Skip to content

Commit 2e94dac

Browse files
Merge pull request #5319 from swiftwasm/main
[pull] swiftwasm from main
2 parents 024c9f0 + 4e3d608 commit 2e94dac

File tree

449 files changed

+10881
-4233
lines changed

Some content is hidden

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

449 files changed

+10881
-4233
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ struct AliasAnalysis {
9898
},
9999

100100
// isAddrVisibleFromObj
101-
{ (bridgedCtxt: BridgedPassContext, bridgedAddr: BridgedValue, bridgedObj: BridgedValue) -> Bool in
101+
{ (bridgedCtxt: BridgedPassContext, bridgedAddr: BridgedValue, bridgedObj: BridgedValue, complexityBudget: Int) -> Bool in
102102
let context = FunctionPassContext(_bridged: bridgedCtxt)
103103
let addr = bridgedAddr.value.at(AliasAnalysis.getPtrOrAddressPath(for: bridgedAddr.value))
104104

105105
// This is similar to `canReferenceSameFieldFn`, except that all addresses of all objects are
106106
// considered which are transitively visible from `bridgedObj`.
107107
let anythingReachableFromObj = bridgedObj.value.at(SmallProjectionPath(.anything))
108-
return addr.canAddressAlias(with: anythingReachableFromObj, context)
108+
return addr.canAddressAlias(with: anythingReachableFromObj, complexityBudget: complexityBudget, context)
109109
},
110110

111111
// canReferenceSameFieldFn

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ extension ProjectedValue {
7575
/// the walk. See `EscapeVisitor` for details.
7676
///
7777
func isEscaping(using visitor: some EscapeVisitor = DefaultVisitor(),
78+
complexityBudget: Int = Int.max,
7879
_ context: some Context) -> Bool {
79-
var walker = EscapeWalker(visitor: visitor, context)
80+
var walker = EscapeWalker(visitor: visitor, complexityBudget: complexityBudget, context)
8081
return walker.walkUp(addressOrValue: value, path: path.escapePath) == .abortWalk
8182
}
8283

@@ -287,9 +288,10 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
287288
AddressUseDefWalker {
288289
typealias Path = EscapeUtilityTypes.EscapePath
289290

290-
init(visitor: V, _ context: some Context) {
291+
init(visitor: V, complexityBudget: Int = Int.max, _ context: some Context) {
291292
self.calleeAnalysis = context.calleeAnalysis
292293
self.visitor = visitor
294+
self.complexityBudget = complexityBudget
293295
}
294296

295297
//===--------------------------------------------------------------------===//
@@ -313,6 +315,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
313315
}
314316

315317
mutating func walkDown(value: Operand, path: Path) -> WalkResult {
318+
if complexityBudgetExceeded(value.value) {
319+
return .abortWalk
320+
}
316321
if hasRelevantType(value.value, at: path.projectionPath) {
317322
switch visitor.visitUse(operand: value, path: path) {
318323
case .continueWalk:
@@ -409,6 +414,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
409414
}
410415

411416
mutating func walkDown(address: Operand, path: Path) -> WalkResult {
417+
if complexityBudgetExceeded(address.value) {
418+
return .abortWalk
419+
}
412420
if hasRelevantType(address.value, at: path.projectionPath) {
413421
switch visitor.visitUse(operand: address, path: path) {
414422
case .continueWalk:
@@ -508,7 +516,7 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
508516
return .continueWalk
509517
}
510518
if !visitor.followLoads && p.matches(pattern: SmallProjectionPath(.anyValueFields).push(.anyClassField)) {
511-
// Any address of a class property of the object to destroy cannot esacpe the destructor.
519+
// Any address of a class property of the object to destroy cannot escape the destructor.
512520
// (Whereas a value stored in such a property could escape.)
513521
return .continueWalk
514522
}
@@ -644,6 +652,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
644652
}
645653

646654
mutating func walkUp(value: Value, path: Path) -> WalkResult {
655+
if complexityBudgetExceeded(value) {
656+
return .abortWalk
657+
}
647658
if hasRelevantType(value, at: path.projectionPath) {
648659
switch visitor.visitDef(def: value, path: path) {
649660
case .continueWalkUp:
@@ -697,6 +708,9 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
697708
}
698709

699710
mutating func walkUp(address: Value, path: Path) -> WalkResult {
711+
if complexityBudgetExceeded(address) {
712+
return .abortWalk
713+
}
700714
if hasRelevantType(address, at: path.projectionPath) {
701715
switch visitor.visitDef(def: address, path: path) {
702716
case .continueWalkUp:
@@ -785,6 +799,10 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
785799
var walkDownCache = WalkerCache<Path>()
786800
var walkUpCache = WalkerCache<Path>()
787801

802+
// Only this number of up/and down walks are done until the walk aborts.
803+
// Used to avoid quadratic complexity in some scenarios.
804+
var complexityBudget: Int
805+
788806
private let calleeAnalysis: CalleeAnalysis
789807

790808
//===--------------------------------------------------------------------===//
@@ -825,6 +843,14 @@ fileprivate struct EscapeWalker<V: EscapeVisitor> : ValueDefUseWalker,
825843
return path.popLastClassAndValuesFromTail()
826844
}
827845

846+
private mutating func complexityBudgetExceeded(_ v: Value) -> Bool {
847+
if complexityBudget <= 0 {
848+
return true
849+
}
850+
complexityBudget = complexityBudget &- 1
851+
return false
852+
}
853+
828854
// Set a breakpoint here to debug when a value is escaping.
829855
private var isEscaping: WalkResult { .abortWalk }
830856
}

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,15 @@ extension ProjectedValue {
221221
/// `%s`.canAddressAlias(with: `%2`) -> true
222222
/// `%1`.canAddressAlias(with: `%2`) -> false
223223
///
224-
func canAddressAlias(with rhs: ProjectedValue, _ context: some Context) -> Bool {
224+
func canAddressAlias(with rhs: ProjectedValue, complexityBudget: Int = Int.max, _ context: some Context) -> Bool {
225225
// self -> rhs will succeed (= return false) if self is a non-escaping "local" object,
226226
// but not necessarily rhs.
227-
if !isEscaping(using: EscapesToValueVisitor(target: rhs), context) {
227+
if !isEscaping(using: EscapesToValueVisitor(target: rhs), complexityBudget: complexityBudget, context) {
228228
return false
229229
}
230230
// The other way round: rhs -> self will succeed if rhs is a non-escaping "local" object,
231231
// but not necessarily self.
232-
if !rhs.isEscaping(using: EscapesToValueVisitor(target: self), context) {
232+
if !rhs.isEscaping(using: EscapesToValueVisitor(target: self), complexityBudget: complexityBudget, context) {
233233
return false
234234
}
235235
return true

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ set(SWIFT_BENCH_MODULES
198198
single-source/TwoSum
199199
single-source/TypeFlood
200200
single-source/UTF8Decode
201+
single-source/UTF16Decode
201202
single-source/Walsh
202203
single-source/WordCount
203204
single-source/XorLoop
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//===--- UTF16Decode.swift -------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
import Foundation
15+
16+
public let benchmarks = [
17+
BenchmarkInfo(
18+
name: "UTF16Decode",
19+
runFunction: run_UTF16Decode,
20+
tags: [.validation, .api, .String],
21+
setUpFunction: setUp),
22+
BenchmarkInfo(
23+
name: "UTF16Decode.initFromCustom.cont",
24+
runFunction: run_UTF16Decode_InitFromCustom_contiguous,
25+
tags: [.validation, .api, .String],
26+
setUpFunction: setUp),
27+
BenchmarkInfo(
28+
name: "UTF16Decode.initFromCustom.cont.ascii",
29+
runFunction: run_UTF16Decode_InitFromCustom_contiguous_ascii,
30+
tags: [.validation, .api, .String, .skip],
31+
setUpFunction: setUp),
32+
BenchmarkInfo(
33+
name: "UTF16Decode.initFromCustom.noncont",
34+
runFunction: run_UTF16Decode_InitFromCustom_noncontiguous,
35+
tags: [.validation, .api, .String],
36+
setUpFunction: setUp),
37+
BenchmarkInfo(
38+
name: "UTF16Decode.initFromCustom.noncont.ascii",
39+
runFunction: run_UTF16Decode_InitFromCustom_noncontiguous_ascii,
40+
tags: [.validation, .api, .String, .skip],
41+
setUpFunction: setUp),
42+
BenchmarkInfo(
43+
name: "UTF16Decode.initFromData",
44+
runFunction: run_UTF16Decode_InitFromData,
45+
tags: [.validation, .api, .String],
46+
setUpFunction: setUp),
47+
BenchmarkInfo(
48+
name: "UTF16Decode.initDecoding",
49+
runFunction: run_UTF16Decode_InitDecoding,
50+
tags: [.validation, .api, .String],
51+
setUpFunction: setUp),
52+
BenchmarkInfo(
53+
name: "UTF16Decode.initFromData.ascii",
54+
runFunction: run_UTF16Decode_InitFromData_ascii,
55+
tags: [.validation, .api, .String, .skip],
56+
setUpFunction: setUp),
57+
BenchmarkInfo(
58+
name: "UTF16Decode.initDecoding.ascii",
59+
runFunction: run_UTF16Decode_InitDecoding_ascii,
60+
tags: [.validation, .api, .String, .skip],
61+
setUpFunction: setUp),
62+
BenchmarkInfo(
63+
name: "UTF16Decode.initFromData.asciiAsAscii",
64+
runFunction: run_UTF16Decode_InitFromData_ascii_as_ascii,
65+
tags: [.validation, .api, .String, .skip],
66+
setUpFunction: setUp),
67+
]
68+
69+
typealias CodeUnit = UInt16
70+
71+
// 1-byte sequences
72+
// This test case is the longest as it's the most performance sensitive.
73+
let ascii = "Swift is a multi-paradigm, compiled programming language created for iOS, OS X, watchOS, tvOS and Linux development by Apple Inc. Swift is designed to work with Apple's Cocoa and Cocoa Touch frameworks and the large body of existing Objective-C code written for Apple products. Swift is intended to be more resilient to erroneous code (\"safer\") than Objective-C and also more concise. It is built with the LLVM compiler framework included in Xcode 6 and later and uses the Objective-C runtime, which allows C, Objective-C, C++ and Swift code to run within a single program."
74+
let asciiCodeUnits: [CodeUnit] = Array(ascii.utf16)
75+
let asciiData: Data = asciiCodeUnits.withUnsafeBytes { Data($0) }
76+
77+
// 2-byte sequences
78+
let russian = "Ру́сский язы́к один из восточнославянских языков, национальный язык русского народа."
79+
// 3-byte sequences
80+
let japanese = "日本語(にほんご、にっぽんご)は、主に日本国内や日本人同士の間で使われている言語である。"
81+
// 4-byte sequences
82+
// Most commonly emoji, which are usually mixed with other text.
83+
let emoji = "Panda 🐼, Dog 🐶, Cat 🐱, Mouse 🐭."
84+
85+
let allStrings: [[CodeUnit]] = [ascii, russian, japanese, emoji].map { Array($0.utf16) }
86+
let allStringsCodeUnits: [CodeUnit] = Array(allStrings.joined())
87+
let allStringsData: Data = allStringsCodeUnits.withUnsafeBytes { Data($0) }
88+
89+
func setUp() {
90+
blackHole(asciiCodeUnits)
91+
blackHole(asciiData)
92+
blackHole(allStrings)
93+
blackHole(allStringsCodeUnits)
94+
blackHole(allStringsData)
95+
blackHole(allStringsCustomContiguous)
96+
blackHole(asciiCustomContiguous)
97+
blackHole(allStringsCustomNoncontiguous)
98+
blackHole(asciiCustomNoncontiguous)
99+
}
100+
101+
@inline(never)
102+
public func run_UTF16Decode(_ N: Int) {
103+
func isEmpty(_ result: UnicodeDecodingResult) -> Bool {
104+
switch result {
105+
case .emptyInput:
106+
return true
107+
default:
108+
return false
109+
}
110+
}
111+
112+
for _ in 1...200*N {
113+
for string in allStrings {
114+
var it = string.makeIterator()
115+
var utf16 = UTF16()
116+
while !isEmpty(utf16.decode(&it)) { }
117+
}
118+
}
119+
}
120+
121+
@inline(never)
122+
public func run_UTF16Decode_InitFromData(_ N: Int) {
123+
for _ in 0..<200*N {
124+
blackHole(String(data: allStringsData, encoding: .utf16))
125+
}
126+
}
127+
128+
@inline(never)
129+
public func run_UTF16Decode_InitDecoding(_ N: Int) {
130+
for _ in 0..<2*N {
131+
blackHole(String(decoding: allStringsCodeUnits, as: UTF16.self))
132+
}
133+
}
134+
135+
@inline(never)
136+
public func run_UTF16Decode_InitFromData_ascii(_ N: Int) {
137+
for _ in 0..<100*N {
138+
blackHole(String(data: asciiData, encoding: .utf16))
139+
}
140+
}
141+
142+
@inline(never)
143+
public func run_UTF16Decode_InitDecoding_ascii(_ N: Int) {
144+
for _ in 0..<N {
145+
blackHole(String(decoding: asciiCodeUnits, as: UTF16.self))
146+
}
147+
}
148+
149+
@inline(never)
150+
public func run_UTF16Decode_InitFromData_ascii_as_ascii(_ N: Int) {
151+
for _ in 0..<1_000*N {
152+
blackHole(String(data: asciiData, encoding: .ascii))
153+
}
154+
}
155+
156+
struct CustomContiguousCollection: Collection {
157+
let storage: [CodeUnit]
158+
typealias Index = Int
159+
typealias Element = CodeUnit
160+
161+
init(_ codeUnits: [CodeUnit]) { self.storage = codeUnits }
162+
subscript(position: Int) -> Element { self.storage[position] }
163+
var startIndex: Index { 0 }
164+
var endIndex: Index { storage.count }
165+
func index(after i: Index) -> Index { i+1 }
166+
167+
@inline(never)
168+
func withContiguousStorageIfAvailable<R>(
169+
_ body: (UnsafeBufferPointer<CodeUnit>) throws -> R
170+
) rethrows -> R? {
171+
try storage.withContiguousStorageIfAvailable(body)
172+
}
173+
}
174+
struct CustomNoncontiguousCollection: Collection {
175+
let storage: [CodeUnit]
176+
typealias Index = Int
177+
typealias Element = CodeUnit
178+
179+
init(_ codeUnits: [CodeUnit]) { self.storage = codeUnits }
180+
subscript(position: Int) -> Element { self.storage[position] }
181+
var startIndex: Index { 0 }
182+
var endIndex: Index { storage.count }
183+
func index(after i: Index) -> Index { i+1 }
184+
185+
@inline(never)
186+
func withContiguousStorageIfAvailable<R>(
187+
_ body: (UnsafeBufferPointer<UInt8>) throws -> R
188+
) rethrows -> R? {
189+
nil
190+
}
191+
}
192+
let allStringsCustomContiguous = CustomContiguousCollection(allStringsCodeUnits)
193+
let asciiCustomContiguous = CustomContiguousCollection(Array(ascii.utf16))
194+
let allStringsCustomNoncontiguous = CustomNoncontiguousCollection(allStringsCodeUnits)
195+
let asciiCustomNoncontiguous = CustomNoncontiguousCollection(Array(ascii.utf16))
196+
197+
@inline(never)
198+
public func run_UTF16Decode_InitFromCustom_contiguous(_ N: Int) {
199+
for _ in 0..<20*N {
200+
blackHole(String(decoding: allStringsCustomContiguous, as: UTF16.self))
201+
}
202+
}
203+
204+
@inline(never)
205+
public func run_UTF16Decode_InitFromCustom_contiguous_ascii(_ N: Int) {
206+
for _ in 0..<10*N {
207+
blackHole(String(decoding: asciiCustomContiguous, as: UTF16.self))
208+
}
209+
}
210+
211+
@inline(never)
212+
public func run_UTF16Decode_InitFromCustom_noncontiguous(_ N: Int) {
213+
for _ in 0..<20*N {
214+
blackHole(String(decoding: allStringsCustomNoncontiguous, as: UTF16.self))
215+
}
216+
}
217+
218+
@inline(never)
219+
public func run_UTF16Decode_InitFromCustom_noncontiguous_ascii(_ N: Int) {
220+
for _ in 0..<10*N {
221+
blackHole(String(decoding: asciiCustomNoncontiguous, as: UTF16.self))
222+
}
223+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ import SuperChars
199199
import TwoSum
200200
import TypeFlood
201201
import UTF8Decode
202+
import UTF16Decode
202203
import Walsh
203204
import WordCount
204205
import XorLoop
@@ -393,6 +394,7 @@ register(SuperChars.benchmarks)
393394
register(TwoSum.benchmarks)
394395
register(TypeFlood.benchmarks)
395396
register(UTF8Decode.benchmarks)
397+
register(UTF16Decode.benchmarks)
396398
register(Walsh.benchmarks)
397399
register(WordCount.benchmarks)
398400
register(XorLoop.benchmarks)

0 commit comments

Comments
 (0)