[llvm] [InstCombine] Fold trunc nuw/nsw (shl exact %x, %y) to i1 -> icmp ne %x, 0 (PR #210499)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 18 03:26:35 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Andreas Jonson (andjo403)

<details>
<summary>Changes</summary>

Regression found from https://github.com/llvm/llvm-project/pull/184182

Proof: https://alive2.llvm.org/ce/z/de6gru

---
Full diff: https://github.com/llvm/llvm-project/pull/210499.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp (+5-1) 
- (modified) llvm/test/Transforms/InstCombine/trunc.ll (+108) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index ebfb796b070ae..2db6396b9d661 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1088,6 +1088,11 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
       }
     }
   }
+  Value *X;
+  if (DestWidth == 1 &&
+      (Trunc.hasNoUnsignedWrap() || Trunc.hasNoSignedWrap()) &&
+      match(Src, m_Exact(m_Shr(m_Value(X), m_Value()))))
+    return new ICmpInst(ICmpInst::ICMP_NE, X, Constant::getNullValue(SrcTy));
 
   // See if we can simplify any instructions used by the input whose sole
   // purpose is to compute bits we don't care about.
@@ -1097,7 +1102,6 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
   if (DestWidth == 1) {
     Value *Zero = Constant::getNullValue(SrcTy);
 
-    Value *X;
     const APInt *C1;
     Constant *C2;
     if (match(Src, m_OneUse(m_Shr(m_Shl(m_Power2(C1), m_Value(X)),
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 29aff222dbd87..507a4678a7a1f 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1354,3 +1354,111 @@ define i8 @neg_trunc_nuw_i8_trunc_nuw_i16(i32 %x) {
   %e = trunc nuw i16 %c to i8
   ret i8 %e
 }
+
+define i1 @trunc_nuw_lshr_exact(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nuw_lshr_exact(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %lshr = lshr exact i8 %x, %c
+  %ret = trunc nuw i8 %lshr to i1
+  ret i1 %ret
+}
+
+define i1 @trunc_nsw_lshr_exact(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nsw_lshr_exact(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %lshr = lshr exact i8 %x, %c
+  %ret = trunc nsw i8 %lshr to i1
+  ret i1 %ret
+}
+
+define i1 @trunc_nuw_ashr_exact(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nuw_ashr_exact(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %ashr = ashr exact i8 %x, %c
+  %ret = trunc nuw i8 %ashr to i1
+  ret i1 %ret
+}
+
+define i1 @trunc_nsw_ashr_exact(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nsw_ashr_exact(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %ashr = ashr exact i8 %x, %c
+  %ret = trunc nsw i8 %ashr to i1
+  ret i1 %ret
+}
+
+define i1 @trunc_nuw_lshr_exact_use(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nuw_lshr_exact_use(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr exact i8 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    call void @use.i8(i8 [[LSHR]])
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %lshr = lshr exact i8 %x, %c
+  call void @use.i8(i8 %lshr)
+  %ret = trunc nuw i8 %lshr to i1
+  ret i1 %ret
+}
+
+define i1 @trunc_nuw_ashr_exact_use(i8 %x, i8 %c) {
+; CHECK-LABEL: @trunc_nuw_ashr_exact_use(
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr exact i8 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    call void @use.i8(i8 [[ASHR]])
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[X]], 0
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %ashr = ashr exact i8 %x, %c
+  call void @use.i8(i8 %ashr)
+  %ret = trunc nuw i8 %ashr to i1
+  ret i1 %ret
+}
+
+define <2 x i1> @trunc_nuw_lshr_icmp_vec(<2 x i8> %x, <2 x i8> %c) {
+; CHECK-LABEL: @trunc_nuw_lshr_icmp_vec(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %lshr = lshr exact <2 x i8> %x, %c
+  %ret = trunc nuw <2 x i8> %lshr to <2 x i1>
+  ret <2 x i1> %ret
+}
+
+define <2 x i1> @trunc_nuw_ashr_icmp_vec(<2 x i8> %x, <2 x i8> %c) {
+; CHECK-LABEL: @trunc_nuw_ashr_icmp_vec(
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %ashr = ashr exact <2 x i8> %x, %c
+  %ret = trunc nuw <2 x i8> %ashr to <2 x i1>
+  ret <2 x i1> %ret
+}
+
+define i1 @neg_trunc_lshr_exact(i8 %x, i8 %c) {
+; CHECK-LABEL: @neg_trunc_lshr_exact(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr exact i8 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = trunc i8 [[LSHR]] to i1
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %lshr = lshr exact i8 %x, %c
+  %ret = trunc i8 %lshr to i1
+  ret i1 %ret
+}
+
+define i1 @neg_trunc_nuw_lshr(i8 %x, i8 %c) {
+; CHECK-LABEL: @neg_trunc_nuw_lshr(
+; CHECK-NEXT:    [[LSHR:%.*]] = lshr i8 [[X:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[RET:%.*]] = trunc nuw i8 [[LSHR]] to i1
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %lshr = lshr i8 %x, %c
+  %ret = trunc nuw i8 %lshr to i1
+  ret i1 %ret
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/210499


More information about the llvm-commits mailing list