Skip to content

Commit 9a90b75

Browse files
authored
Merge pull request #60924 from eeckstein/swift-sil-infrastructure
Some Swift SIL infrastructure additions and improvements
2 parents 86e0059 + 32af2dd commit 9a90b75

File tree

14 files changed

+241
-159
lines changed

14 files changed

+241
-159
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/FunctionUses.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,6 @@ struct FunctionUses {
109109
// The use-list head for each function.
110110
private var uses: [Function: FirstUse] = [:]
111111

112-
init() {
113-
// Already start with a reasonable big capacity to reduce the number of
114-
// re-allocations when appending to the data structures.
115-
useStorage.reserveCapacity(128)
116-
uses.reserveCapacity(64)
117-
}
118-
119112
/// Returns the use-list of `function`.
120113
///
121114
/// Note that `collect` must be called before `getUses` can be used.
@@ -125,7 +118,12 @@ struct FunctionUses {
125118

126119
/// Collects all uses of all function in the module.
127120
mutating func collect(context: ModulePassContext) {
128-
121+
122+
// Already start with a reasonable big capacity to reduce the number of
123+
// re-allocations when appending to the data structures.
124+
useStorage.reserveCapacity(128)
125+
uses.reserveCapacity(64)
126+
129127
// Mark all functions, which are referenced from tables, to have "unknown" uses.
130128

131129
for vTable in context.vTables {

SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
swift_compiler_sources(Optimizer
1010
ModulePassContext.swift
11+
Options.swift
1112
Passes.swift
1213
PassContext.swift
1314
PassRegistration.swift)

SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ struct ModulePassContext {
9191
DefaultWitnessTableList(first: PassContext_firstDefaultWitnessTableInModule(_bridged).table)
9292
}
9393

94+
var options: Options { Options(_bridged: _bridged) }
95+
9496
/// Run a closure with a `PassContext` for a function, which allows to modify that function.
9597
///
9698
/// Only a single `transform` can be alive at the same time, i.e. it's not allowed to nest
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===--- Options.swift ----------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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 OptimizerBridging
14+
15+
struct Options {
16+
let _bridged: BridgedPassContext
17+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassContext.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ struct PassContext {
2222

2323
let _bridged: BridgedPassContext
2424

25+
var options: Options { Options(_bridged: _bridged) }
26+
2527
func continueWithNextSubpassRun(for inst: Instruction? = nil) -> Bool {
2628
let bridgedInst = OptionalBridgedInstruction(obj: inst?.bridged.obj)
2729
return PassContext_continueWithNextSubpassRun(_bridged, bridgedInst) != 0

SwiftCompilerSources/Sources/Optimizer/TestPasses/AccessDumper.swift

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,34 +61,29 @@ private func printAccessInfo(address: Value) {
6161

6262
var apw = AccessPathWalker()
6363
let (ap, scope) = apw.getAccessPathWithScope(of: address)
64-
if let scope = scope {
65-
switch scope {
66-
case let .scope(ba):
67-
print(" Scope: \(ba)")
68-
case .base(_):
69-
print(" Scope: base")
70-
}
64+
switch scope {
65+
case let .scope(ba):
66+
print(" Scope: \(ba)")
67+
case .base(_):
68+
print(" Scope: base")
7169
}
7270

73-
if let ap = ap {
74-
print(" Base: \(ap.base)")
75-
print(" Path: \"\(ap.projectionPath)\"")
71+
print(" Base: \(ap.base)")
72+
print(" Path: \"\(ap.projectionPath)\"")
7673

77-
var arw = AccessStoragePathVisitor()
78-
if !arw.visitAccessStorageRoots(of: ap) {
79-
print(" no Storage paths")
80-
}
74+
var arw = AccessStoragePathVisitor()
75+
if !arw.visitAccessStorageRoots(of: ap) {
76+
print(" no Storage paths")
8177
}
8278
}
8379

8480
private func checkAliasInfo(forArgumentsOf apply: ApplyInst, expectDistinct: Bool) {
8581
let address1 = apply.arguments[0]
8682
let address2 = apply.arguments[1]
8783
var apw = AccessPathWalker()
88-
guard let path1 = apw.getAccessPath(of: address1),
89-
let path2 = apw.getAccessPath(of: address2) else {
90-
return
91-
}
84+
let path1 = apw.getAccessPath(of: address1)
85+
let path2 = apw.getAccessPath(of: address2)
86+
9287
if path1.isDistinct(from: path2) != expectDistinct {
9388
print("wrong isDistinct result of \(apply)")
9489
} else if path2.isDistinct(from: path1) != expectDistinct {

SwiftCompilerSources/Sources/Optimizer/Utilities/AccessUtils.swift

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ enum AccessBase : CustomStringConvertible, Hashable {
7373
/// An address which is derived from a `Builtin.RawPointer`.
7474
case pointer(PointerToAddressInst)
7575

76-
init?(baseAddress: Value) {
76+
/// The access base is some SIL pattern which does not fit into any other case.
77+
/// This should be a very rare situation.
78+
case unidentified
79+
80+
init(baseAddress: Value) {
7781
switch baseAddress {
7882
case let rea as RefElementAddrInst : self = .class(rea)
7983
case let rta as RefTailAddrInst : self = .tail(rta)
@@ -85,15 +89,16 @@ enum AccessBase : CustomStringConvertible, Hashable {
8589
if let ba = mvr.instruction as? BeginApplyInst, baseAddress.type.isAddress {
8690
self = .yield(ba)
8791
} else {
88-
return nil
92+
self = .unidentified
8993
}
9094
default:
91-
return nil
95+
self = .unidentified
9296
}
9397
}
9498

9599
var description: String {
96100
switch self {
101+
case .unidentified: return "?"
97102
case .box(let pbi): return "box - \(pbi)"
98103
case .stack(let asi): return "stack - \(asi)"
99104
case .global(let gl): return "global - @\(gl.name)"
@@ -110,7 +115,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
110115
switch self {
111116
case .class, .tail:
112117
return true
113-
case .box, .stack, .global, .argument, .yield, .pointer:
118+
case .box, .stack, .global, .argument, .yield, .pointer, .unidentified:
114119
return false
115120
}
116121
}
@@ -121,7 +126,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
121126
case .box(let pbi): return pbi.operand
122127
case .class(let rea): return rea.operand
123128
case .tail(let rta): return rta.operand
124-
case .stack, .global, .argument, .yield, .pointer:
129+
case .stack, .global, .argument, .yield, .pointer, .unidentified:
125130
return nil
126131
}
127132
}
@@ -130,7 +135,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
130135
switch self {
131136
case .class(let rea): return rea.fieldIsLet
132137
case .global(let g): return g.isLet
133-
case .box, .stack, .tail, .argument, .yield, .pointer:
138+
case .box, .stack, .tail, .argument, .yield, .pointer, .unidentified:
134139
return false
135140
}
136141
}
@@ -142,7 +147,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
142147
case .class(let rea): return rea.operand is AllocRefInstBase
143148
case .tail(let rta): return rta.operand is AllocRefInstBase
144149
case .stack: return true
145-
case .global, .argument, .yield, .pointer:
150+
case .global, .argument, .yield, .pointer, .unidentified:
146151
return false
147152
}
148153
}
@@ -152,7 +157,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
152157
switch self {
153158
case .box, .class, .tail, .stack, .global:
154159
return true
155-
case .argument, .yield, .pointer:
160+
case .argument, .yield, .pointer, .unidentified:
156161
return false
157162
}
158163
}
@@ -174,7 +179,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
174179
}
175180

176181
func argIsDistinct(_ arg: FunctionArgument, from other: AccessBase) -> Bool {
177-
if arg.isExclusiveIndirectParameter {
182+
if arg.convention.isExclusiveIndirect {
178183
// Exclusive indirect arguments cannot alias with an address for which we know that it
179184
// is not derived from that argument (which might be the case for `pointer` and `yield`).
180185
return other.hasKnownStorageKind
@@ -199,7 +204,7 @@ enum AccessBase : CustomStringConvertible, Hashable {
199204
case (.tail(let rta), .tail(let otherRta)):
200205
return isDifferentAllocation(rta.operand, otherRta.operand)
201206
case (.argument(let arg), .argument(let otherArg)):
202-
return (arg.isExclusiveIndirectParameter || otherArg.isExclusiveIndirectParameter) && arg != otherArg
207+
return (arg.convention.isExclusiveIndirect || otherArg.convention.isExclusiveIndirect) && arg != otherArg
203208

204209
// Handle arguments vs non-arguments
205210
case (.argument(let arg), _):
@@ -224,6 +229,10 @@ struct AccessPath : CustomStringConvertible {
224229
/// address projections only
225230
let projectionPath: SmallProjectionPath
226231

232+
static func unidentified() -> AccessPath {
233+
return AccessPath(base: .unidentified, projectionPath: SmallProjectionPath())
234+
}
235+
227236
var description: String {
228237
"\(projectionPath): \(base)"
229238
}
@@ -362,46 +371,46 @@ enum EnclosingScope {
362371
/// of the access (the base address and the address projections to the accessed fields) and
363372
/// the innermost enclosing scope (`begin_access`).
364373
struct AccessPathWalker {
365-
mutating func getAccessPath(of address: Value) -> AccessPath? {
374+
mutating func getAccessPath(of address: Value) -> AccessPath {
366375
assert(address.type.isAddress, "Expected address")
367376
walker.start()
368377
if walker.walkUp(address: address, path: Walker.Path()) == .abortWalk {
369-
return nil
378+
assert(walker.result.base == .unidentified,
379+
"shouldn't have set an access base in an aborted walk")
370380
}
371381
return walker.result
372382
}
373383

374-
mutating func getAccessPathWithScope(of address: Value) -> (AccessPath?, EnclosingScope?) {
384+
mutating func getAccessPathWithScope(of address: Value) -> (AccessPath, EnclosingScope) {
375385
let ap = getAccessPath(of: address)
376386
return (ap, walker.scope)
377387
}
378388

379-
mutating func getAccessBase(of address: Value) -> AccessBase? {
380-
getAccessPath(of: address)?.base
389+
mutating func getAccessBase(of address: Value) -> AccessBase {
390+
getAccessPath(of: address).base
381391
}
382392

383-
mutating func getAccessScope(of address: Value) -> EnclosingScope? {
393+
mutating func getAccessScope(of address: Value) -> EnclosingScope {
384394
getAccessPathWithScope(of: address).1
385395
}
386396

387397
private var walker = Walker()
388398

389399
private struct Walker : AddressUseDefWalker {
390-
private(set) var result: AccessPath? = nil
400+
private(set) var result = AccessPath.unidentified()
391401
private var foundBeginAccess: BeginAccessInst? = nil
392402
private var pointerId = PointerIdentification()
393403

394-
var scope: EnclosingScope? {
404+
var scope: EnclosingScope {
395405
if let ba = foundBeginAccess {
396406
return .scope(ba)
397407
} else {
398-
guard let accessPath = result else { return nil }
399-
return .base(accessPath.base)
408+
return .base(result.base)
400409
}
401410
}
402411

403412
mutating func start() {
404-
result = nil
413+
result = .unidentified()
405414
foundBeginAccess = nil
406415
}
407416

@@ -435,7 +444,7 @@ struct AccessPathWalker {
435444
}
436445

437446
mutating func rootDef(address: Value, path: Path) -> WalkResult {
438-
assert(result == nil, "rootDef should only called once")
447+
assert(result.base == .unidentified, "rootDef should only called once")
439448
// Try identifying the address a pointer originates from
440449
if let p2ai = address as? PointerToAddressInst {
441450
if let originatingAddr = pointerId.getOriginatingAddress(of: p2ai) {
@@ -446,15 +455,9 @@ struct AccessPathWalker {
446455
}
447456
}
448457

449-
// If this is a base then we're done
450-
if let base = AccessBase(baseAddress: address) {
451-
self.result = AccessPath(base: base, projectionPath: path.projectionPath)
452-
return .continueWalk
453-
}
454-
455-
// The base is unidentified
456-
self.result = nil
457-
return .abortWalk
458+
let base = AccessBase(baseAddress: address)
459+
self.result = AccessPath(base: base, projectionPath: path.projectionPath)
460+
return .continueWalk
458461
}
459462

460463
mutating func walkUp(address: Value, path: Path) -> WalkResult {
@@ -464,7 +467,6 @@ struct AccessPathWalker {
464467
} else if path.indexAddr && !canBeOperandOfIndexAddr(address) {
465468
// An `index_addr` instruction cannot be derived from an address
466469
// projection. Bail out
467-
self.result = nil
468470
return .abortWalk
469471
} else if let ba = address as? BeginAccessInst, foundBeginAccess == nil {
470472
foundBeginAccess = ba
@@ -474,6 +476,27 @@ struct AccessPathWalker {
474476
}
475477
}
476478

479+
extension Value {
480+
// Convenient properties to avoid instantiating an explicit AccessPathWalker.
481+
//
482+
// Although an AccessPathWalker is created for each call of these properties,
483+
// it's very unlikely that this will end up in memory allocations.
484+
// Only in the rare case of `pointer_to_address` -> `address_to_pointer` pairs, which
485+
// go through phi-arguments, the AccessPathWalker will allocate memnory in its cache.
486+
487+
/// Computes the access base of this address value.
488+
var accessBase: AccessBase {
489+
var apWalker = AccessPathWalker()
490+
return apWalker.getAccessBase(of: self)
491+
}
492+
493+
/// Computes the enclosing access scope of this address value.
494+
var accessScope: EnclosingScope {
495+
var apWalker = AccessPathWalker()
496+
return apWalker.getAccessScope(of: self)
497+
}
498+
}
499+
477500
/// A ValueUseDef walker that identifies which values a reference of an access path might
478501
/// originate from.
479502
protocol AccessStoragePathWalker : ValueUseDefWalker where Path == SmallProjectionPath {
@@ -496,7 +519,7 @@ extension AccessStoragePathWalker {
496519
return walkUp(value: rea.operand, path: path.push(.classField, index: rea.fieldIndex)) != .abortWalk
497520
case .tail(let rta):
498521
return walkUp(value: rta.operand, path: path.push(.tailElements, index: 0)) != .abortWalk
499-
case .stack, .global, .argument, .yield, .pointer:
522+
case .stack, .global, .argument, .yield, .pointer, .unidentified:
500523
return false
501524
}
502525
}

SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeInfo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ fileprivate struct EscapeInfoWalker<V: EscapeInfoVisitor> : ValueDefUseWalker,
734734
case is AllocStackInst:
735735
return cachedWalkDown(addressOrValue: def, path: path.with(knownType: nil))
736736
case let arg as FunctionArgument:
737-
if canIgnoreForLoadOrArgument(path) && arg.isExclusiveIndirectParameter && !path.followStores {
737+
if canIgnoreForLoadOrArgument(path) && arg.convention.isExclusiveIndirect && !path.followStores {
738738
return cachedWalkDown(addressOrValue: def, path: path.with(knownType: nil))
739739
} else {
740740
return isEscaping

0 commit comments

Comments
 (0)