[LICM] Code Hygiene - rip out sinkCondFail

Removing this optimization from SIL: It is not worth the extra code complexity and compilation time.

More in-depth explanation for the reasoning behind my decision:
1) What is being done there is obviously not LICM (more below) - even if it is useful it should be its own separate optimization
2) The regression that caused us to add this code is no longer there in most cases - 10% in only one specific corner-case
3) Even if the regression was still there, this is an extremely specific code pattern that we are pattern-matching against. Said pattern would be hard to find in any real code.

There is a small code snippet in rdar://17451529 that caused us to add this optimization. Looking at it now we see that the only difference is in loop1 example -

The only difference in SIL level is in loop 1:
  %295 = tuple_extract %294 : $(Builtin.Int64, Builtin.Int1), 0
  %296 = tuple_extract %294 : $(Builtin.Int64, Builtin.Int1), 1
  cond_fail %296 : $Builtin.Int1
  %298 = struct $Int (%295 : $Builtin.Int64)
  store %298 to %6 : $*Int
  %300 = builtin "cmp_eq_Int64"(%292 : $Builtin.Int64, %16 : $Builtin.Int64) : $Builtin.Int1
  cond_br %300, bb1, bb12

The cond_fail instruction in said loop is moved below the store instruction / above the builtin.

Looking at the resulting IR. And how LLVM optimizes it. It is almost the same.

If we look at the assembly code being executed then, before removing this optimization, we have:
LBB0_11:
	testq	%rcx, %rcx
	je	LBB0_2
	decq	%rcx
	incq	%rax
	movq	%rax, _$S4main4sum1Sivp(%rip)
	jno	LBB0_11

After removing it we have:
LBB0_11:
	incq	%rax
	testq	%rcx, %rcx
	je	LBB0_2
	decq	%rcx
	movq	%rax, %rdx
	incq	%rdx
	jno	LBB0_11

There is no extra load/movq which was mentioned the radar.
This commit is contained in:
Joe Shajrawi
2018-06-01 16:04:17 -07:00
parent 1ba541554a
commit 19a6bb5bdb
2 changed files with 0 additions and 139 deletions

View File

@@ -125,81 +125,6 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L) {
});
}
/// Check if an address does not depend on other values in a basic block.
static SILInstruction *addressIndependent(SILValue Addr) {
Addr = stripCasts(Addr);
if (auto *SGAI = dyn_cast<GlobalAddrInst>(Addr))
return SGAI;
if (auto *SEAI = dyn_cast<StructElementAddrInst>(Addr))
return addressIndependent(SEAI->getOperand());
return nullptr;
}
/// Check if two addresses can potentially access the same memory.
/// For now, return true when both can be traced to the same global variable.
static bool addressCanPairUp(SILValue Addr1, SILValue Addr2) {
SILInstruction *Origin1 = addressIndependent(Addr1);
return Origin1 && Origin1 == addressIndependent(Addr2);
}
/// Move cond_fail down if it can potentially help register promotion later.
static bool sinkCondFail(SILLoop *Loop) {
// Only handle innermost loops for now.
if (!Loop->getSubLoops().empty())
return false;
bool Changed = false;
for (auto *BB : Loop->getBlocks()) {
// A list of CondFails that can be moved down.
SmallVector<CondFailInst*, 4> CFs;
// A pair of load and store that are independent of the CondFails and
// can potentially access the same memory.
LoadInst *LIOfPair = nullptr;
bool foundPair = false;
for (auto &Inst : *BB) {
if (foundPair) {
// Move CFs to right before Inst.
for (unsigned I = 0, E = CFs.size(); I < E; I++) {
DEBUG(llvm::dbgs() << "sinking cond_fail down ");
DEBUG(CFs[I]->dump());
DEBUG(llvm::dbgs() << " before ");
DEBUG(Inst.dump());
CFs[I]->moveBefore(&Inst);
}
Changed = true;
foundPair = false;
LIOfPair = nullptr;
}
if (auto CF = dyn_cast<CondFailInst>(&Inst)) {
CFs.push_back(CF);
} else if (auto LI = dyn_cast<LoadInst>(&Inst)) {
if (addressIndependent(LI->getOperand())) {
LIOfPair = LI;
} else {
CFs.clear();
LIOfPair = nullptr;
}
} else if (auto SI = dyn_cast<StoreInst>(&Inst)) {
if (addressIndependent(SI->getDest())) {
if (LIOfPair &&
addressCanPairUp(SI->getDest(), LIOfPair->getOperand()))
foundPair = true;
} else {
CFs.clear();
LIOfPair = nullptr;
}
} else if (Inst.mayHaveSideEffects()) {
CFs.clear();
LIOfPair = nullptr;
}
}
}
return Changed;
}
/// Checks if \p Inst has no side effects which prevent hoisting.
/// The \a SafeReads set contain instructions which we already proved to have
/// no such side effects.
@@ -517,7 +442,6 @@ void LoopTreeOptimization::analyzeCurrentLoop(
void LoopTreeOptimization::optimizeLoop(SILLoop *CurrentLoop,
ReadSet &SafeReads) {
Changed |= sinkCondFail(CurrentLoop);
Changed |= hoistInstructions(CurrentLoop, DomTree, SafeReads,
RunsOnHighLevelSil);
Changed |= sinkFixLifetime(CurrentLoop, DomTree, LoopInfo);