Skip to content

Commit f0ea9c9

Browse files
committed
CodeGenPrepare: Replace constant PHI arguments with switch condition value
We often see code like the following after running SCCP: switch (x) { case 42: phi(42, ...); } This tends to produce bad code as we currently materialize the constant phi-argument in the switch-block. This increases register pressure and if the pattern repeats for `n` case statements, we end up generating `n` constant values. This changes CodeGenPrepare to catch this pattern and revert it back to: switch (x) { case 42: phi(x, ...); } Differential Revision: https://reviews.llvm.org/D124552
1 parent cd19af7 commit f0ea9c9

File tree

5 files changed

+322
-149
lines changed

5 files changed

+322
-149
lines changed

llvm/lib/CodeGen/CodeGenPrepare.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ class TypePromotionTransaction;
399399
bool optimizeFunnelShift(IntrinsicInst *Fsh);
400400
bool optimizeSelectInst(SelectInst *SI);
401401
bool optimizeShuffleVectorInst(ShuffleVectorInst *SVI);
402+
bool optimizeSwitchType(SwitchInst *SI);
403+
bool optimizeSwitchPhiConstants(SwitchInst *SI);
402404
bool optimizeSwitchInst(SwitchInst *SI);
403405
bool optimizeExtractElementInst(Instruction *Inst);
404406
bool dupRetToEnableTailCallOpts(BasicBlock *BB, bool &ModifiedDT);
@@ -6979,7 +6981,7 @@ bool CodeGenPrepare::tryToSinkFreeOperands(Instruction *I) {
69796981
return Changed;
69806982
}
69816983

6982-
bool CodeGenPrepare::optimizeSwitchInst(SwitchInst *SI) {
6984+
bool CodeGenPrepare::optimizeSwitchType(SwitchInst *SI) {
69836985
Value *Cond = SI->getCondition();
69846986
Type *OldType = Cond->getType();
69856987
LLVMContext &Context = Cond->getContext();
@@ -7028,6 +7030,60 @@ bool CodeGenPrepare::optimizeSwitchInst(SwitchInst *SI) {
70287030
return true;
70297031
}
70307032

7033+
bool CodeGenPrepare::optimizeSwitchPhiConstants(SwitchInst *SI) {
7034+
// The SCCP optimization tends to produce code like this:
7035+
// switch(x) { case 42: phi(42, ...) }
7036+
// Materializing the constant for the phi-argument needs instructions; So we
7037+
// change the code to:
7038+
// switch(x) { case 42: phi(x, ...) }
7039+
7040+
bool Changed = false;
7041+
BasicBlock *SwitchBB = SI->getParent();
7042+
Value *Condition = SI->getCondition();
7043+
Type *ConditionType = Condition->getType();
7044+
7045+
for (const SwitchInst::CaseHandle &Case : SI->cases()) {
7046+
ConstantInt *CaseValue = Case.getCaseValue();
7047+
BasicBlock *CaseBB = Case.getCaseSuccessor();
7048+
// Set to true if we previously checked that `CaseBB` is only reached by
7049+
// a single case from this switch.
7050+
bool CheckedForSinglePred = false;
7051+
for (PHINode &PHI : CaseBB->phis()) {
7052+
Type *PHIType = PHI.getType();
7053+
if (PHIType == ConditionType) {
7054+
// Set to true to skip this case because of multiple preds.
7055+
bool SkipCase = false;
7056+
for (unsigned I = 0, E = PHI.getNumIncomingValues(); I != E; I++) {
7057+
if (PHI.getIncomingValue(I) != CaseValue ||
7058+
PHI.getIncomingBlock(I) != SwitchBB)
7059+
continue;
7060+
// We cannot optimize if there are multiple case labels jumping to
7061+
// this block. This check may get expensive when there are many
7062+
// case labels so we test for it last.
7063+
if (!CheckedForSinglePred) {
7064+
CheckedForSinglePred = true;
7065+
if (SI->findCaseDest(CaseBB) == nullptr) {
7066+
SkipCase = true;
7067+
break;
7068+
}
7069+
}
7070+
7071+
PHI.setIncomingValue(I, Condition);
7072+
Changed = true;
7073+
}
7074+
if (SkipCase)
7075+
break;
7076+
}
7077+
}
7078+
}
7079+
return Changed;
7080+
}
7081+
7082+
bool CodeGenPrepare::optimizeSwitchInst(SwitchInst *SI) {
7083+
bool Changed = optimizeSwitchType(SI);
7084+
Changed |= optimizeSwitchPhiConstants(SI);
7085+
return Changed;
7086+
}
70317087

70327088
namespace {
70337089

0 commit comments

Comments
 (0)