return isSwitchDense(SI->getNumCases(), TableSize);
}
+static bool ShouldUseSwitchConditionAsTableIndex(
+ ConstantInt &MinCaseVal, const ConstantInt &MaxCaseVal,
+ bool HasDefaultResults, const SmallDenseMap<PHINode *, Type *> &ResultTypes,
+ const DataLayout &DL, const TargetTransformInfo &TTI) {
+ if (MinCaseVal.isNullValue())
+ return true;
+ if (MinCaseVal.isNegative() ||
+ MaxCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
+ !HasDefaultResults)
+ return false;
+ return all_of(ResultTypes, [&](const auto &KV) {
+ return SwitchLookupTable::WouldFitInRegister(
+ DL, MaxCaseVal.getLimitedValue() + 1 /* TableSize */,
+ KV.second /* ResultType */);
+ });
+}
+
/// Try to reuse the switch table index compare. Following pattern:
/// \code
/// if (idx < tablesize)
}
uint64_t NumResults = ResultLists[PHIs[0]].size();
- APInt RangeSpread = MaxCaseVal->getValue() - MinCaseVal->getValue();
- uint64_t TableSize = RangeSpread.getLimitedValue() + 1;
- bool TableHasHoles = (NumResults < TableSize);
// If the table has holes, we need a constant result for the default case
// or a bitmask that fits in a register.
getCaseResults(SI, nullptr, SI->getDefaultDest(), &CommonDest,
DefaultResultsList, DL, TTI);
+ for (const auto &I : DefaultResultsList) {
+ PHINode *PHI = I.first;
+ Constant *Result = I.second;
+ DefaultResults[PHI] = Result;
+ }
+
+ bool UseSwitchConditionAsTableIndex = ShouldUseSwitchConditionAsTableIndex(
+ *MinCaseVal, *MaxCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
+ uint64_t TableSize;
+ if (UseSwitchConditionAsTableIndex)
+ TableSize = MaxCaseVal->getLimitedValue() + 1;
+ else
+ TableSize =
+ (MaxCaseVal->getValue() - MinCaseVal->getValue()).getLimitedValue() + 1;
+
+ bool TableHasHoles = (NumResults < TableSize);
bool NeedMask = (TableHasHoles && !HasDefaultResults);
if (NeedMask) {
// As an extra penalty for the validity test we require more cases.
return false;
}
- for (const auto &I : DefaultResultsList) {
- PHINode *PHI = I.first;
- Constant *Result = I.second;
- DefaultResults[PHI] = Result;
- }
-
if (!ShouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes))
return false;
// Compute the table index value.
Builder.SetInsertPoint(SI);
Value *TableIndex;
- if (MinCaseVal->isNullValue())
+ ConstantInt *TableIndexOffset;
+ if (UseSwitchConditionAsTableIndex) {
+ TableIndexOffset = ConstantInt::get(MaxCaseVal->getType(), 0);
TableIndex = SI->getCondition();
- else
- TableIndex = Builder.CreateSub(SI->getCondition(), MinCaseVal,
- "switch.tableidx");
+ } else {
+ TableIndexOffset = MinCaseVal;
+ TableIndex =
+ Builder.CreateSub(SI->getCondition(), TableIndexOffset, "switch.tableidx");
+ }
// Compute the maximum table size representable by the integer type we are
// switching upon.
// Build bitmask; fill in a 1 bit for every case.
const ResultListTy &ResultList = ResultLists[PHIs[0]];
for (size_t I = 0, E = ResultList.size(); I != E; ++I) {
- uint64_t Idx = (ResultList[I].first->getValue() - MinCaseVal->getValue())
+ uint64_t Idx = (ResultList[I].first->getValue() - TableIndexOffset->getValue())
.getLimitedValue();
MaskInt |= One << Idx;
}
// If using a bitmask, use any value to fill the lookup table holes.
Constant *DV = NeedMask ? ResultLists[PHI][0].second : DefaultResults[PHI];
StringRef FuncName = Fn->getName();
- SwitchLookupTable Table(Mod, TableSize, MinCaseVal, ResultList, DV, DL,
- FuncName);
+ SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
+ DL, FuncName);
Value *Result = Table.BuildLookup(TableIndex, Builder);
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[X]], 10
; CHECK-NEXT: [[R_0:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 0
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[R_0]], 0
-; CHECK-NEXT: [[DOTR_0:%.*]] = select i1 [[INVERTED_CMP]], i32 100, i32 [[R_0]]
-; CHECK-NEXT: ret i32 [[DOTR_0]]
+; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[INVERTED_CMP]], i32 100, i32 [[R_0]]
+; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
switch i32 %x, label %sw.default [
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[X]], 10
; CHECK-NEXT: [[R_0:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 12
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[R_0]], 0
-; CHECK-NEXT: [[R_0_:%.*]] = select i1 [[CMP]], i32 [[R_0]], i32 100
-; CHECK-NEXT: ret i32 [[R_0_]]
+; CHECK-NEXT: [[RETVAL_0:%.*]] = select i1 [[CMP]], i32 [[R_0]], i32 100
+; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
switch i32 %x, label %sw.default [
}
declare i32 @__CxxFrameHandler3(...)
+
+define i1 @use_x_as_index(i32 %x) {
+; CHECK-LABEL: @use_x_as_index(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[X:%.*]], 9
+; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i32 [[X]] to i9
+; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul i9 [[SWITCH_CAST]], 1
+; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i9 -234, [[SWITCH_SHIFTAMT]]
+; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i9 [[SWITCH_DOWNSHIFT]] to i1
+; CHECK-NEXT: [[STOREMERGE:%.*]] = select i1 [[TMP0]], i1 [[SWITCH_MASKED]], i1 false
+; CHECK-NEXT: ret i1 [[STOREMERGE]]
+;
+entry:
+ switch i32 %x, label %sw.default [
+ i32 1, label %sw.bb
+ i32 2, label %sw.bb
+ i32 4, label %sw.bb
+ i32 8, label %sw.bb
+ ]
+
+sw.bb:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %storemerge = phi i1 [ true, %sw.bb ], [ false, %sw.default ]
+ ret i1 %storemerge
+}