Skip to content

Commit 625e6e0

Browse files
authored
Merge pull request #2414 from swiftwasm/main
[pull] swiftwasm from main
2 parents 0a784e4 + 3f91269 commit 625e6e0

File tree

150 files changed

+10109
-852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+10109
-852
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ set(SWIFT_BENCH_MODULES
179179
single-source/StringMatch
180180
single-source/StringRemoveDupes
181181
single-source/StringReplaceSubrange
182+
single-source/StringSwitch
182183
single-source/StringTests
183184
single-source/StringWalk
184185
single-source/Substring
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//===--- StringSwitch.swift -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
15+
public let StringSwitch = [
16+
BenchmarkInfo(
17+
name: "StringSwitch",
18+
runFunction: run_StringSwitch,
19+
tags: [.validation, .api])
20+
]
21+
22+
@inline(never)
23+
func getIndex(_ s: String) -> Int {
24+
switch s {
25+
case "Swift": return 0
26+
case "is": return 1
27+
case "a": return 2
28+
case "general-purpose": return 3
29+
case "programming language": return 4
30+
case "built": return 5
31+
case "using": return 6
32+
case "modern": return 7
33+
case "approach": return 8
34+
case "to": return 9
35+
case "safety,": return 10
36+
case "performance,": return 11
37+
case "and": return 12
38+
case "software": return 13
39+
case "design": return 14
40+
case "patterns.": return 15
41+
case "": return 16
42+
case "The": return 17
43+
case "goal": return 18
44+
case "of": return 19
45+
case "the": return 20
46+
case "project": return 21
47+
case "create": return 22
48+
case "best": return 23
49+
case "available": return 24
50+
case "for": return 25
51+
case "uses": return 26
52+
case "ranging": return 27
53+
case "from": return 28
54+
case "systems": return 29
55+
case "mobile": return 30
56+
case "desktop": return 31
57+
case "apps,": return 32
58+
case "scaling": return 33
59+
case "up": return 34
60+
case "cloud": return 35
61+
case "services.": return 36
62+
case "Most": return 37
63+
case "importantly,": return 38
64+
case "designed": return 39
65+
case "make": return 40
66+
case "writing": return 41
67+
case "maintaining": return 42
68+
case "correct": return 43
69+
case "programs": return 44
70+
case "easier": return 45
71+
case "developer.": return 46
72+
case "To": return 47
73+
case "achieve": return 48
74+
case "this": return 49
75+
case "goal,": return 50
76+
case "we": return 51
77+
case "believe": return 52
78+
case "that": return 53
79+
case "most": return 54
80+
case "obvious": return 55
81+
case "way": return 56
82+
case "write": return 57
83+
case "code": return 58
84+
case "must": return 59
85+
case "also": return 60
86+
case "be:": return 61
87+
case "Safe.": return 62
88+
case "should": return 63
89+
case "behave": return 64
90+
case "in": return 65
91+
case "safe": return 66
92+
case "manner.": return 67
93+
case "Undefined": return 68
94+
case "behavior": return 69
95+
case "enemy": return 70
96+
case "developer": return 71
97+
case "mistakes": return 72
98+
case "be": return 73
99+
case "caught": return 74
100+
case "before": return 75
101+
case "production.": return 76
102+
case "Opting": return 77
103+
case "safety": return 78
104+
case "sometimes": return 79
105+
case "means": return 80
106+
case "will": return 81
107+
case "feel": return 82
108+
case "strict,": return 83
109+
case "but": return 84
110+
case "clarity": return 85
111+
case "saves": return 86
112+
case "time": return 87
113+
case "long": return 88
114+
case "run.": return 89
115+
case "Fast.": return 90
116+
case "intended": return 91
117+
case "as": return 92
118+
case "replacement": return 93
119+
case "C-based": return 94
120+
case "languages": return 95
121+
case "(C, C++, Objective-C).": return 96
122+
case "As": return 97
123+
case "such,": return 98
124+
case "comparable": return 99
125+
case "those": return 100
126+
case "performance": return 101
127+
case "tasks.": return 102
128+
case "Performance": return 103
129+
case "predictable": return 104
130+
case "consistent,": return 105
131+
case "not": return 106
132+
case "just": return 107
133+
case "fast": return 108
134+
case "short": return 109
135+
case "bursts": return 110
136+
case "require": return 111
137+
case "clean-up": return 112
138+
case "later.": return 113
139+
case "There": return 114
140+
case "are": return 115
141+
case "lots": return 116
142+
case "with": return 117
143+
case "novel": return 118
144+
case "features": return 119
145+
case "x": return 120
146+
case "being": return 121
147+
case "rare.": return 122
148+
case "Expressive.": return 123
149+
case "benefits": return 124
150+
case "decades": return 125
151+
case "advancement": return 126
152+
case "computer": return 127
153+
case "science": return 128
154+
case "offer": return 129
155+
case "syntax": return 130
156+
case "joy": return 131
157+
case "use,": return 132
158+
case "developers": return 133
159+
case "expect.": return 134
160+
case "But": return 135
161+
case "never": return 136
162+
case "done.": return 137
163+
case "We": return 138
164+
case "monitor": return 139
165+
case "advancements": return 140
166+
case "embrace": return 141
167+
case "what": return 142
168+
case "works,": return 143
169+
case "continually": return 144
170+
case "evolving": return 145
171+
case "even": return 146
172+
case "better.": return 147
173+
case "Tools": return 148
174+
case "critical": return 149
175+
case "part": return 150
176+
case "ecosystem.": return 151
177+
case "strive": return 152
178+
case "integrate": return 153
179+
case "well": return 154
180+
case "within": return 155
181+
case "developerss": return 156
182+
case "toolset,": return 157
183+
case "build": return 158
184+
case "quickly,": return 159
185+
case "present": return 160
186+
case "excellent": return 161
187+
case "diagnostics,": return 162
188+
case "enable": return 163
189+
case "interactive": return 164
190+
case "development": return 165
191+
case "experiences.": return 166
192+
case "can": return 167
193+
case "so": return 168
194+
case "much": return 169
195+
case "more": return 170
196+
case "powerful,": return 171
197+
case "like": return 172
198+
case "Swift-based": return 173
199+
case "playgrounds": return 174
200+
case "do": return 175
201+
case "Xcode,": return 176
202+
case "or": return 177
203+
case "web-based": return 178
204+
case "REPL": return 179
205+
case "when": return 180
206+
case "working": return 181
207+
case "Linux": return 182
208+
case "server-side": return 183
209+
case "code.": return 184
210+
default: return -1
211+
}
212+
}
213+
214+
@inline(never)
215+
func test(_ s: String) {
216+
blackHole(getIndex(s))
217+
}
218+
219+
@inline(never)
220+
public func run_StringSwitch(N: Int) {
221+
let first = "Swift"
222+
let short = "To"
223+
let long = "(C, C++, Objective-C)."
224+
let last = "code."
225+
let none = "non existent string"
226+
for _ in 1...100*N {
227+
test(first)
228+
test(short)
229+
test(long)
230+
test(last)
231+
test(none)
232+
}
233+
}
234+

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ import StringInterpolation
177177
import StringMatch
178178
import StringRemoveDupes
179179
import StringReplaceSubrange
180+
import StringSwitch
180181
import StringTests
181182
import StringWalk
182183
import Substring
@@ -375,6 +376,7 @@ registerBenchmark(StringMatch)
375376
registerBenchmark(StringNormalization)
376377
registerBenchmark(StringRemoveDupes)
377378
registerBenchmark(StringReplaceSubrange)
379+
registerBenchmark(StringSwitch)
378380
registerBenchmark(StringTests)
379381
registerBenchmark(StringWalk)
380382
registerBenchmark(SubstringTest)

docs/SIL.rst

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,11 +1681,12 @@ that use a SIL value are required to be able to be semantically partitioned in
16811681
between "non-lifetime ending uses" that just require the value to be live and
16821682
"lifetime ending uses" that end the lifetime of the value and after which the
16831683
value can no longer be used. Since by definition operands that are lifetime
1684-
ending uses end their associated value's lifetime, we must have that the
1685-
lifetime ending use points jointly post-dominate all non-lifetime ending use
1686-
points and that a value must have exactly one lifetime ending use along all
1687-
reachable program paths, preventing leaks and use-after-frees. As an example,
1688-
consider the following SIL example with partitioned defs/uses annotated inline::
1684+
ending uses end their associated value's lifetime, we must have that, ignoring
1685+
program ending `Dead End Blocks`_, the lifetime ending use points jointly
1686+
post-dominate all non-lifetime ending use points and that a value must have
1687+
exactly one lifetime ending use along all reachable program paths, preventing
1688+
leaks and use-after-frees. As an example, consider the following SIL example
1689+
with partitioned defs/uses annotated inline::
16891690

16901691
sil @stash_and_cast : $@convention(thin) (@owned Klass) -> @owned SuperKlass {
16911692
bb0(%kls1 : @owned $Klass): // Definition of %kls1
@@ -1786,15 +1787,15 @@ the ``ValueOwnershipKind`` of ``v``. In symbols, we must have that::
17861787

17871788
In words, a value can be passed to an operand if applying the operand's
17881789
ownership constraint to the value's ownership does not change the value's
1789-
ownership. Operationally this has a few interesting effects on SIL::
1790+
ownership. Operationally this has a few interesting effects on SIL:
17901791

1791-
1. We have defined away invalid value-operand (aka def-use) pairing since the
1792-
SILVerifier validates the aforementioned relationship on all SIL values,
1793-
uses at all points of the pipeline until ossa is lowered.
1792+
1. We have defined away invalid value-operand (aka def-use) pairing since the
1793+
SILVerifier validates the aforementioned relationship on all SIL values,
1794+
uses at all points of the pipeline until ossa is lowered.
17941795

1795-
2. Many SIL instructions do not care about the ownership kind that their value
1796-
will take. They can just define all of their operand's as having an
1797-
ownership constraint of Any.
1796+
2. Many SIL instructions do not care about the ownership kind that their value
1797+
will take. They can just define all of their operand's as having an
1798+
ownership constraint of Any.
17981799

17991800
Now lets go into more depth upon `Value Ownership Kind`_ and `Ownership Constraint`_.
18001801

@@ -2316,6 +2317,81 @@ The current list of interior pointer SIL instructions are:
23162317
(*) We still need to finish adding support for project_box, but all other
23172318
interior pointers are guarded already.
23182319

2320+
Dead End Blocks
2321+
~~~~~~~~~~~~~~~
2322+
2323+
In SIL, one can express that a program is semantically expected to exit at the
2324+
end of a block by terminating the block with an `unreachable`_. Such a block is
2325+
called a *program terminating block* and all blocks that are post-dominated by
2326+
blocks of the aforementioned kind are called *dead end blocks*. Intuitively, any
2327+
path through a dead end block is known to result in program termination, so
2328+
resources that normally would need to be released back to the system will
2329+
instead be returned to the system by process tear down.
2330+
2331+
Since we rely on the system at these points to perform resource cleanup, we are
2332+
able to loosen our lifetime requirements by allowing for values to not have
2333+
their lifetimes ended along paths that end in program terminating
2334+
blocks. Operationally, this implies that:
2335+
2336+
* All SIL values must have exactly one lifetime ending use on all paths that
2337+
terminate in a `return`_ or `throw`_. In contrast, a SIL value does not need to
2338+
have a lifetime ending use along paths that end in an `unreachable`_.
2339+
2340+
* `end_borrow`_ and `destroy_value`_ are redundent, albeit legal, in blocks
2341+
where all paths through the block end in an `unreachable`_.
2342+
2343+
Consider the following legal SIL where we leak ``%0`` in blocks prefixed with
2344+
``bbDeadEndBlock`` and consume it in ``bb2``::
2345+
2346+
sil @user : $@convention(thin) (@owned Klass) -> @owned Klass {
2347+
bb0(%0 : @owned $Klass):
2348+
cond_br ..., bb1, bb2
2349+
2350+
bb1:
2351+
// This is a dead end block since it is post-dominated by two dead end
2352+
// blocks. It is not a program terminating block though since the program
2353+
// does not end in this block.
2354+
cond_br ..., bbDeadEndBlock1, bbDeadEndBlock2
2355+
2356+
bbDeadEndBlock1:
2357+
// This is a dead end block and a program terminating block.
2358+
//
2359+
// We are exiting the program here causing the operating system to clean up
2360+
// all resources associated with our process, so there is no need for a
2361+
// destroy_value. That memory will be cleaned up anyways.
2362+
unreachable
2363+
2364+
bbDeadEndBlock2:
2365+
// This is a dead end block and a program terminating block.
2366+
//
2367+
// Even though we do not need to insert destroy_value along these paths, we
2368+
// can if we want to. It is just necessary and the optimizer can eliminate
2369+
// such a destroy_value if it wishes.
2370+
//
2371+
// NOTE: The author arbitrarily chose just to destroy %0: we could legally
2372+
// destroy either value (or both!).
2373+
destroy_value %0 : $Klass
2374+
unreachable
2375+
2376+
bb2:
2377+
cond_br ..., bb3, bb4
2378+
2379+
bb3:
2380+
// This block is live, so we need to ensure that %0 is consumed within the
2381+
// block. In this case, %0 is consumed by returning %0 to our caller.
2382+
return %0 : $Klass
2383+
2384+
bb4:
2385+
// This block is also live, but since we do not return %0, we must insert a
2386+
// destroy_value to cleanup %0.
2387+
//
2388+
// NOTE: The copy_value/destroy_value here is redundent and can be removed by
2389+
// the optimizer. The author left it in for illustrative purposes.
2390+
%1 = copy_value %0 : $Klass
2391+
destroy_value %0 : $Klass
2392+
return %1 : $Klass
2393+
}
2394+
23192395
Runtime Failure
23202396
---------------
23212397

0 commit comments

Comments
 (0)