Skip to content

Commit e34c20f

Browse files
authored
Merge pull request #67243 from kubamracek/section-ump
Allow forced constant-folding of global initializers to work on UnsafeMutablePointer types
2 parents 60edc76 + 2876f54 commit e34c20f

File tree

8 files changed

+118
-19
lines changed

8 files changed

+118
-19
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyInitEnumDataAddr.swift

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extension InitEnumDataAddrInst : OnoneSimplifyable {
1818
// Optimize the sequence
1919
// ```
2020
// %1 = init_enum_data_addr %enum_addr, #someCaseWithPayload
21+
// ...
2122
// store %payload to %1
2223
// inject_enum_addr %enum_addr, #someCaseWithPayload
2324
// ```
@@ -26,18 +27,16 @@ extension InitEnumDataAddrInst : OnoneSimplifyable {
2627
// %1 = enum $E, #someCaseWithPayload, %payload
2728
// store %1 to %enum_addr
2829
// ```
29-
// This sequence of three instructions must appear in consecutive order.
30+
// This store and inject instructions must appear in consecutive order.
3031
// But usually this is the case, because it's generated this way by SILGen.
32+
// We also check that between the init and the store, no instruction writes to memory.
3133
//
32-
if let nextInst = self.next,
33-
let store = nextInst as? StoreInst,
34+
if let store = self.uses.singleUse?.instruction as? StoreInst,
3435
store.destination == self,
35-
let singleUse = self.uses.singleUse,
36-
singleUse.instruction == store,
37-
let nextAfterStore = store.next,
38-
let inject = nextAfterStore as? InjectEnumAddrInst,
36+
let inject = store.next as? InjectEnumAddrInst,
3937
inject.enum == self.enum,
40-
inject.enum.type.isLoadable(in: parentFunction) {
38+
inject.enum.type.isLoadable(in: parentFunction),
39+
!anyInstructionMayWriteToMemory(between: self, and: store) {
4140

4241
assert(self.caseIndex == inject.caseIndex, "mismatching case indices when creating an enum")
4342

@@ -51,3 +50,19 @@ extension InitEnumDataAddrInst : OnoneSimplifyable {
5150
}
5251
}
5352
}
53+
54+
// Returns false if `first` and `last` are in the same basic block and no instructions between them write to memory. True otherwise.
55+
private func anyInstructionMayWriteToMemory(between first: Instruction, and last: Instruction) -> Bool {
56+
var nextInstruction = first.next
57+
while let i = nextInstruction {
58+
if i == last {
59+
return false
60+
}
61+
if i.mayWriteToMemory {
62+
return true
63+
}
64+
nextInstruction = i.next
65+
}
66+
// End of basic block, and we did not find `last`
67+
return true
68+
}

SwiftCompilerSources/Sources/SIL/GlobalVariable.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ extension Instruction {
8282
return type.isBuiltinInteger || type.isBuiltinFloat
8383
case .PtrToInt:
8484
return bi.operands[0].value is StringLiteralInst
85+
case .IntToPtr:
86+
return bi.operands[0].value is IntegerLiteralInst
8587
case .StringObjectOr:
8688
// The first operand can be a string literal (i.e. a pointer), but the
8789
// second operand must be a constant. This enables creating a

lib/IRGen/GenConstant.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ Explosion irgen::emitConstantValue(IRGenModule &IGM, SILValue operand,
302302
auto *ptr = emitConstantValue(IGM, args[0]).claimNextConstant();
303303
return llvm::ConstantExpr::getPtrToInt(ptr, IGM.IntPtrTy);
304304
}
305+
case BuiltinValueKind::IntToPtr: {
306+
auto *num = emitConstantValue(IGM, args[0]).claimNextConstant();
307+
return llvm::ConstantExpr::getIntToPtr(num, IGM.Int8PtrTy);
308+
}
305309
case BuiltinValueKind::ZExtOrBitCast: {
306310
auto *val = emitConstantValue(IGM, args[0]).claimNextConstant();
307311
return llvm::ConstantExpr::getZExtOrBitCast(val,

test/IRGen/section.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
@_section("__TEXT,__mysection") var g1: (Int, Int) = (42, 43)
99
@_section("__TEXT,__mysection") var g2: Bool = true
1010
@_section("__TEXT,__mysection") public var g3: Bool = true
11+
@_section("__TEXT,__mysection") var g4: UnsafeMutablePointer<Int>? = nil
12+
@_section("__TEXT,__mysection") var g5: UnsafeMutablePointer<Int>? = UnsafeMutablePointer(bitPattern: 0x42424242)
1113
@_section("__TEXT,__mysection") func foo() {}
1214

1315
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set }
1416
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set }
1517
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set }
18+
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue public var g3: Bool { get set }
19+
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g4: UnsafeMutablePointer<Int>? { get set }
20+
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g5: UnsafeMutablePointer<Int>? { get set }
1621
// SIL: @_section("__TEXT,__mysection") func foo()
1722
// SIL: sil private [global_init_once_fn] @$s7section2g0_WZ : $@convention(c)
1823
// SIL: sil hidden [global_init] @$s7section2g0Sivau : $@convention(thin)
@@ -22,6 +27,10 @@
2227
// SIL: sil hidden [global_init] @$s7section2g2Sbvau : $@convention(thin)
2328
// SIL: sil private [global_init_once_fn] @$s7section2g3_WZ : $@convention(c)
2429
// SIL: sil [global_init] @$s7section2g3Sbvau : $@convention(thin)
30+
// SIL: sil private [global_init_once_fn] @$s7section2g4_WZ : $@convention(c)
31+
// SIL: sil hidden [global_init] @$s7section2g4SpySiGSgvau : $@convention(thin)
32+
// SIL: sil private [global_init_once_fn] @$s7section2g5_WZ : $@convention(c)
33+
// SIL: sil hidden [global_init] @$s7section2g5SpySiGSgvau : $@convention(thin)
2534
// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section3fooyyF : $@convention(thin)
2635

2736
// IR: @"$s7section2g0_Wz" = internal global {{(i64|i32)}} 0
@@ -32,6 +41,10 @@
3241
// IR: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__TEXT,__mysection"
3342
// IR: @"$s7section2g3_Wz" = internal global {{(i64|i32)}} 0
3443
// IR: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__TEXT,__mysection"
44+
// IR: @"$s7section2g4_Wz" = internal global {{i64|i32}} 0
45+
// IR: @"$s7section2g4SpySiGSgvp" = hidden global {{i64|i32}} 0, section "__TEXT,__mysection"
46+
// IR: @"$s7section2g5_Wz" = internal global {{i64|i32}} 0
47+
// IR: @"$s7section2g5SpySiGSgvp" = hidden global {{i64|i32}} 1111638594, section "__TEXT,__mysection"
3548
// IR: define {{.*}}@"$s7section3fooyyF"(){{.*}} section "__TEXT,__mysection"
3649

3750
// ASM: .section{{.*}}__TEXT,__mysection
@@ -46,3 +59,7 @@
4659
// ASM: $s7section2g2Sbvp:
4760
// ASM-NOT: .section
4861
// ASM: $s7section2g3Sbvp:
62+
// ASM-NOT: .section
63+
// ASM: $s7section2g4SpySiGSgvp:
64+
// ASM-NOT: .section
65+
// ASM: $s7section2g5SpySiGSgvp:

test/IRGen/section_non_const.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,6 @@ struct MyStruct6 {
7575
}
7676
}
7777
@_section("__TEXT,__mysection") var g_MyStruct6: MyStruct6 = MyStruct6(a: 42) // expected-error {{global variable must be a compile-time constant to use @_section attribute}}
78+
79+
@_section("__TEXT,__mysection") var gp1: UnsafeMutablePointer<Int>? = nil
80+
@_section("__TEXT,__mysection") var gp2: UnsafeMutablePointer<Int>? = UnsafeMutablePointer(bitPattern: 0x42424242)

test/SILOptimizer/init_static_globals.sil

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ sil_global private @g1_token : $Builtin.Word
6666
sil_global [let] @g2 : $Int32
6767
sil_global private @g2_token : $Builtin.Word
6868

69+
// CHECK-LABEL: sil_global [let] @g3 : $Optional<UnsafeMutablePointer<Int>>
70+
sil_global [let] @g3 : $Optional<UnsafeMutablePointer<Int>>
71+
sil_global private @g3_token : $Builtin.Word
72+
73+
// CHECK-LABEL: sil_global [let] @g4 : $Optional<UnsafeMutablePointer<Int>>
74+
sil_global [let] @g4 : $Optional<UnsafeMutablePointer<Int>>
75+
sil_global private @g4_token : $Builtin.Word
76+
6977

7078
// CHECK-LABEL: sil [global_init_once_fn] [ossa] @globalinit_trivialglobal_func :
7179
// CHECK-NOT: alloc_global
@@ -151,3 +159,33 @@ bb0:
151159
return %6 : $()
152160
}
153161

162+
// CHECK-LABEL: sil [global_init_once_fn] [ossa] @globalinit_enum :
163+
// CHECK-NOT: alloc_global
164+
// CHECK-NOT: store
165+
// CHECK: } // end sil function 'globalinit_enum'
166+
sil [global_init_once_fn] [ossa] @globalinit_enum : $@convention(c) () -> () {
167+
bb0:
168+
alloc_global @g3
169+
%2 = global_addr @g3 : $*Optional<UnsafeMutablePointer<Int>>
170+
%3 = enum $Optional<UnsafeMutablePointer<Int>>, #Optional.none!enumelt
171+
store %3 to [trivial] %2 : $*Optional<UnsafeMutablePointer<Int>>
172+
%5 = tuple ()
173+
return %5 : $()
174+
}
175+
176+
// CHECK-LABEL: sil [global_init_once_fn] [ossa] @globalinit_enum_inttoptr :
177+
// CHECK-NOT: alloc_global
178+
// CHECK-NOT: store
179+
// CHECK: } // end sil function 'globalinit_enum_inttoptr'
180+
sil [global_init_once_fn] [ossa] @globalinit_enum_inttoptr : $@convention(c) () -> () {
181+
bb0:
182+
alloc_global @g4
183+
%2 = global_addr @g4 : $*Optional<UnsafeMutablePointer<Int>>
184+
%4 = integer_literal $Builtin.Word, 1111638594
185+
%5 = builtin "inttoptr_Word"(%4 : $Builtin.Word) : $Builtin.RawPointer
186+
%6 = struct $UnsafeMutablePointer<Int> (%5 : $Builtin.RawPointer)
187+
%7 = enum $Optional<UnsafeMutablePointer<Int>>, #Optional.some!enumelt, %6 : $UnsafeMutablePointer<Int>
188+
store %7 to [trivial] %2 : $*Optional<UnsafeMutablePointer<Int>>
189+
%10 = tuple ()
190+
return %10 : $()
191+
}

test/SILOptimizer/optimize_keypath.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
// RUN: %target-build-swift -O %s -o %t/a.out
77
// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT
8-
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib
8+
// REQUIRES: executable_test,optimized_stdlib
99
// REQUIRES: CPU=arm64 || CPU=x86_64
1010

1111
// REQUIRES: swift_in_compiler
@@ -388,9 +388,8 @@ func testClassMemberComputedModify<T : P>(_ s: inout GenClass<T>) {
388388
// CHECK: [[F:%[0-9]+]] = select_enum [[O:%[0-9]+]]
389389
// CHECK: cond_fail [[F]]
390390
// CHECK: unchecked_enum_data [[O]]
391-
// CHECK: [[E2:%[0-9]+]] = init_enum_data_addr [[E1:%[0-9]+]]
392-
// CHECK: store {{%[0-9]+}} to [[E2]]
393-
// CHECK: inject_enum_addr [[E1]]
391+
// CHECK: [[E2:%[0-9]+]] = enum $Optional<SimpleStruct.Nested>
392+
// CHECK: store [[E2]] to {{%[0-9]+}}
394393
// CHECK: return
395394
@inline(never)
396395
@_semantics("optimize.sil.specialize.generic.never")
@@ -405,9 +404,8 @@ func testModifyOptionalForce(_ s: inout SimpleStruct) {
405404
// CHECK: [[F:%[0-9]+]] = select_enum
406405
// CHECK: cond_fail [[F]]
407406
// CHECK: unchecked_enum_data [[E1:%[0-9]+]]
408-
// CHECK: [[E2:%[0-9]+]] = init_enum_data_addr [[E1:%[0-9]+]]
409-
// CHECK: store {{%[0-9]+}} to [[E2]]
410-
// CHECK: inject_enum_addr [[E1]]
407+
// CHECK: [[E2:%[0-9]+]] = enum $Optional<SimpleClass.Nested>
408+
// CHECK: store [[E2]] to {{%[0-9]+}}
411409
// CHECK: end_access
412410
// CHECK: return
413411
@inline(never)

test/SILOptimizer/simplify_init_enum_data_addr.sil

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ enum E {
1010
case B(AnyObject)
1111
}
1212

13-
enum GenE<T> {
14-
case A(Int)
15-
case B(T)
16-
}
1713
// CHECK-LABEL: sil @optional_int
1814
// CHECK: %2 = enum $Optional<Int>, #Optional.some!enumelt, %1 : $Int
1915
// CHECK: store %2 to %0 : $*Optional<Int>
@@ -59,6 +55,11 @@ bb0(%0 : $*E, %1 : $Int):
5955
return %5 : $()
6056
}
6157

58+
enum GenE<T> {
59+
case A(Int)
60+
case B(T)
61+
}
62+
6263
// CHECK-LABEL: sil [ossa] @not_loadable
6364
// CHECK: %2 = init_enum_data_addr
6465
// CHECK: store %1 to [trivial] %2
@@ -73,3 +74,24 @@ bb0(%0 : $*GenE<T>, %1 : $Int):
7374
return %5 : $()
7475
}
7576

77+
enum F {
78+
case A(UnsafeMutableRawPointer)
79+
case B(AnyObject)
80+
}
81+
82+
// CHECK-LABEL: sil [ossa] @enum_data_addr
83+
// CHECK: %2 = struct $UnsafeMutableRawPointer (%1 : $Builtin.RawPointer)
84+
// CHECK: %3 = enum $F, #F.A!enumelt, %2 : $UnsafeMutableRawPointer
85+
// CHECK: store %3 to [init] %0 : $*F
86+
// CHECK: %5 = tuple ()
87+
// CHECK: return %5
88+
// CHECK: } // end sil function 'enum_data_addr'
89+
sil [ossa] @enum_data_addr : $@convention(thin) (Builtin.RawPointer) -> @out F {
90+
bb0(%0 : $*F, %1 : $Builtin.RawPointer):
91+
%2 = init_enum_data_addr %0 : $*F, #F.A!enumelt
92+
%3 = struct $UnsafeMutableRawPointer (%1 : $Builtin.RawPointer)
93+
store %3 to [trivial] %2 : $*UnsafeMutableRawPointer
94+
inject_enum_addr %0 : $*F, #F.A!enumelt
95+
%6 = tuple ()
96+
return %6 : $()
97+
}

0 commit comments

Comments
 (0)