-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[InstCombine] Infer nsw/nuw for trunc #87910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds support for inferring trunc's nsw/nuw flags. Alive2 support for these flags has landed as AliveToolkit/alive2#1024. But alive2.llvm.org hasn't updated to the trunk. So I cannot provide the proof. Patch is 154.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87910.diff 62 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 0652a8ba80b3fe..437e9b92c7032f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -897,7 +897,20 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
}
}
- return nullptr;
+ bool Changed = false;
+ if (!Trunc.hasNoSignedWrap() &&
+ ComputeMaxSignificantBits(Src, /*Depth=*/0, &Trunc) <= DestWidth) {
+ Trunc.setHasNoSignedWrap(true);
+ Changed = true;
+ }
+ if (!Trunc.hasNoUnsignedWrap() &&
+ MaskedValueIsZero(Src, APInt::getBitsSetFrom(SrcWidth, DestWidth),
+ /*Depth=*/0, &Trunc)) {
+ Trunc.setHasNoUnsignedWrap(true);
+ Changed = true;
+ }
+
+ return Changed ? &Trunc : nullptr;
}
Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp,
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
index 1afae6565fe26b..6e0acfd6851165 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
@@ -45,7 +45,7 @@ entry:
define signext i32 @vsetvl_sext() nounwind #0 {
; CHECK-LABEL: @vsetvl_sext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvli.i64(i64 1, i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvli(i64 1, i64 1, i64 1)
@@ -56,7 +56,7 @@ define signext i32 @vsetvl_sext() nounwind #0 {
define zeroext i32 @vsetvl_zext() nounwind #0 {
; CHECK-LABEL: @vsetvl_zext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvli.i64(i64 1, i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvli(i64 1, i64 1, i64 1)
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
index 093ba75e87b5a7..811a29c7e56248 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
@@ -45,7 +45,7 @@ entry:
define signext i32 @vsetvlmax_sext() nounwind #0 {
; CHECK-LABEL: @vsetvlmax_sext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvlimax.i64(i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvlimax(i64 1, i64 1)
@@ -56,7 +56,7 @@ define signext i32 @vsetvlmax_sext() nounwind #0 {
define zeroext i32 @vsetvlmax_zext() nounwind #0 {
; CHECK-LABEL: @vsetvlmax_zext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvlimax.i64(i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvlimax(i64 1, i64 1)
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index ec3aca26514caf..23eee8547597e4 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -2375,7 +2375,7 @@ define { i64, i64 } @PR57576(i64 noundef %x, i64 noundef %y, i64 noundef %z, i64
; CHECK-NEXT: [[SUB:%.*]] = sub i128 [[XY]], [[ZZ]]
; CHECK-NEXT: [[T:%.*]] = trunc i128 [[SUB]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = lshr i128 [[SUB]], 64
-; CHECK-NEXT: [[DOTTR:%.*]] = trunc i128 [[TMP1]] to i64
+; CHECK-NEXT: [[DOTTR:%.*]] = trunc nuw i128 [[TMP1]] to i64
; CHECK-NEXT: [[DOTNARROW:%.*]] = sub i64 [[DOTTR]], [[W:%.*]]
; CHECK-NEXT: [[R1:%.*]] = insertvalue { i64, i64 } poison, i64 [[T]], 0
; CHECK-NEXT: [[R2:%.*]] = insertvalue { i64, i64 } [[R1]], i64 [[DOTNARROW]], 1
diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
index cd9ec1e59203ff..d72a54e8babc9f 100644
--- a/llvm/test/Transforms/InstCombine/binop-itofp.ll
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -1010,7 +1010,7 @@ define float @test_ui_add_with_signed_constant(i32 %shr.i) {
define float @missed_nonzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @missed_nonzero_check_on_constant_for_si_fmul(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp i16 [[CONV_I]] to float
; CHECK-NEXT: [[MUL3_I_I:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[CONV1_I]])
; CHECK-NEXT: store i32 [[SEL]], ptr [[G_2345:%.*]], align 4
@@ -1027,7 +1027,7 @@ define float @missed_nonzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g
define <2 x float> @missed_nonzero_check_on_constant_for_si_fmul_vec(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @missed_nonzero_check_on_constant_for_si_fmul_vec(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1048,7 +1048,7 @@ define <2 x float> @missed_nonzero_check_on_constant_for_si_fmul_vec(i1 %c, i1 %
define float @negzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @negzero_check_on_constant_for_si_fmul(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp i16 [[CONV_I]] to float
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[CONV1_I]]
; CHECK-NEXT: [[MUL3_I_I:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
@@ -1066,7 +1066,7 @@ define float @negzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345)
define <2 x float> @nonzero_check_on_constant_for_si_fmul_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1087,7 +1087,7 @@ define <2 x float> @nonzero_check_on_constant_for_si_fmul_vec_w_undef(i1 %c, i1
define <2 x float> @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1108,7 +1108,7 @@ define <2 x float> @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(i1 %c,
define <2 x float> @nonzero_check_on_constant_for_si_fmul_negz_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_negz_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
diff --git a/llvm/test/Transforms/InstCombine/bswap-fold.ll b/llvm/test/Transforms/InstCombine/bswap-fold.ll
index 05933d37057cce..19522168beaf5e 100644
--- a/llvm/test/Transforms/InstCombine/bswap-fold.ll
+++ b/llvm/test/Transforms/InstCombine/bswap-fold.ll
@@ -211,7 +211,7 @@ define i64 @variable_shl_not_masked_enough_i64(i64 %x, i64 %n) {
define i16 @test7(i32 %A) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[A:%.*]], 16
-; CHECK-NEXT: [[D:%.*]] = trunc i32 [[TMP1]] to i16
+; CHECK-NEXT: [[D:%.*]] = trunc nuw i32 [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[D]]
;
%B = tail call i32 @llvm.bswap.i32(i32 %A) nounwind
@@ -223,7 +223,7 @@ define i16 @test7(i32 %A) {
define <2 x i16> @test7_vector(<2 x i32> %A) {
; CHECK-LABEL: @test7_vector(
; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i32> [[A:%.*]], <i32 16, i32 16>
-; CHECK-NEXT: [[D:%.*]] = trunc <2 x i32> [[TMP1]] to <2 x i16>
+; CHECK-NEXT: [[D:%.*]] = trunc nuw <2 x i32> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[D]]
;
%B = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %A) nounwind
@@ -235,7 +235,7 @@ define <2 x i16> @test7_vector(<2 x i32> %A) {
define i16 @test8(i64 %A) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[A:%.*]], 48
-; CHECK-NEXT: [[D:%.*]] = trunc i64 [[TMP1]] to i16
+; CHECK-NEXT: [[D:%.*]] = trunc nuw i64 [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[D]]
;
%B = tail call i64 @llvm.bswap.i64(i64 %A) nounwind
@@ -247,7 +247,7 @@ define i16 @test8(i64 %A) {
define <2 x i16> @test8_vector(<2 x i64> %A) {
; CHECK-LABEL: @test8_vector(
; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i64> [[A:%.*]], <i64 48, i64 48>
-; CHECK-NEXT: [[D:%.*]] = trunc <2 x i64> [[TMP1]] to <2 x i16>
+; CHECK-NEXT: [[D:%.*]] = trunc nuw <2 x i64> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[D]]
;
%B = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %A) nounwind
diff --git a/llvm/test/Transforms/InstCombine/bswap.ll b/llvm/test/Transforms/InstCombine/bswap.ll
index 21eb170b8c58d3..d42583bb5699b7 100644
--- a/llvm/test/Transforms/InstCombine/bswap.ll
+++ b/llvm/test/Transforms/InstCombine/bswap.ll
@@ -43,7 +43,7 @@ define i16 @test1_trunc(i32 %i) {
; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[I]], 8
; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 65280
; CHECK-NEXT: [[T5:%.*]] = or disjoint i32 [[T1]], [[T4]]
-; CHECK-NEXT: [[T13:%.*]] = trunc i32 [[T5]] to i16
+; CHECK-NEXT: [[T13:%.*]] = trunc nuw i32 [[T5]] to i16
; CHECK-NEXT: ret i16 [[T13]]
;
%t1 = lshr i32 %i, 24
@@ -61,7 +61,7 @@ define i16 @test1_trunc_extra_use(i32 %i) {
; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 65280
; CHECK-NEXT: [[T5:%.*]] = or disjoint i32 [[T1]], [[T4]]
; CHECK-NEXT: call void @extra_use(i32 [[T5]])
-; CHECK-NEXT: [[T13:%.*]] = trunc i32 [[T5]] to i16
+; CHECK-NEXT: [[T13:%.*]] = trunc nuw i32 [[T5]] to i16
; CHECK-NEXT: ret i16 [[T13]]
;
%t1 = lshr i32 %i, 24
diff --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll
index 97554e9462043c..d9c93ba277295c 100644
--- a/llvm/test/Transforms/InstCombine/cast.ll
+++ b/llvm/test/Transforms/InstCombine/cast.ll
@@ -1471,7 +1471,7 @@ define i64 @test91(i64 %A) {
; ALL-LABEL: @test91(
; ALL-NEXT: [[B:%.*]] = sext i64 [[A:%.*]] to i96
; ALL-NEXT: [[C:%.*]] = lshr i96 [[B]], 48
-; ALL-NEXT: [[D:%.*]] = trunc i96 [[C]] to i64
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i96 [[C]] to i64
; ALL-NEXT: ret i64 [[D]]
;
%B = sext i64 %A to i96
@@ -1676,7 +1676,7 @@ define i8 @trunc_lshr_overshift_sext_uses3(i8 %A) {
define i8 @trunc_lshr_sext_wide_input(i16 %A) {
; ALL-LABEL: @trunc_lshr_sext_wide_input(
; ALL-NEXT: [[TMP1:%.*]] = ashr i16 [[A:%.*]], 9
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1688,7 +1688,7 @@ define i8 @trunc_lshr_sext_wide_input(i16 %A) {
define i8 @trunc_lshr_sext_wide_input_exact(i16 %A) {
; ALL-LABEL: @trunc_lshr_sext_wide_input_exact(
; ALL-NEXT: [[TMP1:%.*]] = ashr exact i16 [[A:%.*]], 9
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1702,7 +1702,7 @@ define <2 x i8> @trunc_lshr_sext_wide_input_uses1(<2 x i16> %A) {
; ALL-NEXT: [[B:%.*]] = sext <2 x i16> [[A:%.*]] to <2 x i32>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[B]])
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A]], <i16 9, i16 9>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1747,7 +1747,7 @@ define <2 x i8> @trunc_lshr_sext_wide_input_uses3(<2 x i16> %A) {
define <2 x i8> @trunc_lshr_overshift_wide_input_sext(<2 x i16> %A) {
; ALL-LABEL: @trunc_lshr_overshift_wide_input_sext(
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A:%.*]], <i16 15, i16 15>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1761,7 +1761,7 @@ define i8 @trunc_lshr_overshift_sext_wide_input_uses1(i16 %A) {
; ALL-NEXT: [[B:%.*]] = sext i16 [[A:%.*]] to i32
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[TMP1:%.*]] = ashr i16 [[A]], 15
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1776,7 +1776,7 @@ define <2 x i8> @trunc_lshr_overshift_sext_wide_input_uses2(<2 x i16> %A) {
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A:%.*]], <i16 15, i16 15>
; ALL-NEXT: [[C:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1925,7 +1925,7 @@ define <2 x i8> @trunc_lshr_overshift2_sext(<2 x i8> %A) {
; ALL-LABEL: @trunc_lshr_overshift2_sext(
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 25, i32 25>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
@@ -1939,7 +1939,7 @@ define i8 @trunc_lshr_overshift2_sext_uses1(i8 %A) {
; ALL-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i32
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 25
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i32 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32
@@ -1954,7 +1954,7 @@ define <2 x i8> @trunc_lshr_overshift2_sext_uses2(<2 x i8> %A) {
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 25, i32 25>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
@@ -1970,7 +1970,7 @@ define i8 @trunc_lshr_overshift2_sext_uses3(i8 %A) {
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 25
; ALL-NEXT: call void @use_i32(i32 [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i32 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32
@@ -2018,7 +2018,7 @@ define <2 x i8> @trunc_lshr_zext_uniform_undef(<2 x i8> %A) {
; ALL-LABEL: @trunc_lshr_zext_uniform_undef(
; ALL-NEXT: [[B:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 undef>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = zext <2 x i8> %A to <2 x i32>
@@ -2042,7 +2042,7 @@ define <3 x i8> @trunc_lshr_zext_nonuniform_undef(<3 x i8> %A) {
; ALL-LABEL: @trunc_lshr_zext_nonuniform_undef(
; ALL-NEXT: [[B:%.*]] = zext <3 x i8> [[A:%.*]] to <3 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <3 x i32> [[B]], <i32 6, i32 2, i32 undef>
-; ALL-NEXT: [[D:%.*]] = trunc <3 x i32> [[C]] to <3 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw <3 x i32> [[C]] to <3 x i8>
; ALL-NEXT: ret <3 x i8> [[D]]
;
%B = zext <3 x i8> %A to <3 x i32>
@@ -2095,7 +2095,7 @@ define i4 @pr33078_3(i8 %A) {
; ALL-LABEL: @pr33078_3(
; ALL-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i16
; ALL-NEXT: [[C:%.*]] = lshr i16 [[B]], 12
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[C]] to i4
+; ALL-NEXT: [[D:%.*]] = trunc nuw i16 [[C]] to i4
; ALL-NEXT: ret i4 [[D]]
;
%B = sext i8 %A to i16
@@ -2109,7 +2109,7 @@ define i8 @pr33078_4(i3 %x) {
; ALL-LABEL: @pr33078_4(
; ALL-NEXT: [[B:%.*]] = sext i3 [[X:%.*]] to i16
; ALL-NEXT: [[C:%.*]] = lshr i16 [[B]], 13
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i16 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i3 %x to i16
diff --git a/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll b/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
index 5955650167c21a..66cbb2636cbc2b 100644
--- a/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
@@ -618,7 +618,7 @@ define i1 @trunc_cttz_false_ult_other_i32_i6(i32 %x) {
define i1 @trunc_cttz_false_ult_other_i32_i6_extra_use(i32 %x) {
; CHECK-LABEL: @trunc_cttz_false_ult_other_i32_i6_extra_use(
; CHECK-NEXT: [[TZ:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false), !range [[RNG0]]
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[TZ]] to i6
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 [[TZ]] to i6
; CHECK-NEXT: call void @use6(i6 [[TRUNC]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i6 [[TRUNC]], 7
; CHECK-NEXT: ret i1 [[CMP]]
@@ -720,7 +720,7 @@ define i1 @trunc_ctlz_false_ugt_other_i32_i6(i32 %x) {
define i1 @trunc_ctlz_false_ugt_other_i32_i6_extra_use(i32 %x) {
; CHECK-LABEL: @trunc_ctlz_false_ugt_other_i32_i6_extra_use(
; CHECK-NEXT: [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range [[RNG0]]
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[LZ]] to i6
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 [[LZ]] to i6
; CHECK-NEXT: call void @use6(i6 [[TRUNC]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i6 [[TRUNC]], 4
; CHECK-NEXT: ret i1 [[CMP]]
diff --git a/llvm/test/Transforms/InstCombine/compare-signs.ll b/llvm/test/Transforms/InstCombine/compare-signs.ll
index d7aa710e1ef03c..3730d46d5f0f4b 100644
--- a/llvm/test/Transforms/InstCombine/compare-signs.ll
+++ b/llvm/test/Transforms/InstCombine/compare-signs.ll
@@ -223,7 +223,7 @@ define <2 x i1> @shift_trunc_signbit_test_vec_uses(<2 x i17> %x, ptr %p1, ptr %p
; CHECK-LABEL: @shift_trunc_signbit_test_vec_uses(
; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i17> [[X:%.*]], <i17 4, i17 4>
; CHECK-NEXT: store <2 x i17> [[SH]], ptr [[P1:%.*]], align 8
-; CHECK-NEXT: [[TR:%.*]] = trunc <2 x i17> [[SH]] to <2 x i13>
+; CHECK-NEXT: [[TR:%.*]] = trunc nuw <2 x i17> [[SH]] to <2 x i13>
...
[truncated]
|
@llvm/pr-subscribers-backend-risc-v Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds support for inferring trunc's nsw/nuw flags. Alive2 support for these flags has landed as AliveToolkit/alive2#1024. But alive2.llvm.org hasn't updated to the trunk. So I cannot provide the proof. Patch is 154.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87910.diff 62 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 0652a8ba80b3fe..437e9b92c7032f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -897,7 +897,20 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
}
}
- return nullptr;
+ bool Changed = false;
+ if (!Trunc.hasNoSignedWrap() &&
+ ComputeMaxSignificantBits(Src, /*Depth=*/0, &Trunc) <= DestWidth) {
+ Trunc.setHasNoSignedWrap(true);
+ Changed = true;
+ }
+ if (!Trunc.hasNoUnsignedWrap() &&
+ MaskedValueIsZero(Src, APInt::getBitsSetFrom(SrcWidth, DestWidth),
+ /*Depth=*/0, &Trunc)) {
+ Trunc.setHasNoUnsignedWrap(true);
+ Changed = true;
+ }
+
+ return Changed ? &Trunc : nullptr;
}
Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp,
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
index 1afae6565fe26b..6e0acfd6851165 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvli-knownbits.ll
@@ -45,7 +45,7 @@ entry:
define signext i32 @vsetvl_sext() nounwind #0 {
; CHECK-LABEL: @vsetvl_sext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvli.i64(i64 1, i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvli(i64 1, i64 1, i64 1)
@@ -56,7 +56,7 @@ define signext i32 @vsetvl_sext() nounwind #0 {
define zeroext i32 @vsetvl_zext() nounwind #0 {
; CHECK-LABEL: @vsetvl_zext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvli.i64(i64 1, i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvli(i64 1, i64 1, i64 1)
diff --git a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
index 093ba75e87b5a7..811a29c7e56248 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/riscv-vsetvlimax-knownbits.ll
@@ -45,7 +45,7 @@ entry:
define signext i32 @vsetvlmax_sext() nounwind #0 {
; CHECK-LABEL: @vsetvlmax_sext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvlimax.i64(i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvlimax(i64 1, i64 1)
@@ -56,7 +56,7 @@ define signext i32 @vsetvlmax_sext() nounwind #0 {
define zeroext i32 @vsetvlmax_zext() nounwind #0 {
; CHECK-LABEL: @vsetvlmax_zext(
; CHECK-NEXT: [[A:%.*]] = call i64 @llvm.riscv.vsetvlimax.i64(i64 1, i64 1)
-; CHECK-NEXT: [[B:%.*]] = trunc i64 [[A]] to i32
+; CHECK-NEXT: [[B:%.*]] = trunc nuw nsw i64 [[A]] to i32
; CHECK-NEXT: ret i32 [[B]]
;
%a = call i64 @llvm.riscv.vsetvlimax(i64 1, i64 1)
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index ec3aca26514caf..23eee8547597e4 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -2375,7 +2375,7 @@ define { i64, i64 } @PR57576(i64 noundef %x, i64 noundef %y, i64 noundef %z, i64
; CHECK-NEXT: [[SUB:%.*]] = sub i128 [[XY]], [[ZZ]]
; CHECK-NEXT: [[T:%.*]] = trunc i128 [[SUB]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = lshr i128 [[SUB]], 64
-; CHECK-NEXT: [[DOTTR:%.*]] = trunc i128 [[TMP1]] to i64
+; CHECK-NEXT: [[DOTTR:%.*]] = trunc nuw i128 [[TMP1]] to i64
; CHECK-NEXT: [[DOTNARROW:%.*]] = sub i64 [[DOTTR]], [[W:%.*]]
; CHECK-NEXT: [[R1:%.*]] = insertvalue { i64, i64 } poison, i64 [[T]], 0
; CHECK-NEXT: [[R2:%.*]] = insertvalue { i64, i64 } [[R1]], i64 [[DOTNARROW]], 1
diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
index cd9ec1e59203ff..d72a54e8babc9f 100644
--- a/llvm/test/Transforms/InstCombine/binop-itofp.ll
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -1010,7 +1010,7 @@ define float @test_ui_add_with_signed_constant(i32 %shr.i) {
define float @missed_nonzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @missed_nonzero_check_on_constant_for_si_fmul(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp i16 [[CONV_I]] to float
; CHECK-NEXT: [[MUL3_I_I:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[CONV1_I]])
; CHECK-NEXT: store i32 [[SEL]], ptr [[G_2345:%.*]], align 4
@@ -1027,7 +1027,7 @@ define float @missed_nonzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g
define <2 x float> @missed_nonzero_check_on_constant_for_si_fmul_vec(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @missed_nonzero_check_on_constant_for_si_fmul_vec(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1048,7 +1048,7 @@ define <2 x float> @missed_nonzero_check_on_constant_for_si_fmul_vec(i1 %c, i1 %
define float @negzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @negzero_check_on_constant_for_si_fmul(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp i16 [[CONV_I]] to float
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[CONV1_I]]
; CHECK-NEXT: [[MUL3_I_I:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[TMP1]])
@@ -1066,7 +1066,7 @@ define float @negzero_check_on_constant_for_si_fmul(i1 %c, i1 %.b, ptr %g_2345)
define <2 x float> @nonzero_check_on_constant_for_si_fmul_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1087,7 +1087,7 @@ define <2 x float> @nonzero_check_on_constant_for_si_fmul_vec_w_undef(i1 %c, i1
define <2 x float> @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
@@ -1108,7 +1108,7 @@ define <2 x float> @nonzero_check_on_constant_for_si_fmul_nz_vec_w_undef(i1 %c,
define <2 x float> @nonzero_check_on_constant_for_si_fmul_negz_vec_w_undef(i1 %c, i1 %.b, ptr %g_2345) {
; CHECK-LABEL: @nonzero_check_on_constant_for_si_fmul_negz_vec_w_undef(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i32 65529, i32 53264
-; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc i32 [[SEL]] to i16
+; CHECK-NEXT: [[CONV_I_S:%.*]] = trunc nuw i32 [[SEL]] to i16
; CHECK-NEXT: [[CONV_I_V:%.*]] = insertelement <2 x i16> poison, i16 [[CONV_I_S]], i64 0
; CHECK-NEXT: [[CONV_I:%.*]] = shufflevector <2 x i16> [[CONV_I_V]], <2 x i16> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[CONV1_I:%.*]] = sitofp <2 x i16> [[CONV_I]] to <2 x float>
diff --git a/llvm/test/Transforms/InstCombine/bswap-fold.ll b/llvm/test/Transforms/InstCombine/bswap-fold.ll
index 05933d37057cce..19522168beaf5e 100644
--- a/llvm/test/Transforms/InstCombine/bswap-fold.ll
+++ b/llvm/test/Transforms/InstCombine/bswap-fold.ll
@@ -211,7 +211,7 @@ define i64 @variable_shl_not_masked_enough_i64(i64 %x, i64 %n) {
define i16 @test7(i32 %A) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[A:%.*]], 16
-; CHECK-NEXT: [[D:%.*]] = trunc i32 [[TMP1]] to i16
+; CHECK-NEXT: [[D:%.*]] = trunc nuw i32 [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[D]]
;
%B = tail call i32 @llvm.bswap.i32(i32 %A) nounwind
@@ -223,7 +223,7 @@ define i16 @test7(i32 %A) {
define <2 x i16> @test7_vector(<2 x i32> %A) {
; CHECK-LABEL: @test7_vector(
; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i32> [[A:%.*]], <i32 16, i32 16>
-; CHECK-NEXT: [[D:%.*]] = trunc <2 x i32> [[TMP1]] to <2 x i16>
+; CHECK-NEXT: [[D:%.*]] = trunc nuw <2 x i32> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[D]]
;
%B = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %A) nounwind
@@ -235,7 +235,7 @@ define <2 x i16> @test7_vector(<2 x i32> %A) {
define i16 @test8(i64 %A) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[A:%.*]], 48
-; CHECK-NEXT: [[D:%.*]] = trunc i64 [[TMP1]] to i16
+; CHECK-NEXT: [[D:%.*]] = trunc nuw i64 [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[D]]
;
%B = tail call i64 @llvm.bswap.i64(i64 %A) nounwind
@@ -247,7 +247,7 @@ define i16 @test8(i64 %A) {
define <2 x i16> @test8_vector(<2 x i64> %A) {
; CHECK-LABEL: @test8_vector(
; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i64> [[A:%.*]], <i64 48, i64 48>
-; CHECK-NEXT: [[D:%.*]] = trunc <2 x i64> [[TMP1]] to <2 x i16>
+; CHECK-NEXT: [[D:%.*]] = trunc nuw <2 x i64> [[TMP1]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[D]]
;
%B = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %A) nounwind
diff --git a/llvm/test/Transforms/InstCombine/bswap.ll b/llvm/test/Transforms/InstCombine/bswap.ll
index 21eb170b8c58d3..d42583bb5699b7 100644
--- a/llvm/test/Transforms/InstCombine/bswap.ll
+++ b/llvm/test/Transforms/InstCombine/bswap.ll
@@ -43,7 +43,7 @@ define i16 @test1_trunc(i32 %i) {
; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[I]], 8
; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 65280
; CHECK-NEXT: [[T5:%.*]] = or disjoint i32 [[T1]], [[T4]]
-; CHECK-NEXT: [[T13:%.*]] = trunc i32 [[T5]] to i16
+; CHECK-NEXT: [[T13:%.*]] = trunc nuw i32 [[T5]] to i16
; CHECK-NEXT: ret i16 [[T13]]
;
%t1 = lshr i32 %i, 24
@@ -61,7 +61,7 @@ define i16 @test1_trunc_extra_use(i32 %i) {
; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 65280
; CHECK-NEXT: [[T5:%.*]] = or disjoint i32 [[T1]], [[T4]]
; CHECK-NEXT: call void @extra_use(i32 [[T5]])
-; CHECK-NEXT: [[T13:%.*]] = trunc i32 [[T5]] to i16
+; CHECK-NEXT: [[T13:%.*]] = trunc nuw i32 [[T5]] to i16
; CHECK-NEXT: ret i16 [[T13]]
;
%t1 = lshr i32 %i, 24
diff --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll
index 97554e9462043c..d9c93ba277295c 100644
--- a/llvm/test/Transforms/InstCombine/cast.ll
+++ b/llvm/test/Transforms/InstCombine/cast.ll
@@ -1471,7 +1471,7 @@ define i64 @test91(i64 %A) {
; ALL-LABEL: @test91(
; ALL-NEXT: [[B:%.*]] = sext i64 [[A:%.*]] to i96
; ALL-NEXT: [[C:%.*]] = lshr i96 [[B]], 48
-; ALL-NEXT: [[D:%.*]] = trunc i96 [[C]] to i64
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i96 [[C]] to i64
; ALL-NEXT: ret i64 [[D]]
;
%B = sext i64 %A to i96
@@ -1676,7 +1676,7 @@ define i8 @trunc_lshr_overshift_sext_uses3(i8 %A) {
define i8 @trunc_lshr_sext_wide_input(i16 %A) {
; ALL-LABEL: @trunc_lshr_sext_wide_input(
; ALL-NEXT: [[TMP1:%.*]] = ashr i16 [[A:%.*]], 9
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1688,7 +1688,7 @@ define i8 @trunc_lshr_sext_wide_input(i16 %A) {
define i8 @trunc_lshr_sext_wide_input_exact(i16 %A) {
; ALL-LABEL: @trunc_lshr_sext_wide_input_exact(
; ALL-NEXT: [[TMP1:%.*]] = ashr exact i16 [[A:%.*]], 9
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1702,7 +1702,7 @@ define <2 x i8> @trunc_lshr_sext_wide_input_uses1(<2 x i16> %A) {
; ALL-NEXT: [[B:%.*]] = sext <2 x i16> [[A:%.*]] to <2 x i32>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[B]])
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A]], <i16 9, i16 9>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1747,7 +1747,7 @@ define <2 x i8> @trunc_lshr_sext_wide_input_uses3(<2 x i16> %A) {
define <2 x i8> @trunc_lshr_overshift_wide_input_sext(<2 x i16> %A) {
; ALL-LABEL: @trunc_lshr_overshift_wide_input_sext(
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A:%.*]], <i16 15, i16 15>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1761,7 +1761,7 @@ define i8 @trunc_lshr_overshift_sext_wide_input_uses1(i16 %A) {
; ALL-NEXT: [[B:%.*]] = sext i16 [[A:%.*]] to i32
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[TMP1:%.*]] = ashr i16 [[A]], 15
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[TMP1]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nsw i16 [[TMP1]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i16 %A to i32
@@ -1776,7 +1776,7 @@ define <2 x i8> @trunc_lshr_overshift_sext_wide_input_uses2(<2 x i16> %A) {
; ALL-NEXT: [[TMP1:%.*]] = ashr <2 x i16> [[A:%.*]], <i16 15, i16 15>
; ALL-NEXT: [[C:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i16> [[TMP1]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nsw <2 x i16> [[TMP1]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i16> %A to <2 x i32>
@@ -1925,7 +1925,7 @@ define <2 x i8> @trunc_lshr_overshift2_sext(<2 x i8> %A) {
; ALL-LABEL: @trunc_lshr_overshift2_sext(
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 25, i32 25>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
@@ -1939,7 +1939,7 @@ define i8 @trunc_lshr_overshift2_sext_uses1(i8 %A) {
; ALL-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i32
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 25
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i32 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32
@@ -1954,7 +1954,7 @@ define <2 x i8> @trunc_lshr_overshift2_sext_uses2(<2 x i8> %A) {
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 25, i32 25>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
@@ -1970,7 +1970,7 @@ define i8 @trunc_lshr_overshift2_sext_uses3(i8 %A) {
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 25
; ALL-NEXT: call void @use_i32(i32 [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i32 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32
@@ -2018,7 +2018,7 @@ define <2 x i8> @trunc_lshr_zext_uniform_undef(<2 x i8> %A) {
; ALL-LABEL: @trunc_lshr_zext_uniform_undef(
; ALL-NEXT: [[B:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 undef>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw <2 x i32> [[C]] to <2 x i8>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = zext <2 x i8> %A to <2 x i32>
@@ -2042,7 +2042,7 @@ define <3 x i8> @trunc_lshr_zext_nonuniform_undef(<3 x i8> %A) {
; ALL-LABEL: @trunc_lshr_zext_nonuniform_undef(
; ALL-NEXT: [[B:%.*]] = zext <3 x i8> [[A:%.*]] to <3 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <3 x i32> [[B]], <i32 6, i32 2, i32 undef>
-; ALL-NEXT: [[D:%.*]] = trunc <3 x i32> [[C]] to <3 x i8>
+; ALL-NEXT: [[D:%.*]] = trunc nuw <3 x i32> [[C]] to <3 x i8>
; ALL-NEXT: ret <3 x i8> [[D]]
;
%B = zext <3 x i8> %A to <3 x i32>
@@ -2095,7 +2095,7 @@ define i4 @pr33078_3(i8 %A) {
; ALL-LABEL: @pr33078_3(
; ALL-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i16
; ALL-NEXT: [[C:%.*]] = lshr i16 [[B]], 12
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[C]] to i4
+; ALL-NEXT: [[D:%.*]] = trunc nuw i16 [[C]] to i4
; ALL-NEXT: ret i4 [[D]]
;
%B = sext i8 %A to i16
@@ -2109,7 +2109,7 @@ define i8 @pr33078_4(i3 %x) {
; ALL-LABEL: @pr33078_4(
; ALL-NEXT: [[B:%.*]] = sext i3 [[X:%.*]] to i16
; ALL-NEXT: [[C:%.*]] = lshr i16 [[B]], 13
-; ALL-NEXT: [[D:%.*]] = trunc i16 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = trunc nuw nsw i16 [[C]] to i8
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i3 %x to i16
diff --git a/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll b/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
index 5955650167c21a..66cbb2636cbc2b 100644
--- a/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/cmp-intrinsic.ll
@@ -618,7 +618,7 @@ define i1 @trunc_cttz_false_ult_other_i32_i6(i32 %x) {
define i1 @trunc_cttz_false_ult_other_i32_i6_extra_use(i32 %x) {
; CHECK-LABEL: @trunc_cttz_false_ult_other_i32_i6_extra_use(
; CHECK-NEXT: [[TZ:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false), !range [[RNG0]]
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[TZ]] to i6
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 [[TZ]] to i6
; CHECK-NEXT: call void @use6(i6 [[TRUNC]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i6 [[TRUNC]], 7
; CHECK-NEXT: ret i1 [[CMP]]
@@ -720,7 +720,7 @@ define i1 @trunc_ctlz_false_ugt_other_i32_i6(i32 %x) {
define i1 @trunc_ctlz_false_ugt_other_i32_i6_extra_use(i32 %x) {
; CHECK-LABEL: @trunc_ctlz_false_ugt_other_i32_i6_extra_use(
; CHECK-NEXT: [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range [[RNG0]]
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 [[LZ]] to i6
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 [[LZ]] to i6
; CHECK-NEXT: call void @use6(i6 [[TRUNC]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i6 [[TRUNC]], 4
; CHECK-NEXT: ret i1 [[CMP]]
diff --git a/llvm/test/Transforms/InstCombine/compare-signs.ll b/llvm/test/Transforms/InstCombine/compare-signs.ll
index d7aa710e1ef03c..3730d46d5f0f4b 100644
--- a/llvm/test/Transforms/InstCombine/compare-signs.ll
+++ b/llvm/test/Transforms/InstCombine/compare-signs.ll
@@ -223,7 +223,7 @@ define <2 x i1> @shift_trunc_signbit_test_vec_uses(<2 x i17> %x, ptr %p1, ptr %p
; CHECK-LABEL: @shift_trunc_signbit_test_vec_uses(
; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i17> [[X:%.*]], <i17 4, i17 4>
; CHECK-NEXT: store <2 x i17> [[SH]], ptr [[P1:%.*]], align 8
-; CHECK-NEXT: [[TR:%.*]] = trunc <2 x i17> [[SH]] to <2 x i13>
+; CHECK-NEXT: [[TR:%.*]] = trunc nuw <2 x i17> [[SH]] to <2 x i13>
...
[truncated]
|
/*Depth=*/0, &Trunc)) { | ||
Trunc.setHasNoUnsignedWrap(true); | ||
Changed = true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From an efficiency POV, I think you should probably startout with a computeKnownBits
on src and see if you get lucky about leading ones / zeros. Then if you don't, do a call to computeMaxSignificantBits
.
Not an issue now but I think we should look into updating Guess same is true for |
LGTM. |
MaskedValueIsZero(Src, APInt::getBitsSetFrom(SrcWidth, DestWidth), | ||
/*Depth=*/0, &Trunc)) { | ||
Trunc.setHasNoUnsignedWrap(true); | ||
Changed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we infer this in SimplifyDemanded instead, where we already have the KnownBits of the trunc arg?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot infer nsw flags from KnownBits (e.g., trunc (ashr i64 X, 32) to i32
). BTW we never set poison-generating flags in SimplifyDemanded
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't infer nsw, but we can infer nuw. Do you see any reason why doing this in SimplifyDemanded would be problematic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't infer nsw, but we can infer nuw.
I prefer to infer both flags here, then we may reuse KnownBits in further patches.
Do you see any reason why doing this in SimplifyDemanded would be problematic?
SimplifyDemanded
is context-sensitive. IMO it is not the right place to infer flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping @nikic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I won't insist on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
MaskedValueIsZero(Src, APInt::getBitsSetFrom(SrcWidth, DestWidth), | ||
/*Depth=*/0, &Trunc)) { | ||
Trunc.setHasNoUnsignedWrap(true); | ||
Changed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I won't insist on this.
llvm/llvm-project#87910 infers `nuw` and `nsw` on some `trunc` instructions we're doing `FileCheck` on. Tolerate but don't require them to support both release and head LLVM.
llvm/llvm-project#87910 infers `nuw` and `nsw` on some `trunc` instructions we're doing `FileCheck` on. Tolerate but don't require them to support both release and head LLVM.
codegen tests: Tolerate `nuw` `nsw` on `trunc` llvm/llvm-project#87910 infers `nuw` and `nsw` on some `trunc` instructions we're doing `FileCheck` on. Tolerate but don't require them to support both release and head LLVM. `@rustbot` label: +llvm-main cc `@durin42`
Rollup merge of rust-lang#123808 - maurer:nuw-nsw-trunc, r=durin42 codegen tests: Tolerate `nuw` `nsw` on `trunc` llvm/llvm-project#87910 infers `nuw` and `nsw` on some `trunc` instructions we're doing `FileCheck` on. Tolerate but don't require them to support both release and head LLVM. `@rustbot` label: +llvm-main cc `@durin42`
This patch adds support for inferring trunc's nsw/nuw flags.
Alive2 support for these flags has landed as AliveToolkit/alive2#1024. But alive2.llvm.org hasn't updated to the trunk. So I cannot provide the proof.