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

via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 19 00:55:04 PDT 2026


Author: Andreas Jonson
Date: 2026-07-19T09:55:00+02:00
New Revision: 8042e61d6ae99347e8cab040b324b33cabfb1d4a

URL: https://github.com/llvm/llvm-project/commit/8042e61d6ae99347e8cab040b324b33cabfb1d4a
DIFF: https://github.com/llvm/llvm-project/commit/8042e61d6ae99347e8cab040b324b33cabfb1d4a.diff

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

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
    llvm/test/Transforms/InstCombine/trunc.ll

Removed: 
    


################################################################################
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
+}


        


More information about the llvm-commits mailing list