[llvm] 4e0dd00 - [InstCombine] Combine trunc (lshr X, BW-1) to i1 --> icmp slt X, 0 (#142593) (#143846)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 16 00:46:56 PDT 2025
Author: mayanksolanki393
Date: 2025-06-16T09:46:52+02:00
New Revision: 4e0dd007ac6a7b7e0a284062b61c6d22250337df
URL: https://github.com/llvm/llvm-project/commit/4e0dd007ac6a7b7e0a284062b61c6d22250337df
DIFF: https://github.com/llvm/llvm-project/commit/4e0dd007ac6a7b7e0a284062b61c6d22250337df.diff
LOG: [InstCombine] Combine trunc (lshr X, BW-1) to i1 --> icmp slt X, 0 (#142593) (#143846)
Fixes #142593, the issue was fixed using the suggestion on the ticket
itself.
Godbolt: https://godbolt.org/z/oW5b74jc4
alive2 proof: https://alive2.llvm.org/ce/z/QHnD7e
Added:
llvm/test/Transforms/InstCombine/trunc-lshr.ll
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
llvm/test/Transforms/InstCombine/logical-select.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index d4a2fe5e37ef5..033ef8be700eb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -815,6 +815,12 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
return new ICmpInst(ICmpInst::ICMP_EQ, X, CmpC);
}
+ if (match(Src, m_Shr(m_Value(X), m_SpecificInt(SrcWidth - 1)))) {
+ // trunc (ashr X, BW-1) to i1 --> icmp slt X, 0
+ // trunc (lshr X, BW-1) to i1 --> icmp slt X, 0
+ return new ICmpInst(ICmpInst::ICMP_SLT, X, Zero);
+ }
+
Constant *C;
if (match(Src, m_OneUse(m_LShr(m_Value(X), m_ImmConstant(C))))) {
// trunc (lshr X, C) to i1 --> icmp ne (and X, C'), 0
diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll
index 050a53406a9c5..87e05002665ce 100644
--- a/llvm/test/Transforms/InstCombine/logical-select.ll
+++ b/llvm/test/Transforms/InstCombine/logical-select.ll
@@ -807,9 +807,9 @@ define <2 x i16> @bitcast_vec_cond_commute3(<4 x i8> %cond, <2 x i16> %pc, <2 x
; CHECK-LABEL: @bitcast_vec_cond_commute3(
; CHECK-NEXT: [[C:%.*]] = mul <2 x i16> [[PC:%.*]], [[PC]]
; CHECK-NEXT: [[D:%.*]] = mul <2 x i16> [[PD:%.*]], [[PD]]
+; CHECK-NEXT: [[DOTNOT2:%.*]] = icmp slt <4 x i8> [[COND:%.*]], zeroinitializer
; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i16> [[D]] to <4 x i8>
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i16> [[C]] to <4 x i8>
-; CHECK-NEXT: [[DOTNOT2:%.*]] = icmp slt <4 x i8> [[COND:%.*]], zeroinitializer
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[DOTNOT2]], <4 x i8> [[TMP1]], <4 x i8> [[TMP2]]
; CHECK-NEXT: [[R:%.*]] = bitcast <4 x i8> [[TMP3]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[R]]
@@ -1069,8 +1069,8 @@ define <2 x i1> @not_d_bools_vector_poison(<2 x i1> %c, <2 x i1> %x, <2 x i1> %y
define i32 @not_d_allSignBits(i32 %cond, i32 %tval, i32 %fval) {
; CHECK-LABEL: @not_d_allSignBits(
-; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[FVAL:%.*]], -1
; CHECK-NEXT: [[DOTNOT2:%.*]] = icmp slt i32 [[COND:%.*]], 0
+; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[FVAL:%.*]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[DOTNOT2]], i32 [[TVAL:%.*]], i32 [[TMP1]]
; CHECK-NEXT: ret i32 [[SEL]]
;
diff --git a/llvm/test/Transforms/InstCombine/trunc-lshr.ll b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
new file mode 100644
index 0000000000000..4364b09cfa709
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
@@ -0,0 +1,95 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define i1 @test1(i32 %i, ptr %p) {
+; CHECK-LABEL: define i1 @test1(
+; CHECK-SAME: i32 [[I:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT: [[DOTLOBIT:%.*]] = lshr i32 [[I]], 31
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[P]], align 1
+; CHECK-NEXT: ret i1 false
+;
+ %lobit = lshr i32 %i, 31
+ %t = trunc nuw i32 %lobit to i1
+ %b = icmp slt i32 %i, 0
+ %not = xor i1 %t, true
+ %op = select i1 %not, i1 %b, i1 false
+ store i32 %lobit, ptr %p, align 1
+ ret i1 %op
+}
+
+define i1 @test2(i32 %i, ptr %p) {
+; CHECK-LABEL: define i1 @test2(
+; CHECK-SAME: i32 [[I:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT: [[DOTLOBIT:%.*]] = ashr i32 [[I]], 31
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[P]], align 1
+; CHECK-NEXT: ret i1 false
+;
+ %lobit = ashr i32 %i, 31
+ %t = trunc nuw i32 %lobit to i1
+ %b = icmp slt i32 %i, 0
+ %not = xor i1 %t, true
+ %op = select i1 %not, i1 %b, i1 false
+ store i32 %lobit, ptr %p, align 1
+ ret i1 %op
+}
+
+define i1 @test3(i32 %i, ptr %p, ptr %q) {
+; CHECK-LABEL: define i1 @test3(
+; CHECK-SAME: i32 [[I:%.*]], ptr [[P:%.*]], ptr [[Q:%.*]]) {
+; CHECK-NEXT: [[DOTLOBIT:%.*]] = lshr i32 [[I]], 31
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[P]], align 1
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[Q]], align 1
+; CHECK-NEXT: ret i1 false
+;
+ %lobit = lshr i32 %i, 31
+ %t = trunc nuw i32 %lobit to i1
+ %b = icmp slt i32 %i, 0
+ %not = xor i1 %t, true
+ %op = select i1 %not, i1 %b, i1 false
+ store i32 %lobit, ptr %p, align 1
+ store i32 %lobit, ptr %q, align 1
+ ret i1 %op
+}
+
+; Negative Test
+define i1 @test4(i32 %i, ptr %p) {
+; CHECK-LABEL: define i1 @test4(
+; CHECK-SAME: i32 [[I:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT: [[DOTLOBIT:%.*]] = lshr i32 [[I]], 30
+; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[DOTLOBIT]] to i1
+; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[I]], 0
+; CHECK-NEXT: [[NOT_:%.*]] = xor i1 [[T]], true
+; CHECK-NEXT: [[COMMON_RET1_OP:%.*]] = select i1 [[NOT_]], i1 [[B]], i1 false
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[P]], align 1
+; CHECK-NEXT: ret i1 [[COMMON_RET1_OP]]
+;
+ %lobit = lshr i32 %i, 30 ; should not fold as no. of bits shifted < BitWidth - 1
+ %t = trunc nuw i32 %lobit to i1
+ %b = icmp slt i32 %i, 0
+ %not = xor i1 %t, true
+ %op = select i1 %not, i1 %b, i1 false
+ store i32 %lobit, ptr %p, align 1
+ ret i1 %op
+}
+
+; Negative Test
+define i1 @test5(i32 %i, ptr %p) {
+; CHECK-LABEL: define i1 @test5(
+; CHECK-SAME: i32 [[I:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT: [[DOTLOBIT:%.*]] = ashr i32 [[I]], 30
+; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[DOTLOBIT]] to i1
+; CHECK-NEXT: [[B:%.*]] = icmp slt i32 [[I]], 0
+; CHECK-NEXT: [[NOT_:%.*]] = xor i1 [[T]], true
+; CHECK-NEXT: [[COMMON_RET1_OP:%.*]] = select i1 [[NOT_]], i1 [[B]], i1 false
+; CHECK-NEXT: store i32 [[DOTLOBIT]], ptr [[P]], align 1
+; CHECK-NEXT: ret i1 [[COMMON_RET1_OP]]
+;
+ %lobit = ashr i32 %i, 30 ; should not fold as no. of bits shifted < BitWidth - 1
+ %t = trunc nuw i32 %lobit to i1
+ %b = icmp slt i32 %i, 0
+ %not = xor i1 %t, true
+ %op = select i1 %not, i1 %b, i1 false
+ store i32 %lobit, ptr %p, align 1
+ ret i1 %op
+}
+
More information about the llvm-commits
mailing list