diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5986,6 +5986,7 @@ // For LinearMapKind, these are the constants used to derive the value. ConstantInt *LinearOffset = nullptr; ConstantInt *LinearMultiplier = nullptr; + bool LinearMapValWrapped = false; // For ArrayKind, this is the array. GlobalVariable *Array = nullptr; @@ -6046,6 +6047,8 @@ bool LinearMappingPossible = true; APInt PrevVal; APInt DistToPrev; + // When linear map is monotonic, we can attach nsw. + bool Inc, Wrapped = false; assert(TableSize >= 2 && "Should be a SingleValue table."); // Check if there is the same distance between two consecutive values. for (uint64_t I = 0; I < TableSize; ++I) { @@ -6065,12 +6068,15 @@ LinearMappingPossible = false; break; } + Wrapped |= + Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal); } PrevVal = Val; } if (LinearMappingPossible) { LinearOffset = cast(TableContents[0]); LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev); + LinearMapValWrapped = Wrapped; Kind = LinearMapKind; ++NumLinearMaps; return; @@ -6119,9 +6125,14 @@ Value *Result = Builder.CreateIntCast(Index, LinearMultiplier->getType(), false, "switch.idx.cast"); if (!LinearMultiplier->isOne()) - Result = Builder.CreateMul(Result, LinearMultiplier, "switch.idx.mult"); + Result = Builder.CreateMul(Result, LinearMultiplier, "switch.idx.mult", + /*HasNUW = */ false, + /*HasNSW = */ !LinearMapValWrapped); + if (!LinearOffset->isZero()) - Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset"); + Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset", + /*HasNUW = */ false, + /*HasNSW = */ !LinearMapValWrapped); return Result; } case BitMapKind: { diff --git a/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll b/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll --- a/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll +++ b/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]] ; @@ -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: @@ -1816,8 +1816,8 @@ ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[N:%.*]] to i3 ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub nsw i3 [[TRUNC]], -2 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i3 [[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: @@ -1856,8 +1856,8 @@ ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i3 [[TRUNC]], -2 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i3 [[SWITCH_TABLEIDX]], -3 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i3 [[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: [[DOTSROA_0_0:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 0 ; CHECK-NEXT: ret i32 [[DOTSROA_0_0]] ; @@ -1901,8 +1901,8 @@ ; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i3 [[TRUNC]], -2 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i3 [[SWITCH_TABLEIDX]], -4 ; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i3 [[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: [[DOTSROA_0_0:%.*]] = select i1 [[TMP0]], i32 [[SWITCH_OFFSET]], i32 0 ; CHECK-NEXT: ret i32 [[DOTSROA_0_0]] ; @@ -1938,8 +1938,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]], 31 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i8 [[SWITCH_IDX_MULT]], 31 +; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i8 [[SWITCH_IDX_CAST]], 31 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i8 [[SWITCH_IDX_MULT]], 31 ; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP0]], i8 [[SWITCH_OFFSET]], i8 3 ; CHECK-NEXT: ret i8 [[X]] ; @@ -1992,8 +1992,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]], -32 -; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i8 [[SWITCH_IDX_MULT]], -32 +; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i8 [[SWITCH_IDX_CAST]], -32 +; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i8 [[SWITCH_IDX_MULT]], -32 ; CHECK-NEXT: [[X:%.*]] = select i1 [[TMP0]], i8 [[SWITCH_OFFSET]], i8 3 ; CHECK-NEXT: ret i8 [[X]] ;