Skip to content

Commit cee4505

Browse files
committed
SimplifyLoad: improve simplification of load of global variable
Inline the initialization code of a global initializer if the load is a global_addr with a builtin "once" dependency.
1 parent 3229749 commit cee4505

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ extension LoadInst : OnoneSimplifyable, SILCombineSimplifyable {
9898

9999
/// The load of a global let variable is replaced by its static initializer value.
100100
private func replaceLoadOfGlobalLet(_ context: SimplifyContext) -> Bool {
101-
guard let globalInitVal = getGlobalInitValue(address: address) else {
101+
guard let globalInitVal = getGlobalInitValue(address: address, context) else {
102102
return false
103103
}
104104
if !globalInitVal.canBeCopied(into: parentFunction, context) {
@@ -211,30 +211,51 @@ extension LoadInst : OnoneSimplifyable, SILCombineSimplifyable {
211211
}
212212

213213
/// Returns the init value of a global which is loaded from `address`.
214-
private func getGlobalInitValue(address: Value) -> Value? {
214+
private func getGlobalInitValue(address: Value, _ context: SimplifyContext) -> Value? {
215215
switch address {
216216
case let gai as GlobalAddrInst:
217217
if gai.global.isLet {
218-
return gai.global.staticInitValue
218+
if let staticInitValue = gai.global.staticInitValue {
219+
return staticInitValue
220+
}
221+
if let staticInitValue = getInitializerFromInitFunction(of: gai, context) {
222+
return staticInitValue
223+
}
219224
}
220225
case let pta as PointerToAddressInst:
221226
return globalLoadedViaAddressor(pointer: pta.pointer)?.staticInitValue
222227
case let sea as StructElementAddrInst:
223-
if let structVal = getGlobalInitValue(address: sea.struct) as? StructInst {
228+
if let structVal = getGlobalInitValue(address: sea.struct, context) as? StructInst {
224229
return structVal.operands[sea.fieldIndex].value
225230
}
226231
case let tea as TupleElementAddrInst:
227-
if let tupleVal = getGlobalInitValue(address: tea.tuple) as? TupleInst {
232+
if let tupleVal = getGlobalInitValue(address: tea.tuple, context) as? TupleInst {
228233
return tupleVal.operands[tea.fieldIndex].value
229234
}
230235
case let bai as BeginAccessInst:
231-
return getGlobalInitValue(address: bai.address)
236+
return getGlobalInitValue(address: bai.address, context)
232237
default:
233238
break
234239
}
235240
return nil
236241
}
237242

243+
private func getInitializerFromInitFunction(of globalAddr: GlobalAddrInst, _ context: SimplifyContext) -> Value? {
244+
guard let dependentOn = globalAddr.dependencyToken,
245+
let builtinOnce = dependentOn as? BuiltinInst,
246+
builtinOnce.id == .Once,
247+
let initFnRef = builtinOnce.operands[1].value as? FunctionRefInst else
248+
{
249+
return nil
250+
}
251+
let initFn = initFnRef.referencedFunction
252+
context.notifyDependency(onBodyOf: initFn)
253+
guard let (_, storeToGlobal) = getGlobalInitialization(of: initFn, allowGlobalValue: true) else {
254+
return nil
255+
}
256+
return storeToGlobal.source
257+
}
258+
238259
private func globalLoadedViaAddressor(pointer: Value) -> GlobalVariable? {
239260
if let ai = pointer as? ApplyInst,
240261
let callee = ai.referencedFunction,

test/SILOptimizer/simplify_load.sil

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,36 @@ sil_global [let] @gstr : $Str = {
2323
class B { }
2424
class E : B { }
2525

26+
sil_global hidden [let] @gb : $B
27+
sil_global hidden [let] @gb2 : $(B, Int64)
28+
29+
sil_global private @gb_obj : $B = {
30+
%initval = object $B ()
31+
}
32+
33+
sil [global_init_once_fn] @init_gb : $@convention(c) () -> () {
34+
bb0:
35+
alloc_global @gb
36+
%1 = global_addr @gb : $*B
37+
%2 = global_value @gb_obj : $B
38+
store %2 to %1 : $*B
39+
%6 = tuple ()
40+
return %6 : $()
41+
}
42+
43+
sil [global_init_once_fn] @init_gb2 : $@convention(c) () -> () {
44+
bb0:
45+
alloc_global @gb2
46+
%1 = global_addr @gb2 : $*(B, Int64)
47+
%2 = global_value @gb_obj : $B
48+
%3 = integer_literal $Builtin.Int64, 10
49+
%4 = struct $Int64 (%3 : $Builtin.Int64)
50+
%5 = tuple (%2 : $B, %4 : $Int64)
51+
store %5 to %1 : $*(B, Int64)
52+
%6 = tuple ()
53+
return %6 : $()
54+
}
55+
2656
sil [global_init] @gstr_addressor : $@convention(thin) () -> Builtin.RawPointer {
2757
bb0:
2858
%0 = global_addr @gstr : $*Str
@@ -96,6 +126,64 @@ bb0:
96126
return %3 : $Int64
97127
}
98128

129+
// CHECK-LABEL: sil @load_global_object :
130+
// CHECK: %1 = global_value @gb_obj
131+
// CHECK-NEXT: return %1
132+
// CHECK: } // end sil function 'load_global_object'
133+
sil @load_global_object : $@convention(thin) (Builtin.RawPointer) -> @owned B {
134+
bb0(%0 : $Builtin.RawPointer):
135+
%1 = function_ref @init_gb : $@convention(c) () -> ()
136+
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
137+
%3 = global_addr @gb : $*B depends_on %2
138+
%4 = load %3 : $*B
139+
return %4 : $B
140+
}
141+
142+
// CHECK-LABEL: sil @load_global_object_keep_once :
143+
// CHECK: %2 = builtin "once"
144+
// CHECK: %3 = global_value @gb_obj
145+
// CHECK: fix_lifetime
146+
// CHECK: return %3
147+
// CHECK: } // end sil function 'load_global_object_keep_once'
148+
sil @load_global_object_keep_once : $@convention(thin) (Builtin.RawPointer) -> @owned B {
149+
bb0(%0 : $Builtin.RawPointer):
150+
%1 = function_ref @init_gb : $@convention(c) () -> ()
151+
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
152+
%3 = global_addr @gb : $*B depends_on %2
153+
%4 = load %3 : $*B
154+
%5 = global_addr @gb : $*B depends_on %2
155+
fix_lifetime %5 : $*B
156+
return %4 : $B
157+
}
158+
159+
// CHECK-LABEL: sil @load_global_object_from_tuple :
160+
// CHECK: %1 = global_value @gb_obj
161+
// CHECK-NEXT: return %1
162+
// CHECK: } // end sil function 'load_global_object_from_tuple'
163+
sil @load_global_object_from_tuple : $@convention(thin) (Builtin.RawPointer) -> @owned B {
164+
bb0(%0 : $Builtin.RawPointer):
165+
%1 = function_ref @init_gb2 : $@convention(c) () -> ()
166+
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
167+
%3 = global_addr @gb2 : $*(B, Int64) depends_on %2
168+
%4 = tuple_element_addr %3 : $*(B, Int64), 0
169+
%5 = load %4 : $*B
170+
return %5 : $B
171+
}
172+
173+
// CHECK-LABEL: sil @load_global_tuple :
174+
// CHECK: %1 = global_value @gb_obj
175+
// CHECK: [[T:%.*]] = tuple (%1 : $B, {{%.*}} : $Int64)
176+
// CHECK-NEXT: return [[T]]
177+
// CHECK: } // end sil function 'load_global_tuple'
178+
sil @load_global_tuple : $@convention(thin) (Builtin.RawPointer) -> @owned (B, Int64) {
179+
bb0(%0 : $Builtin.RawPointer):
180+
%1 = function_ref @init_gb2 : $@convention(c) () -> ()
181+
%2 = builtin "once"(%0 : $Builtin.RawPointer, %1 : $@convention(c) () -> ()) : $Builtin.SILToken
182+
%3 = global_addr @gb2 : $*(B, Int64) depends_on %2
183+
%4 = load %3 : $*(B, Int64)
184+
return %4 : $(B, Int64)
185+
}
186+
99187
// CHECK-LABEL: sil @load_first_char_from_string_literal
100188
// CHECK: bb0:
101189
// CHECK-NEXT: %0 = integer_literal $Builtin.Int8, 97

0 commit comments

Comments
 (0)