Skip to content

Commit 6a0b7d1

Browse files
committed
ObjectOutliner: create outlined arrays as let variables
This will allow load-simplification to replace a load of such an array.
1 parent c690fef commit 6a0b7d1

File tree

10 files changed

+37
-28
lines changed

10 files changed

+37
-28
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocVectorLowering.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ private func createOutlinedGlobal(
227227
let elementType = allocVectorBuiltin.substitutionMap.replacementTypes[0]!
228228
let outlinedGlobal = context.createGlobalVariable(
229229
name: context.mangleOutlinedVariable(from: allocVectorBuiltin.parentFunction),
230-
type: elementType, isPrivate: true)
230+
type: elementType, linkage: .private, isLet: false)
231231

232232
let globalBuilder = Builder(staticInitializerOf: outlinedGlobal, context)
233233

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ private func optimizeObjectAllocation(allocRef: AllocRefInstBase, _ context: Fun
106106

107107
let outlinedGlobal = context.createGlobalVariable(
108108
name: context.mangleOutlinedVariable(from: allocRef.parentFunction),
109-
type: allocRef.type, isPrivate: true)
109+
type: allocRef.type, linkage: .private,
110+
// Only if it's a COW object we can be sure that the object allocated in the global is not mutated.
111+
// If someone wants to mutate it, it has to be copied first.
112+
isLet: endOfInitInst is EndCOWMutationInst)
110113

111114
constructObject(of: allocRef, inInitializerOf: outlinedGlobal, storesToClassFields, storesToTailElements, context)
112115
context.erase(instructions: storesToClassFields)
@@ -562,7 +565,7 @@ private func replace(findStringCall: ApplyInst,
562565

563566
// Create an "opaque" global variable which is passed as inout to
564567
// _findStringSwitchCaseWithCache and into which the function stores the "cache".
565-
let cacheVar = context.createGlobalVariable(name: name, type: cacheType, isPrivate: true)
568+
let cacheVar = context.createGlobalVariable(name: name, type: cacheType, linkage: .private, isLet: false)
566569

567570
let varBuilder = Builder(staticInitializerOf: cacheVar, context)
568571
let zero = varBuilder.createIntegerLiteral(0, type: wordTy)

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,9 @@ struct FunctionPassContext : MutatingContext {
391391
}
392392
}
393393

394-
func createGlobalVariable(name: String, type: Type, isPrivate: Bool) -> GlobalVariable {
394+
func createGlobalVariable(name: String, type: Type, linkage: Linkage, isLet: Bool) -> GlobalVariable {
395395
let gv = name._withBridgedStringRef {
396-
_bridged.createGlobalVariable($0, type.bridged, isPrivate)
396+
_bridged.createGlobalVariable($0, type.bridged, linkage.bridged, isLet)
397397
}
398398
return gv.globalVar
399399
}

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ struct BridgedPassContext {
255255
BridgedFunction applySiteCallee) const;
256256

257257
SWIFT_IMPORT_UNSAFE BridgedGlobalVar createGlobalVariable(BridgedStringRef name, BridgedType type,
258-
bool isPrivate) const;
258+
BridgedLinkage linkage, bool isLet) const;
259259
void inlineFunction(BridgedInstruction apply, bool mandatoryInline) const;
260260
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue getSILUndef(BridgedType type) const;
261261
BRIDGED_INLINE bool optimizeMemoryAccesses(BridgedFunction f) const;

lib/IRGen/GenDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,8 +2755,11 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
27552755
if (forDefinition && !gvar->hasInitializer()) {
27562756
if (initVal) {
27572757
gvar->setInitializer(initVal);
2758-
if (var->isLet() ||
2759-
(var->isInitializedObject() && canMakeStaticObjectReadOnly(var->getLoweredType()))) {
2758+
if (var->isLet() &&
2759+
// Even if it's a `let`, we cannot allocate an object as constant, because it's header
2760+
// (metadata, ref-count) is initialized at runtime.
2761+
// Exception: if it's an array for which we can initialize the header statically.
2762+
(!var->isInitializedObject() || canMakeStaticObjectReadOnly(var->getLoweredType()))) {
27602763
gvar->setConstant(true);
27612764
}
27622765
} else {

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,11 +1879,14 @@ BridgedOwnedString BridgedPassContext::mangleWithClosureArgs(
18791879
return BridgedOwnedString(mangler.mangle());
18801880
}
18811881

1882-
BridgedGlobalVar BridgedPassContext::createGlobalVariable(BridgedStringRef name, BridgedType type, bool isPrivate) const {
1883-
return {SILGlobalVariable::create(
1882+
BridgedGlobalVar BridgedPassContext::createGlobalVariable(BridgedStringRef name, BridgedType type, BridgedLinkage linkage, bool isLet) const {
1883+
auto *global = SILGlobalVariable::create(
18841884
*invocation->getPassManager()->getModule(),
1885-
isPrivate ? SILLinkage::Private : SILLinkage::Public, IsNotSerialized,
1886-
name.unbridged(), type.unbridged())};
1885+
(swift::SILLinkage)linkage, IsNotSerialized,
1886+
name.unbridged(), type.unbridged());
1887+
if (isLet)
1888+
global->setLet(true);
1889+
return {global};
18871890
}
18881891

18891892
void BridgedPassContext::fixStackNesting(BridgedFunction function) const {

test/SILOptimizer/global-functionptr.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public struct S: P {
3636
}
3737
}
3838

39-
// CHECK-SIL-LABEL: sil_global private @$s4Test8funcPtrs{{.*}}_WZTv_ : $_ContiguousArrayStorage<FuncPtr> = {
39+
// CHECK-SIL-LABEL: sil_global private [let] @$s4Test8funcPtrs{{.*}}_WZTv_ : $_ContiguousArrayStorage<FuncPtr> = {
4040
// CHECK-SIL: %{{[0-9]+}} = function_ref @$s4Test7FuncPtr{{.*}}Tg5 : $@convention(thin) () -> ()
4141
// CHECK-SIL: %initval = object $_ContiguousArrayStorage<FuncPtr> ({{%[0-9]+}} : $_ArrayBody, [tail_elems] {{%[0-9]+}} : $FuncPtr, {{%[0-9]+}} : $FuncPtr)
4242
private let funcPtrs = [

test/SILOptimizer/objectoutliner.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ sil_global [let] @g1 : $Int32 = {
2424
sil_global [let] @gobj : $Obj
2525
sil_global @gobj_var : $Obj
2626

27-
// CHECK-LABEL: sil_global private @outline_global_simpleTv_ : $Obj = {
27+
// CHECK-LABEL: sil_global private [let] @outline_global_simpleTv_ : $Obj = {
2828
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 1
2929
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
3030
// CHECK-NEXT: %initval = object $Obj (%1 : $Int64)
3131
// CHECK-NEXT: }
3232

33-
// CHECK-LABEL: sil_global private @outline_global_tailelemsTv_ : $Obj = {
33+
// CHECK-LABEL: sil_global private [let] @outline_global_tailelemsTv_ : $Obj = {
3434
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 1
3535
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
3636
// CHECK-NEXT: %2 = integer_literal $Builtin.Int64, 2
@@ -40,7 +40,7 @@ sil_global @gobj_var : $Obj
4040
// CHECK-NEXT: %initval = object $Obj (%1 : $Int64, [tail_elems] %3 : $Int64, %5 : $Int64)
4141
// CHECK-NEXT: }
4242

43-
// CHECK-LABEL: sil_global private @tuple_tailelemsTv_ : $Obj = {
43+
// CHECK-LABEL: sil_global private [let] @tuple_tailelemsTv_ : $Obj = {
4444
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 27
4545
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
4646
// CHECK-NEXT: %2 = integer_literal $Builtin.Int64, 1
@@ -58,7 +58,7 @@ sil_global @gobj_var : $Obj
5858
// CHECK-NEXT: %initval = object $Obj (%1 : $Int64, [tail_elems] %6 : $(Int64, Bool), %11 : $(Int64, Bool), %13 : $(Int64, Bool))
5959
// CHECK-NEXT: }
6060

61-
// CHECK-LABEL: sil_global private @outline_global_addressTv_ : $Obj = {
61+
// CHECK-LABEL: sil_global private [let] @outline_global_addressTv_ : $Obj = {
6262
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 1
6363
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
6464
// CHECK-NEXT: %2 = global_addr @g1 : $*Int32

test/SILOptimizer/static_arrays.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,49 +17,49 @@
1717
// CHECK-NEXT: }
1818

1919
// CHECK-LABEL: outlined variable #0 of arrayLookup(_:)
20-
// CHECK-NEXT: sil_global private @{{.*}}arrayLookup{{.*}} = {
20+
// CHECK-NEXT: sil_global private [let] @{{.*}}arrayLookup{{.*}} = {
2121
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 10
2222
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 11
2323
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 12
2424
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}}, {{[^,]*}})
2525
// CHECK-NEXT: }
2626

2727
// CHECK-LABEL: outlined variable #0 of returnArray()
28-
// CHECK-NEXT: sil_global private @{{.*}}returnArray{{.*}} = {
28+
// CHECK-NEXT: sil_global private [let] @{{.*}}returnArray{{.*}} = {
2929
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 20
3030
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 21
3131
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
3232
// CHECK-NEXT: }
3333

3434
// CHECK-LABEL: outlined variable #0 of returnStaticStringArray()
35-
// CHECK-NEXT: sil_global private @{{.*}}returnStaticStringArray{{.*}} = {
35+
// CHECK-NEXT: sil_global private [let] @{{.*}}returnStaticStringArray{{.*}} = {
3636
// CHECK-DAG: string_literal utf8 "a"
3737
// CHECK-DAG: string_literal utf8 "b"
3838
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
3939
// CHECK-NEXT: }
4040

4141
// CHECK-LABEL: outlined variable #0 of passArray()
42-
// CHECK-NEXT: sil_global private @{{.*}}passArray{{.*}} = {
42+
// CHECK-NEXT: sil_global private [let] @{{.*}}passArray{{.*}} = {
4343
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 27
4444
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 28
4545
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
4646
// CHECK-NEXT: }
4747

4848
// CHECK-LABEL: outlined variable #1 of passArray()
49-
// CHECK-NEXT: sil_global private @{{.*}}passArray{{.*}} = {
49+
// CHECK-NEXT: sil_global private [let] @{{.*}}passArray{{.*}} = {
5050
// CHECK: integer_literal $Builtin.Int{{[0-9]+}}, 29
5151
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}})
5252
// CHECK-NEXT: }
5353

5454
// CHECK-LABEL: outlined variable #0 of storeArray()
55-
// CHECK-NEXT: sil_global private @{{.*}}storeArray{{.*}} = {
55+
// CHECK-NEXT: sil_global private [let] @{{.*}}storeArray{{.*}} = {
5656
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 227
5757
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 228
5858
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems] {{[^,]*}}, {{[^,]*}})
5959
// CHECK-NEXT: }
6060

6161
// CHECK-LABEL: outlined variable #0 of functionArray()
62-
// CHECK-NEXT: sil_global private @{{.*functionArray.*}} = {
62+
// CHECK-NEXT: sil_global private [let] @{{.*functionArray.*}} = {
6363
// CHECK: function_ref
6464
// CHECK: thin_to_thick_function
6565
// CHECK: convert_function
@@ -70,7 +70,7 @@
7070
// CHECK-NEXT: }
7171

7272
// CHECK-LABEL: outlined variable #0 of returnDictionary()
73-
// CHECK-NEXT: sil_global private @{{.*}}returnDictionary{{.*}} = {
73+
// CHECK-NEXT: sil_global private [let] @{{.*}}returnDictionary{{.*}} = {
7474
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 5
7575
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 4
7676
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 2
@@ -81,11 +81,11 @@
8181
// CHECK-NEXT: }
8282

8383
// CHECK-LABEL: outlined variable #0 of returnStringDictionary()
84-
// CHECK-NEXT: sil_global private @{{.*}}returnStringDictionary{{.*}} = {
84+
// CHECK-NEXT: sil_global private [let] @{{.*}}returnStringDictionary{{.*}} = {
8585
// CHECK: object {{.*}} ({{[^,]*}}, [tail_elems]
8686
// CHECK-NEXT: }
8787

88-
// CHECK-LABEL: sil_global private @{{.*}}main{{.*}} = {
88+
// CHECK-LABEL: sil_global private [let] @{{.*}}main{{.*}} = {
8989
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 100
9090
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 101
9191
// CHECK-DAG: integer_literal $Builtin.Int{{[0-9]+}}, 102

test/SILOptimizer/static_enums.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public enum FunctionEnum {
202202
// CHECK-LABEL: sil_global hidden @$s4test2feAA12FunctionEnumOvp : $FunctionEnum = {
203203
var fe = FunctionEnum.f(printClass)
204204

205-
// CHECK-LABEL: sil_global private @$s4test9createArrSaySiSgGyFTv_ : $_ContiguousArrayStorage<Optional<Int>> = {
205+
// CHECK-LABEL: sil_global private [let] @$s4test9createArrSaySiSgGyFTv_ : $_ContiguousArrayStorage<Optional<Int>> = {
206206
@inline(never)
207207
func createArr() -> [Int?] {
208208
return [ 27, 42, nil, 103 ]

0 commit comments

Comments
 (0)