Skip to content

Commit 8189840

Browse files
authored
Merge pull request #75505 from eeckstein/alias-analysis
AliasAnalysis: a complete overhaul of alias- and memory-behavior analysis
2 parents 658de4a + 031f235 commit 8189840

Some content is hidden

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

58 files changed

+2288
-2780
lines changed

Diff for: SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

+773-129
Large diffs are not rendered by default.

Diff for: SwiftCompilerSources/Sources/Optimizer/Analysis/CalleeAnalysis.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public struct CalleeAnalysis {
2424
},
2525
// getMemBehaviorFn
2626
{ (bridgedApply: BridgedInstruction, observeRetains: Bool, bca: BridgedCalleeAnalysis) -> BridgedMemoryBehavior in
27-
let apply = bridgedApply.instruction as! ApplySite
27+
let apply = bridgedApply.instruction as! FullApplySite
2828
let e = bca.analysis.getSideEffects(ofApply: apply)
2929
return e.getMemBehavior(observeRetains: observeRetains)
3030
}
@@ -60,7 +60,7 @@ public struct CalleeAnalysis {
6060
}
6161

6262
/// Returns the global (i.e. not argument specific) side effects of an apply.
63-
public func getSideEffects(ofApply apply: ApplySite) -> SideEffects.GlobalEffects {
63+
public func getSideEffects(ofApply apply: FullApplySite) -> SideEffects.GlobalEffects {
6464
return getSideEffects(ofCallee: apply.callee)
6565
}
6666

@@ -78,7 +78,7 @@ public struct CalleeAnalysis {
7878
}
7979

8080
/// Returns the argument specific side effects of an apply.
81-
public func getSideEffects(of apply: ApplySite, operand: Operand, path: SmallProjectionPath) -> SideEffects.GlobalEffects {
81+
public func getSideEffects(of apply: FullApplySite, operand: Operand, path: SmallProjectionPath) -> SideEffects.GlobalEffects {
8282
var result = SideEffects.GlobalEffects()
8383
guard let calleeArgIdx = apply.calleeArgumentIndex(of: operand) else {
8484
return result

Diff for: SwiftCompilerSources/Sources/Optimizer/DataStructures/Set.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ struct InstructionSet : IntrusiveSet {
164164
var d = "{\n"
165165
for inst in function.instructions {
166166
if contains(inst) {
167-
d += inst.description
167+
d += inst.description + "\n"
168168
}
169169
}
170170
d += "}\n"

Diff for: SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift

+18
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,21 @@ typealias BasicBlockWorklist = Worklist<BasicBlockSet>
7676
typealias InstructionWorklist = Worklist<InstructionSet>
7777
typealias ValueWorklist = Worklist<ValueSet>
7878
typealias OperandWorklist = Worklist<OperandSet>
79+
80+
extension InstructionWorklist {
81+
mutating func pushPredecessors(of inst: Instruction, ignoring ignoreInst: SingleValueInstruction) {
82+
if let prev = inst.previous {
83+
if prev != ignoreInst {
84+
pushIfNotVisited(prev)
85+
}
86+
} else {
87+
for predBlock in inst.parentBlock.predecessors {
88+
let termInst = predBlock.terminator
89+
if termInst != ignoreInst {
90+
pushIfNotVisited(termInst)
91+
}
92+
}
93+
}
94+
}
95+
}
96+

Diff for: SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ let computeEscapeEffects = FunctionPass(name: "compute-escape-effects") {
4747
}
4848

4949
// First check: is the argument (or a projected value of it) escaping at all?
50-
if !arg.at(.anything).isEscapingWhenWalkingDown(using: IgnoreRecursiveCallVisitor(),
51-
context) {
50+
if !arg.at(.anything).isEscaping(using: IgnoreRecursiveCallVisitor(),
51+
initialWalkingDirection: .down,
52+
context)
53+
{
5254
let effect = EscapeEffects.ArgumentEffect(.notEscaping, argumentIndex: arg.index,
5355
pathPattern: SmallProjectionPath(.anything))
5456
newEffects.append(effect)
@@ -84,7 +86,7 @@ func addArgEffects(_ arg: FunctionArgument, argPath ap: SmallProjectionPath,
8486
// containing one or more references.
8587
let argPath = arg.type.isClass ? ap : ap.push(.anyValueFields)
8688

87-
guard let result = arg.at(argPath).visitByWalkingDown(using: ArgEffectsVisitor(), context) else {
89+
guard let result = arg.at(argPath).visit(using: ArgEffectsVisitor(), initialWalkingDirection: .down, context) else {
8890
return false
8991
}
9092

Diff for: SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,6 @@ private extension PartialApplyInst {
544544
var followTrivialTypes: Bool { true }
545545
}
546546

547-
return self.isEscapingWhenWalkingDown(using: EscapesToApply(), context)
547+
return self.isEscaping(using: EscapesToApply(), initialWalkingDirection: .down, context)
548548
}
549549
}

Diff for: SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift

+9-4
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ private extension BuiltinInst {
200200
return
201201
}
202202

203-
let instanceType = type.instanceTypeOfMetatype(in: parentFunction)
203+
let instanceType = type.loweredInstanceTypeOfMetatype(in: parentFunction)
204204
let builder = Builder(before: self, context)
205205
let newMetatype = builder.createMetatype(of: instanceType, representation: .Thin)
206206
operands[argument].set(to: newMetatype, context)
@@ -277,16 +277,21 @@ private func typesOfValuesAreEqual(_ lhs: Value, _ rhs: Value, in function: Func
277277
if lhsMetatype.isDynamicSelfMetatype != rhsMetatype.isDynamicSelfMetatype {
278278
return nil
279279
}
280-
let lhsTy = lhsMetatype.instanceTypeOfMetatype(in: function)
281-
let rhsTy = rhsMetatype.instanceTypeOfMetatype(in: function)
280+
let lhsTy = lhsMetatype.loweredInstanceTypeOfMetatype(in: function)
281+
let rhsTy = rhsMetatype.loweredInstanceTypeOfMetatype(in: function)
282282

283283
// Do we know the exact types? This is not the case e.g. if a type is passed as metatype
284284
// to the function.
285285
let typesAreExact = lhsExistential.metatype is MetatypeInst &&
286286
rhsExistential.metatype is MetatypeInst
287287

288288
if typesAreExact {
289-
if lhsTy == rhsTy {
289+
// We need to compare the not lowered types, because function types may differ in their original version
290+
// but are equal in the lowered version, e.g.
291+
// ((Int, Int) -> ())
292+
// (((Int, Int)) -> ())
293+
//
294+
if lhsMetatype == rhsMetatype {
290295
return true
291296
}
292297
// Comparing types of different classes which are in a sub-class relation is not handled by the

Diff for: SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

-5
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,6 @@ struct FunctionPassContext : MutatingContext {
258258
SimplifyContext(_bridged: _bridged, notifyInstructionChanged: notifyInstructionChanged, preserveDebugInfo: preserveDebugInfo)
259259
}
260260

261-
var aliasAnalysis: AliasAnalysis {
262-
let bridgedAA = _bridged.getAliasAnalysis()
263-
return AliasAnalysis(bridged: bridgedAA)
264-
}
265-
266261
var deadEndBlocks: DeadEndBlocksAnalysis {
267262
let bridgeDEA = _bridged.getDeadEndBlocksAnalysis()
268263
return DeadEndBlocksAnalysis(bridged: bridgeDEA)

Diff for: SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ private func registerSwiftPasses() {
110110
registerForSILCombine(DestructureTupleInst.self, { run(DestructureTupleInst.self, $0) })
111111

112112
// Test passes
113+
registerPass(aliasInfoDumper, { aliasInfoDumper.run($0) })
113114
registerPass(functionUsesDumper, { functionUsesDumper.run($0) })
114115
registerPass(silPrinterPass, { silPrinterPass.run($0) })
115116
registerPass(escapeInfoDumper, { escapeInfoDumper.run($0) })
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===--- AliasInfoDumper.swift --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 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 SIL
14+
15+
/// Prints the memory behavior of relevant instructions in relation to address values of the function.
16+
let aliasInfoDumper = FunctionPass(name: "dump-alias-info") {
17+
(function: Function, context: FunctionPassContext) in
18+
19+
let aliasAnalysis = context.aliasAnalysis
20+
21+
print("@\(function.name)")
22+
23+
let values = function.allValues
24+
25+
var pair = 0
26+
for (index1, value1) in values.enumerated() {
27+
for (index2, value2) in values.enumerated() {
28+
if index2 >= index1 {
29+
let result = aliasAnalysis.mayAlias(value1, value2)
30+
precondition(result == aliasAnalysis.mayAlias(value2, value1), "alias analysis not symmetric")
31+
32+
print("PAIR #\(pair).")
33+
print(" \(value1)")
34+
print(" \(value2)")
35+
if result {
36+
print(" MayAlias")
37+
} else if !value1.uses.isEmpty && !value2.uses.isEmpty {
38+
print(" NoAlias")
39+
} else {
40+
print(" noalias?")
41+
}
42+
43+
pair += 1
44+
}
45+
}
46+
}
47+
}
48+
49+
private extension Function {
50+
var allValues: [Value] {
51+
var values: [Value] = []
52+
for block in blocks {
53+
values.append(contentsOf: block.arguments.map { $0 })
54+
for inst in block.instructions {
55+
values.append(contentsOf: inst.results)
56+
}
57+
}
58+
return values
59+
}
60+
}

Diff for: SwiftCompilerSources/Sources/Optimizer/TestPasses/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
swift_compiler_sources(Optimizer
1010
FunctionUsesDumper.swift
1111
AccessDumper.swift
12+
AliasInfoDumper.swift
1213
DeadEndBlockDumper.swift
1314
EscapeInfoDumper.swift
1415
MemBehaviorDumper.swift

Diff for: SwiftCompilerSources/Sources/Optimizer/TestPasses/EscapeInfoDumper.swift

+3-5
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,7 @@ let addressEscapeInfoDumper = FunctionPass(name: "dump-addr-escape-info") {
109109
for value in valuesToCheck {
110110
print("value:\(value)")
111111
for apply in applies {
112-
let path = AliasAnalysis.getPtrOrAddressPath(for: value)
113-
114-
if value.at(path).isEscaping(using: Visitor(apply: apply), context) {
112+
if value.allContainedAddresss.isEscaping(using: Visitor(apply: apply), context) {
115113
print(" ==> \(apply)")
116114
} else {
117115
print(" - \(apply)")
@@ -129,8 +127,8 @@ let addressEscapeInfoDumper = FunctionPass(name: "dump-addr-escape-info") {
129127
print(lhs)
130128
print(rhs)
131129

132-
let projLhs = lhs.at(AliasAnalysis.getPtrOrAddressPath(for: lhs))
133-
let projRhs = rhs.at(AliasAnalysis.getPtrOrAddressPath(for: rhs))
130+
let projLhs = lhs.allContainedAddresss
131+
let projRhs = rhs.allContainedAddresss
134132
let mayAlias = projLhs.canAddressAlias(with: projRhs, context)
135133
if mayAlias != projRhs.canAddressAlias(with: projLhs, context) {
136134
fatalError("canAddressAlias(with:) must be symmetric")

Diff for: SwiftCompilerSources/Sources/Optimizer/TestPasses/MemBehaviorDumper.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ let memBehaviorDumper = FunctionPass(name: "dump-mem-behavior") {
2727

2828
for value in values where value.definingInstruction != inst {
2929

30-
if value.type.isAddress || value is AddressToPointerInst {
30+
if value.type.isAddress {
3131
let read = inst.mayRead(fromAddress: value, aliasAnalysis)
3232
let write = inst.mayWrite(toAddress: value, aliasAnalysis)
3333
print("PAIR #\(currentPair).")
@@ -57,21 +57,22 @@ private extension Function {
5757
private extension Instruction {
5858
var shouldTest: Bool {
5959
switch self {
60-
case is ApplyInst,
61-
is TryApplyInst,
60+
case is ApplySite,
6261
is EndApplyInst,
63-
is BeginApplyInst,
6462
is AbortApplyInst,
6563
is BeginAccessInst,
6664
is EndAccessInst,
6765
is EndCOWMutationInst,
6866
is CopyValueInst,
6967
is DestroyValueInst,
68+
is IsUniqueInst,
7069
is EndBorrowInst,
7170
is LoadInst,
71+
is LoadBorrowInst,
7272
is StoreInst,
7373
is CopyAddrInst,
7474
is BuiltinInst,
75+
is StoreBorrowInst,
7576
is DebugValueInst:
7677
return true
7778
default:

0 commit comments

Comments
 (0)