Skip to content

Commit b907987

Browse files
Merge pull request #5422 from swiftwasm/main
[pull] swiftwasm from main
2 parents bd84593 + af933b0 commit b907987

File tree

133 files changed

+2307
-1728
lines changed

Some content is hidden

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

133 files changed

+2307
-1728
lines changed

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

+41-14
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,17 @@ struct AliasAnalysis {
6868
let inst = bridgedInst.instruction
6969
let val = bridgedVal.value
7070
let path = AliasAnalysis.getPtrOrAddressPath(for: val)
71-
if let apply = inst as? ApplySite {
72-
let effect = getMemoryEffect(of: apply, for: val, path: path, context)
73-
switch (effect.read, effect.write) {
74-
case (false, false): return .None
75-
case (true, false): return .MayRead
76-
case (false, true): return .MayWrite
77-
case (true, true): return .MayReadWrite
71+
switch inst {
72+
case let apply as ApplySite:
73+
return getMemoryEffect(ofApply: apply, for: val, path: path, context).bridged
74+
case let builtin as BuiltinInst:
75+
return getMemoryEffect(ofBuiltin: builtin, for: val, path: path, context).bridged
76+
default:
77+
if val.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: true), context) {
78+
return .MayReadWrite
7879
}
80+
return .None
7981
}
80-
if val.at(path).isEscaping(using: EscapesToInstructionVisitor(target: inst, isAddress: true), context) {
81-
return .MayReadWrite
82-
}
83-
return .None
8482
},
8583

8684
// isObjReleasedFn
@@ -121,7 +119,7 @@ struct AliasAnalysis {
121119
}
122120
}
123121

124-
private func getMemoryEffect(of apply: ApplySite, for address: Value, path: SmallProjectionPath, _ context: FunctionPassContext) -> SideEffects.Memory {
122+
private func getMemoryEffect(ofApply apply: ApplySite, for address: Value, path: SmallProjectionPath, _ context: FunctionPassContext) -> SideEffects.Memory {
125123
let calleeAnalysis = context.calleeAnalysis
126124
let visitor = SideEffectsVisitor(apply: apply, calleeAnalysis: calleeAnalysis, isAddress: true)
127125
let memoryEffects: SideEffects.Memory
@@ -132,7 +130,7 @@ private func getMemoryEffect(of apply: ApplySite, for address: Value, path: Smal
132130
memoryEffects = result.memory
133131
} else {
134132
// `address` has unknown escapes. So we have to take the global effects of the called function(s).
135-
memoryEffects = calleeAnalysis.getSideEffects(of: apply).memory
133+
memoryEffects = calleeAnalysis.getSideEffects(ofApply: apply).memory
136134
}
137135
// Do some magic for `let` variables. Function calls cannot modify let variables.
138136
// The only exception is that the let variable is directly passed to an indirect out of the
@@ -144,14 +142,28 @@ private func getMemoryEffect(of apply: ApplySite, for address: Value, path: Smal
144142
return memoryEffects
145143
}
146144

145+
private func getMemoryEffect(ofBuiltin builtin: BuiltinInst, for address: Value, path: SmallProjectionPath, _ context: FunctionPassContext) -> SideEffects.Memory {
146+
147+
switch builtin.id {
148+
case .Once, .OnceWithContext:
149+
if !address.at(path).isEscaping(using: AddressVisibleByBuiltinOnceVisitor(), context) {
150+
return SideEffects.Memory()
151+
}
152+
let callee = builtin.operands[1].value
153+
return context.calleeAnalysis.getSideEffects(ofCallee: callee).memory
154+
default:
155+
return builtin.memoryEffects
156+
}
157+
}
158+
147159
private func getOwnershipEffect(of apply: ApplySite, for value: Value, path: SmallProjectionPath, _ context: FunctionPassContext) -> SideEffects.Ownership {
148160
let visitor = SideEffectsVisitor(apply: apply, calleeAnalysis: context.calleeAnalysis, isAddress: false)
149161
if let result = value.at(path).visit(using: visitor, context) {
150162
// The resulting effects are the argument effects to which `value` escapes to.
151163
return result.ownership
152164
} else {
153165
// `value` has unknown escapes. So we have to take the global effects of the called function(s).
154-
return visitor.calleeAnalysis.getSideEffects(of: apply).ownership
166+
return visitor.calleeAnalysis.getSideEffects(ofApply: apply).ownership
155167
}
156168
}
157169

@@ -180,6 +192,11 @@ private struct SideEffectsVisitor : EscapeVisitorWithResult {
180192
var followLoads: Bool { !isAddress }
181193
}
182194

195+
private struct AddressVisibleByBuiltinOnceVisitor : EscapeVisitor {
196+
var followTrivialTypes: Bool { true }
197+
var followLoads: Bool { false }
198+
}
199+
183200
/// Lets `ProjectedValue.isEscaping` return true if the value is "escaping" to the `target` instruction.
184201
private struct EscapesToInstructionVisitor : EscapeVisitor {
185202
let target: Instruction
@@ -229,3 +246,13 @@ private struct IsIndirectResultWalker: AddressDefUseWalker {
229246
}
230247
}
231248

249+
private extension SideEffects.Memory {
250+
var bridged: swift.MemoryBehavior {
251+
switch (read, write) {
252+
case (false, false): return .None
253+
case (true, false): return .MayRead
254+
case (false, true): return .MayWrite
255+
case (true, true): return .MayReadWrite
256+
}
257+
}
258+
}

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct CalleeAnalysis {
2525
// getMemBehaviorFn
2626
{ (bridgedApply: BridgedInstruction, observeRetains: Bool, bca: BridgedCalleeAnalysis) -> swift.MemoryBehavior in
2727
let apply = bridgedApply.instruction as! ApplySite
28-
let e = bca.analysis.getSideEffects(of: apply)
28+
let e = bca.analysis.getSideEffects(ofApply: apply)
2929
return e.getMemBehavior(observeRetains: observeRetains)
3030
}
3131
)
@@ -60,8 +60,12 @@ public struct CalleeAnalysis {
6060
}
6161

6262
/// Returns the global (i.e. not argument specific) side effects of an apply.
63-
public func getSideEffects(of apply: ApplySite) -> SideEffects.GlobalEffects {
64-
guard let callees = getCallees(callee: apply.callee) else {
63+
public func getSideEffects(ofApply apply: ApplySite) -> SideEffects.GlobalEffects {
64+
return getSideEffects(ofCallee: apply.callee)
65+
}
66+
67+
public func getSideEffects(ofCallee callee: Value) -> SideEffects.GlobalEffects {
68+
guard let callees = getCallees(callee: callee) else {
6569
return .worstEffects
6670
}
6771

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

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ swift_compiler_sources(Optimizer
1111
CleanupDebugSteps.swift
1212
ComputeEscapeEffects.swift
1313
ComputeSideEffects.swift
14+
InitializeStaticGlobals.swift
1415
ObjCBridgingOptimization.swift
1516
MergeCondFails.swift
1617
ReleaseDevirtualizer.swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//===--- InitializeStaticGlobals.swift -------------------------------------==//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
/// Converts a lazily initialized global to a statically initialized global variable.
16+
///
17+
/// When this pass runs on a global initializer `[global_init_once_fn]` it tries to
18+
/// create a static initializer for the initialized global.
19+
///
20+
/// ```
21+
/// sil [global_init_once_fn] @globalinit {
22+
/// alloc_global @the_global
23+
/// %a = global_addr @the_global
24+
/// %i = some_const_initializer_insts
25+
/// store %i to %a
26+
/// }
27+
/// ```
28+
/// The pass creates a static initializer for the global:
29+
/// ```
30+
/// sil_global @the_global = {
31+
/// %initval = some_const_initializer_insts
32+
/// }
33+
/// ```
34+
/// and removes the allocation and store instructions from the initializer function:
35+
/// ```
36+
/// sil [global_init_once_fn] @globalinit {
37+
/// %a = global_addr @the_global
38+
/// %i = some_const_initializer_insts
39+
/// }
40+
/// ```
41+
/// The initializer then becomes a side-effect free function which let's the builtin-
42+
/// simplification remove the `builtin "once"` which calls the initializer.
43+
///
44+
let initializeStaticGlobalsPass = FunctionPass(name: "initialize-static-globals") {
45+
(function: Function, context: FunctionPassContext) in
46+
47+
if !function.isGlobalInitOnceFunction {
48+
return
49+
}
50+
51+
guard let (allocInst, storeToGlobal) = function.getGlobalInitialization() else {
52+
return
53+
}
54+
55+
if !allocInst.global.canBeInitializedStatically {
56+
return
57+
}
58+
59+
context.createStaticInitializer(for: allocInst.global,
60+
initValue: storeToGlobal.source as! SingleValueInstruction)
61+
context.erase(instruction: allocInst)
62+
context.erase(instruction: storeToGlobal)
63+
}
64+
65+
private extension Function {
66+
/// Analyses the global initializer function and returns the `alloc_global` and `store`
67+
/// instructions which initialize the global.
68+
///
69+
/// The function's single basic block must contain following code pattern:
70+
/// ```
71+
/// alloc_global @the_global
72+
/// %a = global_addr @the_global
73+
/// %i = some_const_initializer_insts
74+
/// store %i to %a
75+
/// ```
76+
func getGlobalInitialization() -> (allocInst: AllocGlobalInst, storeToGlobal: StoreInst)? {
77+
78+
guard let block = singleBlock else {
79+
return nil
80+
}
81+
82+
var allocInst: AllocGlobalInst? = nil
83+
var globalAddr: GlobalAddrInst? = nil
84+
var store: StoreInst? = nil
85+
86+
for inst in block.instructions {
87+
switch inst {
88+
case is ReturnInst,
89+
is DebugValueInst,
90+
is DebugStepInst:
91+
break
92+
case let agi as AllocGlobalInst:
93+
if allocInst != nil {
94+
return nil
95+
}
96+
allocInst = agi
97+
case let ga as GlobalAddrInst:
98+
if globalAddr != nil {
99+
return nil
100+
}
101+
guard let agi = allocInst, agi.global == ga.global else {
102+
return nil
103+
}
104+
globalAddr = ga
105+
case let si as StoreInst:
106+
if store != nil {
107+
return nil
108+
}
109+
guard let ga = globalAddr else {
110+
return nil
111+
}
112+
if si.destination != ga {
113+
return nil
114+
}
115+
store = si
116+
default:
117+
if !inst.isValidInStaticInitializerOfGlobal {
118+
return nil
119+
}
120+
}
121+
}
122+
if let store = store {
123+
return (allocInst: allocInst!, storeToGlobal: store)
124+
}
125+
return nil
126+
}
127+
128+
var singleBlock: BasicBlock? {
129+
let block = entryBlock
130+
if block.next != nil {
131+
return nil
132+
}
133+
return block
134+
}
135+
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ swift_compiler_sources(Optimizer
1212
SimplifyBranch.swift
1313
SimplifyBuiltin.swift
1414
SimplifyCondBranch.swift
15+
SimplifyCondFail.swift
16+
SimplifyDebugStep.swift
17+
SimplifyDestructure.swift
1518
SimplifyGlobalValue.swift
19+
SimplifyLoad.swift
1620
SimplifyStrongRetainRelease.swift
1721
SimplifyStructExtract.swift
22+
SimplifyTupleExtract.swift
1823
SimplifyUncheckedEnumData.swift)

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

+28-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ extension BuiltinInst : OnoneSimplifyable {
2222
optimizeIsConcrete(allowArchetypes: false, context)
2323
case .IsSameMetatype:
2424
optimizeIsSameMetatype(context)
25+
case .Once:
26+
optimizeBuiltinOnce(context)
2527
default:
26-
// TODO: handle other builtin types
27-
break
28+
if let literal = constantFold(context) {
29+
uses.replaceAll(with: literal, context)
30+
}
2831
}
2932
}
3033
}
@@ -64,6 +67,29 @@ private extension BuiltinInst {
6467

6568
uses.replaceAll(with: result, context)
6669
}
70+
71+
func optimizeBuiltinOnce(_ context: SimplifyContext) {
72+
guard let callee = calleeOfOnce, callee.isDefinition else {
73+
return
74+
}
75+
// If the callee is side effect-free we can remove the whole builtin "once".
76+
// We don't use the callee's memory effects but instead look at all callee instructions
77+
// because memory effects are not computed in the Onone pipeline, yet.
78+
// This is no problem because the callee (usually a global init function )is mostly very small,
79+
// or contains the side-effect instruction `alloc_global` right at the beginning.
80+
if callee.instructions.contains(where: { $0.mayReadOrWriteMemory || $0.hasUnspecifiedSideEffects }) {
81+
return
82+
}
83+
context.erase(instruction: self)
84+
}
85+
86+
var calleeOfOnce: Function? {
87+
let callee = operands[1].value
88+
if let fri = callee as? FunctionRefInst {
89+
return fri.referencedFunction
90+
}
91+
return nil
92+
}
6793
}
6894

6995
private func typesOfValuesAreEqual(_ lhs: Value, _ rhs: Value, in function: Function) -> Bool? {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===--- SimplifyCondFail.swift -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
extension CondFailInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
18+
/// Eliminates
19+
/// ```
20+
/// %0 = integer_literal 0
21+
/// cond_fail %0, "message"
22+
/// ```
23+
if let literal = condition as? IntegerLiteralInst,
24+
literal.value.isZero() {
25+
26+
context.erase(instruction: self)
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===--- SimplifyDebugStep.swift ------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
extension DebugStepInst : Simplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
// When compiling with optimizations (note: it's not a OnoneSimplifyable transformation),
18+
// unconditionally remove debug_step instructions.
19+
context.erase(instruction: self)
20+
}
21+
}
22+

0 commit comments

Comments
 (0)