Skip to content

Commit c85153a

Browse files
committed
SimplifyLoad: remove a load from a global object, e.g. from an outlined array
Loading array elements or the array's count/capacity can be replaced with the actual value if the array is a statically allocated global let-variable.
1 parent e5fea75 commit c85153a

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,34 @@ private func getGlobalInitValue(address: Value, _ context: SimplifyContext) -> V
234234
}
235235
case let bai as BeginAccessInst:
236236
return getGlobalInitValue(address: bai.address, context)
237+
case let rta as RefTailAddrInst:
238+
return getGlobalTailElement(of: rta, index: 0)
239+
case let ia as IndexAddrInst:
240+
if let rta = ia.base as? RefTailAddrInst,
241+
let literal = ia.index as? IntegerLiteralInst,
242+
let index = literal.value
243+
{
244+
return getGlobalTailElement(of: rta, index: index)
245+
}
246+
case let rea as RefElementAddrInst:
247+
if let object = rea.instance.immutableGlobalObjectRoot {
248+
return object.baseOperands[rea.fieldIndex].value
249+
}
237250
default:
238251
break
239252
}
240253
return nil
241254
}
242255

256+
private func getGlobalTailElement(of refTailAddr: RefTailAddrInst, index: Int) -> Value? {
257+
if let object = refTailAddr.instance.immutableGlobalObjectRoot,
258+
index >= 0 && index < object.tailOperands.count
259+
{
260+
return object.tailOperands[index].value
261+
}
262+
return nil
263+
}
264+
243265
private func getInitializerFromInitFunction(of globalAddr: GlobalAddrInst, _ context: SimplifyContext) -> Value? {
244266
guard let dependentOn = globalAddr.dependencyToken,
245267
let builtinOnce = dependentOn as? BuiltinInst,
@@ -321,6 +343,19 @@ private extension Value {
321343
}
322344
return (baseAddress: self, offset: 0)
323345
}
346+
347+
// If the reference-root of self references a global object, returns the `object` instruction of the
348+
// global's initializer. But only if the global is a let-global.
349+
var immutableGlobalObjectRoot: ObjectInst? {
350+
if let gv = self.referenceRoot as? GlobalValueInst,
351+
gv.global.isLet,
352+
let initval = gv.global.staticInitValue,
353+
let object = initval as? ObjectInst
354+
{
355+
return object
356+
}
357+
return nil
358+
}
324359
}
325360

326361
private extension Instruction {

test/SILOptimizer/redundant_load_elimination.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ public func testLetField(_ c: C, f: () -> ()) -> (Int, Int) {
2727
let globalLetArray = [1, 2, 3, 4]
2828

2929
// CHECK-LABEL: sil @$s4test5test15indexS2i_tF :
30-
// CHECK: load
3130
// CHECK: [[L:%.*]] = load
3231
// CHECK-NOT: load
3332
// CHECK: builtin "sadd_with_overflow{{.*}}"([[L]] : {{.*}}, [[L]] :

test/SILOptimizer/simplify_load.sil

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

26+
class C {
27+
@_hasStorage var c: Builtin.Int64
28+
}
29+
30+
class D : C {
31+
@_hasStorage var d: Builtin.Int64
32+
}
33+
2634
sil_global hidden [let] @gb : $B
2735
sil_global hidden [let] @gb2 : $(B, Int64)
2836

2937
sil_global private @gb_obj : $B = {
3038
%initval = object $B ()
3139
}
3240

41+
sil_global [let] @gc : $D = {
42+
%0 = integer_literal $Builtin.Int64, 0
43+
%1 = integer_literal $Builtin.Int64, 1
44+
%2 = integer_literal $Builtin.Int64, 2
45+
%3 = integer_literal $Builtin.Int64, 3
46+
%initval = object $D (%0, %1, [tail_elems] %2, %3)
47+
}
48+
49+
sil_global @gc_var : $D = {
50+
%0 = integer_literal $Builtin.Int64, 0
51+
%1 = integer_literal $Builtin.Int64, 1
52+
%2 = integer_literal $Builtin.Int64, 2
53+
%3 = integer_literal $Builtin.Int64, 3
54+
%initval = object $D (%0, %1, [tail_elems] %2, %3)
55+
}
56+
3357
sil [global_init_once_fn] @init_gb : $@convention(c) () -> () {
3458
bb0:
3559
alloc_global @gb
@@ -469,3 +493,40 @@ bb0(%0 : $*B):
469493
return %3 : $()
470494
}
471495

496+
// CHECK-LABEL: sil [ossa] @load_from_global_object :
497+
// CHECK-DAG: [[I0:%.*]] = integer_literal $Builtin.Int64, 0
498+
// CHECK-DAG: [[I1:%.*]] = integer_literal $Builtin.Int64, 1
499+
// CHECK-DAG: [[I2:%.*]] = integer_literal $Builtin.Int64, 2
500+
// CHECK-DAG: [[I3:%.*]] = integer_literal $Builtin.Int64, 3
501+
// CHECK: [[T:%.*]] = tuple ([[I0]] : $Builtin.Int64, [[I1]] : $Builtin.Int64, [[I2]] : $Builtin.Int64, [[I3]] : $Builtin.Int64)
502+
// CHECK: return [[T]]
503+
// CHECK: } // end sil function 'load_from_global_object'
504+
sil [ossa] @load_from_global_object : $@convention(thin) () -> (Builtin.Int64, Builtin.Int64, Builtin.Int64, Builtin.Int64) {
505+
bb0:
506+
%0 = global_value @gc : $D
507+
%1 = upcast %0 to $C
508+
%2 = ref_element_addr %1, #C.c
509+
%3 = ref_element_addr %0, #D.d
510+
%4 = ref_tail_addr %1, $Builtin.Int64
511+
%5 = integer_literal $Builtin.Word, 1
512+
%6 = index_addr %4, %5
513+
%7 = load [trivial] %2
514+
%8 = load [trivial] %3
515+
%9 = load [trivial] %4
516+
%10 = load [trivial] %6
517+
%11 = tuple (%7, %8, %9, %10)
518+
return %11
519+
}
520+
521+
// CHECK-LABEL: sil [ossa] @dont_load_from_global_var_object :
522+
// CHECK: [[L:%.*]] = load
523+
// CHECK: return [[L]]
524+
// CHECK: } // end sil function 'dont_load_from_global_var_object'
525+
sil [ossa] @dont_load_from_global_var_object : $@convention(thin) () -> Builtin.Int64 {
526+
bb0:
527+
%0 = global_value @gc_var : $D
528+
%1 = ref_element_addr %0, #D.d
529+
%2 = load [trivial] %1
530+
return %2
531+
}
532+

0 commit comments

Comments
 (0)