Skip to content

Commit 898cdc0

Browse files
authored
Merge pull request #36439 from eeckstein/lookup-table-opt
Remove unnecessary retain/release/initialization overhead from lookup table Arrays.
2 parents 91be112 + c62b452 commit 898cdc0

File tree

5 files changed

+103
-14
lines changed

5 files changed

+103
-14
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,6 +2634,23 @@ void IRGenSILFunction::visitGlobalAddrInst(GlobalAddrInst *i) {
26342634
setLoweredAddress(i, addr);
26352635
}
26362636

2637+
/// Returns true if \p val has no other uses than ref_element_addr or
2638+
/// ref_tail_addr.
2639+
static bool hasOnlyProjections(SILValue val) {
2640+
for (Operand *use : val->getUses()) {
2641+
SILInstruction *user = use->getUser();
2642+
if (auto *upCast = dyn_cast<UpcastInst>(user)) {
2643+
if (!hasOnlyProjections(upCast))
2644+
return false;
2645+
continue;
2646+
}
2647+
if (isa<RefElementAddrInst>(user) || isa<RefTailAddrInst>(user))
2648+
continue;
2649+
return false;
2650+
}
2651+
return true;
2652+
}
2653+
26372654
void IRGenSILFunction::visitGlobalValueInst(GlobalValueInst *i) {
26382655
SILGlobalVariable *var = i->getReferencedGlobal();
26392656
assert(var->isInitializedObject() &&
@@ -2645,17 +2662,19 @@ void IRGenSILFunction::visitGlobalValueInst(GlobalValueInst *i) {
26452662

26462663
llvm::Value *Ref = IGM.getAddrOfSILGlobalVariable(var, ti,
26472664
NotForDefinition).getAddress();
2648-
2649-
auto ClassType = loweredTy.getASTType();
2650-
llvm::Value *Metadata =
2651-
emitClassHeapMetadataRef(*this, ClassType, MetadataValueType::TypeMetadata,
2652-
MetadataState::Complete);
2653-
llvm::Value *CastAddr = Builder.CreateBitCast(Ref, IGM.RefCountedPtrTy);
2654-
llvm::Value *InitRef = emitInitStaticObjectCall(Metadata, CastAddr, "staticref");
2655-
InitRef = Builder.CreateBitCast(InitRef, Ref->getType());
2656-
2665+
// We don't need to initialize the global object if it's never used for
2666+
// something which can access the object header.
2667+
if (!hasOnlyProjections(i)) {
2668+
auto ClassType = loweredTy.getASTType();
2669+
llvm::Value *Metadata =
2670+
emitClassHeapMetadataRef(*this, ClassType, MetadataValueType::TypeMetadata,
2671+
MetadataState::Complete);
2672+
llvm::Value *CastAddr = Builder.CreateBitCast(Ref, IGM.RefCountedPtrTy);
2673+
llvm::Value *InitRef = emitInitStaticObjectCall(Metadata, CastAddr, "staticref");
2674+
Ref = Builder.CreateBitCast(InitRef, Ref->getType());
2675+
}
26572676
Explosion e;
2658-
e.add(InitRef);
2677+
e.add(Ref);
26592678
setLoweredExplosion(i, e);
26602679
}
26612680

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ class SILCombiner :
301301

302302
SILInstruction *visitMarkDependenceInst(MarkDependenceInst *MDI);
303303
SILInstruction *visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *CBOI);
304+
SILInstruction *visitGlobalValueInst(GlobalValueInst *globalValue);
304305
SILInstruction *visitConvertFunctionInst(ConvertFunctionInst *CFI);
305306
SILInstruction *
306307
visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *Cvt);

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,3 +2283,40 @@ SILCombiner::visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *cboi) {
22832283

22842284
return nullptr;
22852285
}
2286+
2287+
/// Returns true if reference counting and debug_value users of a global_value
2288+
/// can be deleted.
2289+
static bool checkGlobalValueUsers(SILValue val,
2290+
SmallVectorImpl<SILInstruction *> &toDelete) {
2291+
for (Operand *use : val->getUses()) {
2292+
SILInstruction *user = use->getUser();
2293+
if (isa<RefCountingInst>(user) || isa<DebugValueInst>(user)) {
2294+
toDelete.push_back(user);
2295+
continue;
2296+
}
2297+
if (auto *upCast = dyn_cast<UpcastInst>(user)) {
2298+
if (!checkGlobalValueUsers(upCast, toDelete))
2299+
return false;
2300+
continue;
2301+
}
2302+
// Projection instructions don't access the object header, so they don't
2303+
// prevent deleting reference counting instructions.
2304+
if (isa<RefElementAddrInst>(user) || isa<RefTailAddrInst>(user))
2305+
continue;
2306+
return false;
2307+
}
2308+
return true;
2309+
}
2310+
2311+
SILInstruction *
2312+
SILCombiner::visitGlobalValueInst(GlobalValueInst *globalValue) {
2313+
// Delete all reference count instructions on a global_value if the only other
2314+
// users are projections (ref_element_addr and ref_tail_addr).
2315+
SmallVector<SILInstruction *, 8> toDelete;
2316+
if (!checkGlobalValueUsers(globalValue, toDelete))
2317+
return nullptr;
2318+
for (SILInstruction *inst : toDelete) {
2319+
eraseInstFromFunction(*inst);
2320+
}
2321+
return nullptr;
2322+
}

test/SILOptimizer/sil_combine.sil

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4203,4 +4203,26 @@ bb1(%result : $Builtin.NativeObject):
42034203

42044204
bb2(%error : $Error):
42054205
unreachable
4206-
}
4206+
}
4207+
4208+
sil_global private @outlined_global : $_ContiguousArrayStorage<Int>
4209+
4210+
// CHECK-LABEL: sil @test_global_value
4211+
// CHECK-NOT: retain
4212+
// CHECK-NOT: release
4213+
// CHECK-NOT: debug_value
4214+
// CHECK: } // end sil function 'test_global_value'
4215+
sil @test_global_value : $@convention(thin) () -> Int {
4216+
bb0:
4217+
%0 = global_value @outlined_global : $_ContiguousArrayStorage<Int>
4218+
strong_retain %0 : $_ContiguousArrayStorage<Int>
4219+
debug_value %0 : $_ContiguousArrayStorage<Int>, let, name "x"
4220+
%2 = upcast %0 : $_ContiguousArrayStorage<Int> to $__ContiguousArrayStorageBase
4221+
strong_retain %2 : $__ContiguousArrayStorageBase
4222+
%13 = ref_tail_addr [immutable] %2 : $__ContiguousArrayStorageBase, $Int
4223+
%16 = load %13 : $*Int
4224+
strong_release %2 : $__ContiguousArrayStorageBase
4225+
strong_release %0 : $_ContiguousArrayStorage<Int>
4226+
return %16 : $Int
4227+
} // end sil function 'test_global_value'
4228+

test/SILOptimizer/static_arrays.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-sil | %FileCheck %s
2+
// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -Xllvm -sil-disable-pass=FunctionSignatureOpts -module-name=test -emit-ir | %FileCheck %s -check-prefix=CHECK-LLVM
23

34
// Also do an end-to-end test to check all components, including IRGen.
45
// RUN: %empty-directory(%t)
@@ -98,9 +99,18 @@
9899
// CHECK: return
99100
public let globalVariable = [ 100, 101, 102 ]
100101

101-
// CHECK-LABEL: sil {{.*}}arrayLookup{{.*}} : $@convention(thin) (Int) -> Int {
102-
// CHECK: global_value @{{.*}}arrayLookup{{.*}}
103-
// CHECK: return
102+
// CHECK-LABEL: sil [noinline] @$s4test11arrayLookupyS2iF
103+
// CHECK: global_value @$s4test11arrayLookupyS2iFTv_
104+
// CHECK-NOT: retain
105+
// CHECK-NOT: release
106+
// CHECK: } // end sil function '$s4test11arrayLookupyS2iF'
107+
108+
// CHECK-LLVM-LABEL: define {{.*}} @"$s4test11arrayLookupyS2iF"
109+
// CHECK-LLVM-NOT: call
110+
// CHECK-LLVM: [[E:%[0-9]+]] = getelementptr {{.*}} @"$s4test11arrayLookupyS2iFTv_"
111+
// CHECK-LLVM-NEXT: [[L:%[0-9]+]] = load {{.*}} [[E]]
112+
// CHECK-LLVM-NEXT: ret {{.*}} [[L]]
113+
// CHECK-LLVM: }
104114
@inline(never)
105115
public func arrayLookup(_ i: Int) -> Int {
106116
let lookupTable = [10, 11, 12]

0 commit comments

Comments
 (0)