Skip to content

Commit 5e2f3d8

Browse files
author
Joe Shajrawi
committed
[LICM]: support hosting ref_element_addr even if they are not guaranteed to be executed
In some instances, some instructions, like ref_element_addr, can be hoisted outside of loops even if they are not guaranteed to be executed. We currently don’t support that / bail. We only try to do so / do further analysis only for begin_access because they are extremely heavy. However, we need to support hosting of ref_element_addr in that case, if it does not have a loop dependent operand, in order to be able to hoist begin_access instructions in some benchmarks. Initial local testing shows that this PR, when we enable exclusivity, improves the performance of a certain internal benchmark by over 40% See rdar://problem/43623829
1 parent 809764f commit 5e2f3d8

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

lib/SILOptimizer/LoopTransforms/LICM.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -332,20 +332,23 @@ hoistSpecialInstruction(std::unique_ptr<LoopNestSummary> &LoopSummary,
332332
bool Changed = false;
333333

334334
for (auto *Inst : Special) {
335-
auto *BI = dyn_cast<BeginAccessInst>(Inst);
336-
assert(BI && "Only BeginAccessInst are supported");
337-
SmallVector<EndAccessInst *, 2> Ends;
338-
getEndAccesses(BI, Ends);
339-
if (!hoistInstruction(DT, BI, Loop, Preheader)) {
335+
if (!hoistInstruction(DT, Inst, Loop, Preheader)) {
340336
continue;
341337
}
342-
LLVM_DEBUG(llvm::dbgs() << "Hoisted " << *BI);
343-
for (auto *instSink : Ends) {
344-
if (!sinkInstruction(DT, LoopSummary, instSink, LI)) {
345-
llvm_unreachable("LICM: Could not perform must-sink instruction");
338+
if (auto *BI = dyn_cast<BeginAccessInst>(Inst)) {
339+
SmallVector<EndAccessInst *, 2> Ends;
340+
getEndAccesses(BI, Ends);
341+
LLVM_DEBUG(llvm::dbgs() << "Hoisted BeginAccess " << *BI);
342+
for (auto *instSink : Ends) {
343+
if (!sinkInstruction(DT, LoopSummary, instSink, LI)) {
344+
llvm_unreachable("LICM: Could not perform must-sink instruction");
345+
}
346346
}
347+
LLVM_DEBUG(llvm::errs() << " Successfully hosited and sank pair\n");
348+
} else {
349+
auto *REA = static_cast<RefElementAddrInst *>(Inst);
350+
LLVM_DEBUG(llvm::dbgs() << "Hoisted RefElementAddr " << *REA);
347351
}
348-
LLVM_DEBUG(llvm::errs() << " Successfully hosited and sank pair\n");
349352
Changed = true;
350353
}
351354

@@ -615,6 +618,11 @@ void LoopTreeOptimization::analyzeCurrentLoop(
615618
checkSideEffects(Inst, MayWrites);
616619
break;
617620
}
621+
case SILInstructionKind::RefElementAddrInst: {
622+
auto *REA = static_cast<RefElementAddrInst *>(&Inst);
623+
SpecialHoist.insert(REA);
624+
break;
625+
}
618626
case swift::SILInstructionKind::CondFailInst: {
619627
// We can (and must) hoist cond_fail instructions if the operand is
620628
// invariant. We must hoist them so that we preserve memory safety. A

test/SILOptimizer/licm.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,35 @@ bb3:
319319
dealloc_stack %0 : $*Builtin.Int32
320320
return %9999 : $()
321321
}
322+
323+
class RefElemClass {
324+
var x : Int32
325+
326+
init()
327+
}
328+
329+
// Check hoisting of ref_element_addr in conditional control flow (for exclusivity)
330+
//
331+
// CHECK-LABEL: sil @hoist_ref_elem
332+
// CHECK: bb0(%0 : $RefElemClass):
333+
// CHECK-NEXT: ref_element_addr %0 : $RefElemClass, #RefElemClass.x
334+
// CHECK-NEXT: br bb1
335+
sil @hoist_ref_elem : $@convention(thin) (RefElemClass) -> () {
336+
bb0(%0 : $RefElemClass):
337+
br bb1
338+
339+
// loop.
340+
bb1:
341+
cond_br undef, bb2, bb3
342+
343+
bb2:
344+
cond_br undef, bb4, bb1
345+
346+
bb3:
347+
%x = ref_element_addr %0 : $RefElemClass, #RefElemClass.x
348+
br bb1
349+
350+
bb4:
351+
%10 = tuple ()
352+
return %10 : $()
353+
}

0 commit comments

Comments
 (0)