Skip to content

Commit 89d86b6

Browse files
authored
SimplifyCFG: Enable switch replacements in more cases (#156477)
In some cases, we can replace a switch with simpler instructions or a lookup table. For instance, if every case results in the same value, we can simply replace the switch with that single value. However, lookup tables are not always supported. Targets, function attributes and compiler options can deactivate lookup table creation. Currently, even simpler switch replacements like the single value optimization do not get applied, because we only enable these transformations if lookup tables are enabled. This PR enables the other kinds of replacements, even if lookup tables are not supported. First, it checks if the potential replacements are lookup tables. If they are, then check if lookup tables are supported and whether to continue. If they are not, then we can apply the other transformations. Originally, lookup table creation was delayed until late stages of the compilation pipeline, because it can result in difficult-to-analyze code and prevent other optimizations. As a side effect of this change, we can also enable the simpler optimizations much earlier in the compilation process.
1 parent 4aa59f5 commit 89d86b6

File tree

2 files changed

+537
-8
lines changed

2 files changed

+537
-8
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6458,6 +6458,9 @@ class SwitchReplacement {
64586458
/// Return the default value of the switch.
64596459
Constant *getDefaultValue();
64606460

6461+
/// Return true if the replacement is a lookup table.
6462+
bool isLookupTable();
6463+
64616464
private:
64626465
// Depending on the switch, there are different alternatives.
64636466
enum {
@@ -6605,7 +6608,6 @@ SwitchReplacement::SwitchReplacement(
66056608
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
66066609
LinearMapValWrapped = NonMonotonic || MayWrap;
66076610
Kind = LinearMapKind;
6608-
++NumLinearMaps;
66096611
return;
66106612
}
66116613
}
@@ -6625,7 +6627,6 @@ SwitchReplacement::SwitchReplacement(
66256627
BitMap = ConstantInt::get(M.getContext(), TableInt);
66266628
BitMapElementTy = IT;
66276629
Kind = BitMapKind;
6628-
++NumBitMaps;
66296630
return;
66306631
}
66316632

@@ -6642,6 +6643,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
66426643
case SingleValueKind:
66436644
return SingleValue;
66446645
case LinearMapKind: {
6646+
++NumLinearMaps;
66456647
// Derive the result value from the input value.
66466648
Value *Result = Builder.CreateIntCast(Index, LinearMultiplier->getType(),
66476649
false, "switch.idx.cast");
@@ -6657,6 +6659,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
66576659
return Result;
66586660
}
66596661
case BitMapKind: {
6662+
++NumBitMaps;
66606663
// Type of the bitmap (e.g. i59).
66616664
IntegerType *MapTy = BitMap->getIntegerType();
66626665

@@ -6679,6 +6682,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
66796682
return Builder.CreateTrunc(DownShifted, BitMapElementTy, "switch.masked");
66806683
}
66816684
case LookupTableKind: {
6685+
++NumLookupTables;
66826686
auto *Table =
66836687
new GlobalVariable(*Func->getParent(), Initializer->getType(),
66846688
/*isConstant=*/true, GlobalVariable::PrivateLinkage,
@@ -6745,6 +6749,8 @@ static bool isTypeLegalForLookupTable(Type *Ty, const TargetTransformInfo &TTI,
67456749

67466750
Constant *SwitchReplacement::getDefaultValue() { return DefaultValue; }
67476751

6752+
bool SwitchReplacement::isLookupTable() { return Kind == LookupTableKind; }
6753+
67486754
static bool isSwitchDense(uint64_t NumCases, uint64_t CaseRange) {
67496755
// 40% is the default density for building a jump table in optsize/minsize
67506756
// mode. See also TargetLoweringBase::isSuitableForJumpTable(), which this
@@ -6915,11 +6921,6 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
69156921

69166922
BasicBlock *BB = SI->getParent();
69176923
Function *Fn = BB->getParent();
6918-
// Only build lookup table when we have a target that supports it or the
6919-
// attribute is not set.
6920-
if (!TTI.shouldBuildLookupTables() ||
6921-
(Fn->getFnAttribute("no-jump-tables").getValueAsBool()))
6922-
return false;
69236924

69246925
// FIXME: If the switch is too sparse for a lookup table, perhaps we could
69256926
// split off a dense part and build a lookup table for that.
@@ -7078,6 +7079,20 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
70787079
PhiToReplacementMap.insert({PHI, Replacement});
70797080
}
70807081

7082+
bool AnyLookupTables = any_of(
7083+
PhiToReplacementMap, [](auto &KV) { return KV.second.isLookupTable(); });
7084+
7085+
// A few conditions prevent the generation of lookup tables:
7086+
// 1. The target does not support lookup tables.
7087+
// 2. The "no-jump-tables" function attribute is set.
7088+
// However, these objections do not apply to other switch replacements, like
7089+
// the bitmap, so we only stop here if any of these conditions are met and we
7090+
// want to create a LUT. Otherwise, continue with the switch replacement.
7091+
if (AnyLookupTables &&
7092+
(!TTI.shouldBuildLookupTables() ||
7093+
Fn->getFnAttribute("no-jump-tables").getValueAsBool()))
7094+
return false;
7095+
70817096
Builder.SetInsertPoint(SI);
70827097
// TableIndex is the switch condition - TableIndexOffset if we don't
70837098
// use the condition directly
@@ -7219,7 +7234,6 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
72197234
if (DTU)
72207235
DTU->applyUpdates(Updates);
72217236

7222-
++NumLookupTables;
72237237
if (NeedMask)
72247238
++NumLookupTablesHoles;
72257239
return true;

0 commit comments

Comments
 (0)