Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5942,7 +5942,7 @@ /// Build instructions with Builder to retrieve the value at /// the position given by Index in the lookup table. - Value *BuildLookup(Value *Index, IRBuilder<> &Builder); + Value *BuildLookup(Value *Index, IRBuilder<> &Builder, APInt &MaxIndex); /// Return true if a table with TableSize elements of /// type ElementType would fit in a target-legal register. @@ -6106,7 +6106,7 @@ Kind = ArrayKind; } -Value *SwitchLookupTable::BuildLookup(Value *Index, IRBuilder<> &Builder) { +Value *SwitchLookupTable::BuildLookup(Value *Index, IRBuilder<> &Builder, APInt &MaxIndex) { switch (Kind) { case SingleValueKind: return SingleValue; @@ -6114,10 +6114,18 @@ // Derive the result value from the input value. Value *Result = Builder.CreateIntCast(Index, LinearMultiplier->getType(), false, "switch.idx.cast"); + // Check whether signed wrap needed. + bool MulSW, AddSW; + // TODO: cast BitWidth by cleaner way + MaxIndex = APInt(LinearMultiplier->getBitWidth(), MaxIndex.getZExtValue()); + LinearOffset->getValue().sadd_ov( + LinearMultiplier->getValue().smul_ov(MaxIndex, MulSW), AddSW); if (!LinearMultiplier->isOne()) - Result = Builder.CreateMul(Result, LinearMultiplier, "switch.idx.mult"); + Result = Builder.CreateMul(Result, LinearMultiplier, "switch.idx.mult", + /*HasNUW = */ false, /*HasNSW = */ !MulSW); if (!LinearOffset->isZero()) - Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset"); + Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset", + /*HasNUW = */ false, /*HasNSW = */ !AddSW); return Result; } case BitMapKind: { @@ -6497,20 +6505,22 @@ Builder.SetInsertPoint(SI); Value *TableIndex; ConstantInt *TableIndexOffset; + APInt MaxIndex(MaxCaseVal->getBitWidth(), 0); if (UseSwitchConditionAsTableIndex) { TableIndexOffset = ConstantInt::get(MaxCaseVal->getType(), 0); TableIndex = SI->getCondition(); + MaxIndex = MaxCaseVal->getValue(); } else { TableIndexOffset = MinCaseVal; // If the default is unreachable, all case values are s>= MinCaseVal. Then // we can try to attach nsw. bool CanBeWrapped = true; if (!DefaultIsReachable) - MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), CanBeWrapped); - + MaxIndex = + MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), CanBeWrapped); TableIndex = Builder.CreateSub(SI->getCondition(), TableIndexOffset, "switch.tableidx", /*HasNUW =*/false, - /*HasNSW =*/!CanBeWrapped); + /*HasNSW =*/!(CanBeWrapped || DefaultIsReachable)); } BranchInst *RangeCheckBranch = nullptr; @@ -6591,7 +6601,7 @@ SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV, DL, FuncName); - Value *Result = Table.BuildLookup(TableIndex, Builder); + Value *Result = Table.BuildLookup(TableIndex, Builder, MaxIndex); // Do a small peephole optimization: re-use the switch table compare if // possible. Index: llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll +++ llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll @@ -1223,8 +1223,8 @@ ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 10 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[SWITCH_TABLEIDX]] to i8 -; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul i8 [[SWITCH_IDX_CAST]], -5 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i8 [[SWITCH_IDX_MULT]], 18 +; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i8 [[SWITCH_IDX_CAST]], -5 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i8 [[SWITCH_IDX_MULT]], 18 ; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP0]], i8 [[SWITCH_OFFSET]], i8 3 ; CHECK-NEXT: ret i8 [[X]] ; @@ -1251,7 +1251,7 @@ ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[C:%.*]], -13 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 4 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i8 [[SWITCH_TABLEIDX]] to i32 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[SWITCH_IDX_CAST]], 18 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i32 [[SWITCH_IDX_CAST]], 18 ; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 3 ; CHECK-NEXT: ret i32 [[X]] ; @@ -1278,7 +1278,7 @@ ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i32 [[C:%.*]], 10 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SWITCH_TABLEIDX]], 4 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = trunc i32 [[SWITCH_TABLEIDX]] to i8 -; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul i8 [[SWITCH_IDX_CAST]], 100 +; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i8 [[SWITCH_IDX_CAST]], 100 ; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP0]], i8 [[SWITCH_IDX_MULT]], i8 3 ; CHECK-NEXT: ret i8 [[X]] ; @@ -1330,7 +1330,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[X:%.*]], 4 ; CHECK-NEXT: [[INVERTED_CMP:%.*]] = xor i1 [[TMP0]], true -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[X]], 10 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw 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: [[RETVAL_0:%.*]] = select i1 [[INVERTED_CMP]], i32 100, i32 [[R_0]] @@ -1398,7 +1398,7 @@ ; CHECK-LABEL: @no_reuse_cmp( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[X:%.*]], 4 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[X]], 10 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw 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: [[RETVAL_0:%.*]] = select i1 [[CMP]], i32 [[R_0]], i32 100 @@ -1434,7 +1434,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[EC:%.*]] = icmp ne i32 [[Y:%.*]], 0 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[X:%.*]], 4 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[X]], 10 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i32 [[X]], 10 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 0 ; CHECK-NEXT: [[R_0:%.*]] = select i1 [[EC]], i32 [[SPEC_SELECT]], i32 100 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[R_0]], 0 @@ -1778,8 +1778,8 @@ ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[N:%.*]] to i2 ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i2 [[TRUNC]], -2 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[SWITCH_TABLEIDX]] to i32 -; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul i32 [[SWITCH_IDX_CAST]], 1111 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[SWITCH_IDX_MULT]], 1111 +; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i32 [[SWITCH_IDX_CAST]], 1111 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i32 [[SWITCH_IDX_MULT]], 1111 ; CHECK-NEXT: ret i32 [[SWITCH_OFFSET]] ; start: