From 8e9969dd645f452e915c33b96af2e0e30547a452 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Wed, 11 Jun 2025 19:00:27 +0800 Subject: [PATCH 1/6] pre-commit test [InstCombine] Fold `ceil(X >> C) == 0 -> X == 0` update test 1 address review comments rm header 1 1 --- .../InstCombine/InstCombineCompares.cpp | 1 + .../test/Transforms/InstCombine/ceil-shift.ll | 285 ++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/ceil-shift.ll diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 084e7fbaa268a..07a21f99f1f3b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1298,6 +1298,7 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { // eq/ne (mul X, Y)) with (icmp eq/ne X/Y) and if X/Y is known non-zero that // will fold to a constant elsewhere. } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/ceil-shift.ll b/llvm/test/Transforms/InstCombine/ceil-shift.ll new file mode 100644 index 0000000000000..7d460d5f399f5 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/ceil-shift.ll @@ -0,0 +1,285 @@ +; 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 @ceil_shift4(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %is_zero = icmp eq i32 %quot_or_rem, 0 + ret i1 %is_zero +} + +define i1 @ceil_shift4_add(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4_add( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %ceil = add i32 %quot, %zext_has_rem + %res = icmp eq i32 %ceil, 0 + ret i1 %res +} + +define i1 @ceil_shift6(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift6( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %quot = lshr i32 %arg0, 6 + %rem = and i32 %arg0, 63 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift6_ne(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift6_ne( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[RES]] +; + %quot = lshr i32 %arg0, 6 + %rem = and i32 %arg0, 63 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp ne i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift11(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift11( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 11 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 2047 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %quot = lshr i32 %arg0, 11 + %rem = and i32 %arg0, 2047 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift11_ne(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift11_ne( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[RES]] +; + %quot = lshr i32 %arg0, 6 + %rem = and i32 %arg0, 63 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp ne i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift0(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift0( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %quot = lshr i32 %arg0, 0 + %rem = and i32 %arg0, 0 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift4_comm(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4_comm( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %zext_has_rem, %quot + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +declare void @use(i32) + +define i1 @ceil_shift4_used_1(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4_used_1( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: call void @use(i32 [[TMP1]]) +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[TMP1]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 4 + call void @use(i32 %quot) + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift4_used_5(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4_used_5( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP1]], [[TMP4]] +; CHECK-NEXT: call void @use(i32 [[TMP5]]) +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + call void @use(i32 %quot_or_rem) + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { +; CHECK-LABEL: define <4 x i1> @ceil_shift4_v4i32( +; CHECK-SAME: <4 x i32> [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr <4 x i32> [[ARG0]], splat (i32 16) +; CHECK-NEXT: [[REM:%.*]] = and <4 x i32> [[ARG0]], splat (i32 65535) +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <4 x i32> [[REM]], zeroinitializer +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <4 x i1> [[HAS_REM]] to <4 x i32> +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <4 x i32> [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: ret <4 x i1> [[TMP1]] +; + %quot = lshr <4 x i32> %arg0, splat (i32 16) + %rem = and <4 x i32> %arg0, splat (i32 65535) + %has_rem = icmp ne <4 x i32> %rem, zeroinitializer + %zext_has_rem = zext <4 x i1> %has_rem to <4 x i32> + %quot_or_rem = or <4 x i32> %quot, %zext_has_rem + %res = icmp eq <4 x i32> %quot_or_rem, zeroinitializer + ret <4 x i1> %res +} + +define <8 x i1> @ceil_shift4_v8i16(<8 x i16> %arg0) { +; CHECK-LABEL: define <8 x i1> @ceil_shift4_v8i16( +; CHECK-SAME: <8 x i16> [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr <8 x i16> [[ARG0]], splat (i16 4) +; CHECK-NEXT: [[REM:%.*]] = and <8 x i16> [[ARG0]], splat (i16 15) +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <8 x i16> [[REM]], zeroinitializer +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <8 x i1> [[HAS_REM]] to <8 x i16> +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <8 x i16> [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: ret <8 x i1> [[TMP1]] +; + %quot = lshr <8 x i16> %arg0, splat (i16 4) + %rem = and <8 x i16> %arg0, splat (i16 15) + %has_rem = icmp ne <8 x i16> %rem, zeroinitializer + %zext_has_rem = zext <8 x i1> %has_rem to <8 x i16> + %quot_or_rem = or <8 x i16> %quot, %zext_has_rem + %res = icmp eq <8 x i16> %quot_or_rem, zeroinitializer + ret <8 x i1> %res +} + +; negative tests + +define i1 @ceil_shift_not_mask_1(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift_not_mask_1( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[ARG0]], 31 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP1]], [[TMP4]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 31 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} + +define i1 @ceil_shift_not_mask_2(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift_not_mask_2( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 5 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP1]], [[TMP4]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK-NEXT: ret i1 [[TMP6]] +; + %quot = lshr i32 %arg0, 5 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_or_rem = or i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_or_rem, 0 + ret i1 %res +} From 1a91c572f00c6edb6762de366cc9578ad2785042 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sat, 14 Jun 2025 10:09:44 +0800 Subject: [PATCH 2/6] [InstCombine] Fold `ceil(X >> C) == 0 -> X == 0` --- .../InstCombine/InstCombineCompares.cpp | 14 ++++ .../test/Transforms/InstCombine/ceil-shift.ll | 69 +++---------------- 2 files changed, 24 insertions(+), 59 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 07a21f99f1f3b..7508a4f8e73d3 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1299,6 +1299,20 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { // will fold to a constant elsewhere. } + // icmp eq/ne ((X >> C) | (X & mask(C) != 0)), 0 -> icmp eq/ne X, 0 + if (ICmpInst::isEquality(Pred)) { + Value *X; + const APInt *C1, *C2; + if (match(Cmp.getOperand(0), + m_OneUse(m_c_Or( + m_LShr(m_Value(X), m_APInt(C1)), + m_ZExt(m_SpecificICmp(ICmpInst::ICMP_NE, + m_And(m_Deferred(X), m_LowBitMask(C2)), + m_Zero()))))) && + C2->popcount() == C1->getZExtValue()) + return new ICmpInst(Pred, X, ConstantInt::getNullValue(X->getType())); + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/ceil-shift.ll b/llvm/test/Transforms/InstCombine/ceil-shift.ll index 7d460d5f399f5..f3552aee9cb66 100644 --- a/llvm/test/Transforms/InstCombine/ceil-shift.ll +++ b/llvm/test/Transforms/InstCombine/ceil-shift.ll @@ -4,12 +4,7 @@ define i1 @ceil_shift4(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 4 @@ -24,12 +19,7 @@ define i1 @ceil_shift4(i32 %arg0) { define i1 @ceil_shift4_add(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_add( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -44,12 +34,7 @@ define i1 @ceil_shift4_add(i32 %arg0) { define i1 @ceil_shift6(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 6 @@ -64,12 +49,7 @@ define i1 @ceil_shift6(i32 %arg0) { define i1 @ceil_shift6_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -84,12 +64,7 @@ define i1 @ceil_shift6_ne(i32 %arg0) { define i1 @ceil_shift11(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 11 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 2047 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 11 @@ -104,12 +79,7 @@ define i1 @ceil_shift11(i32 %arg0) { define i1 @ceil_shift11_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -139,12 +109,7 @@ define i1 @ceil_shift0(i32 %arg0) { define i1 @ceil_shift4_comm(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_comm( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -163,11 +128,7 @@ define i1 @ceil_shift4_used_1(i32 %arg0) { ; CHECK-SAME: i32 [[ARG0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[TMP1]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -205,12 +166,7 @@ define i1 @ceil_shift4_used_5(i32 %arg0) { define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { ; CHECK-LABEL: define <4 x i1> @ceil_shift4_v4i32( ; CHECK-SAME: <4 x i32> [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr <4 x i32> [[ARG0]], splat (i32 16) -; CHECK-NEXT: [[REM:%.*]] = and <4 x i32> [[ARG0]], splat (i32 65535) -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <4 x i32> [[REM]], zeroinitializer -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <4 x i1> [[HAS_REM]] to <4 x i32> -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <4 x i32> [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ARG0]], zeroinitializer ; CHECK-NEXT: ret <4 x i1> [[TMP1]] ; %quot = lshr <4 x i32> %arg0, splat (i32 16) @@ -225,12 +181,7 @@ define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { define <8 x i1> @ceil_shift4_v8i16(<8 x i16> %arg0) { ; CHECK-LABEL: define <8 x i1> @ceil_shift4_v8i16( ; CHECK-SAME: <8 x i16> [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr <8 x i16> [[ARG0]], splat (i16 4) -; CHECK-NEXT: [[REM:%.*]] = and <8 x i16> [[ARG0]], splat (i16 15) -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <8 x i16> [[REM]], zeroinitializer -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <8 x i1> [[HAS_REM]] to <8 x i16> -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <8 x i16> [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[ARG0]], zeroinitializer ; CHECK-NEXT: ret <8 x i1> [[TMP1]] ; %quot = lshr <8 x i16> %arg0, splat (i16 4) From 88301673e99451a4efa3ec9aeda4650f468ee6ec Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sat, 14 Jun 2025 21:02:56 +0800 Subject: [PATCH 3/6] add test --- .../test/Transforms/InstCombine/ceil-shift.ll | 111 ++++++++++++++++-- 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/ceil-shift.ll b/llvm/test/Transforms/InstCombine/ceil-shift.ll index f3552aee9cb66..7d47ebb166529 100644 --- a/llvm/test/Transforms/InstCombine/ceil-shift.ll +++ b/llvm/test/Transforms/InstCombine/ceil-shift.ll @@ -4,7 +4,12 @@ define i1 @ceil_shift4(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 4 @@ -19,7 +24,12 @@ define i1 @ceil_shift4(i32 %arg0) { define i1 @ceil_shift4_add(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_add( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -34,7 +44,12 @@ define i1 @ceil_shift4_add(i32 %arg0) { define i1 @ceil_shift6(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 6 @@ -49,7 +64,12 @@ define i1 @ceil_shift6(i32 %arg0) { define i1 @ceil_shift6_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -64,7 +84,12 @@ define i1 @ceil_shift6_ne(i32 %arg0) { define i1 @ceil_shift11(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 11 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 2047 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 11 @@ -79,7 +104,12 @@ define i1 @ceil_shift11(i32 %arg0) { define i1 @ceil_shift11_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -109,7 +139,12 @@ define i1 @ceil_shift0(i32 %arg0) { define i1 @ceil_shift4_comm(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_comm( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -128,7 +163,11 @@ define i1 @ceil_shift4_used_1(i32 %arg0) { ; CHECK-SAME: i32 [[ARG0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[TMP1]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -163,10 +202,37 @@ define i1 @ceil_shift4_used_5(i32 %arg0) { ret i1 %res } +define i1 @ceil_shift4_used_add_nuw_nsw(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift4_used_add_nuw_nsw( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 +; CHECK-NEXT: [[CEIL:%.*]] = add nuw nsw i32 [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: call void @use(i32 [[CEIL]]) +; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CEIL]], 0 +; CHECK-NEXT: ret i1 [[RES]] +; + %quot = lshr i32 %arg0, 4 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %ceil = add nuw nsw i32 %quot, %zext_has_rem + call void @use(i32 %ceil) + %res = icmp eq i32 %ceil, 0 + ret i1 %res +} + define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { ; CHECK-LABEL: define <4 x i1> @ceil_shift4_v4i32( ; CHECK-SAME: <4 x i32> [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ARG0]], zeroinitializer +; CHECK-NEXT: [[QUOT:%.*]] = lshr <4 x i32> [[ARG0]], splat (i32 16) +; CHECK-NEXT: [[REM:%.*]] = and <4 x i32> [[ARG0]], splat (i32 65535) +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <4 x i32> [[REM]], zeroinitializer +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <4 x i1> [[HAS_REM]] to <4 x i32> +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <4 x i32> [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[QUOT_OR_REM]], zeroinitializer ; CHECK-NEXT: ret <4 x i1> [[TMP1]] ; %quot = lshr <4 x i32> %arg0, splat (i32 16) @@ -181,7 +247,12 @@ define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { define <8 x i1> @ceil_shift4_v8i16(<8 x i16> %arg0) { ; CHECK-LABEL: define <8 x i1> @ceil_shift4_v8i16( ; CHECK-SAME: <8 x i16> [[ARG0:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[ARG0]], zeroinitializer +; CHECK-NEXT: [[QUOT:%.*]] = lshr <8 x i16> [[ARG0]], splat (i16 4) +; CHECK-NEXT: [[REM:%.*]] = and <8 x i16> [[ARG0]], splat (i16 15) +; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <8 x i16> [[REM]], zeroinitializer +; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <8 x i1> [[HAS_REM]] to <8 x i16> +; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <8 x i16> [[QUOT]], [[ZEXT_HAS_REM]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[QUOT_OR_REM]], zeroinitializer ; CHECK-NEXT: ret <8 x i1> [[TMP1]] ; %quot = lshr <8 x i16> %arg0, splat (i16 4) @@ -234,3 +305,23 @@ define i1 @ceil_shift_not_mask_2(i32 %arg0) { %res = icmp eq i32 %quot_or_rem, 0 ret i1 %res } + +define i1 @ceil_shift_not_add_or(i32 %arg0) { +; CHECK-LABEL: define i1 @ceil_shift_not_add_or( +; CHECK-SAME: i32 [[ARG0:%.*]]) { +; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 +; CHECK-NEXT: [[HAS_REM_NOT:%.*]] = icmp eq i32 [[REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[ARG0]], 32 +; CHECK-NEXT: [[RES1:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: [[RES:%.*]] = or i1 [[HAS_REM_NOT]], [[RES1]] +; CHECK-NEXT: ret i1 [[RES]] +; + %quot = lshr i32 %arg0, 5 + %rem = and i32 %arg0, 15 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %quot_and_rem = and i32 %quot, %zext_has_rem + %res = icmp eq i32 %quot_and_rem, 0 + ret i1 %res +} + From 32cf84843ebdba923c050daad495a72b3cbb2948 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sat, 14 Jun 2025 21:09:26 +0800 Subject: [PATCH 4/6] match both or and add --- .../InstCombine/InstCombineCompares.cpp | 17 +++-- .../test/Transforms/InstCombine/ceil-shift.ll | 74 +++---------------- 2 files changed, 22 insertions(+), 69 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 7508a4f8e73d3..04d821ba6fa91 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1299,16 +1299,19 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { // will fold to a constant elsewhere. } - // icmp eq/ne ((X >> C) | (X & mask(C) != 0)), 0 -> icmp eq/ne X, 0 + // icmp eq/ne ((X >> C) or/add (X & mask(C) != 0)), 0 -> icmp eq/ne X, 0 if (ICmpInst::isEquality(Pred)) { + auto *BO = dyn_cast(Cmp.getOperand(0)); Value *X; const APInt *C1, *C2; - if (match(Cmp.getOperand(0), - m_OneUse(m_c_Or( - m_LShr(m_Value(X), m_APInt(C1)), - m_ZExt(m_SpecificICmp(ICmpInst::ICMP_NE, - m_And(m_Deferred(X), m_LowBitMask(C2)), - m_Zero()))))) && + if (BO && + (BO->getOpcode() == Instruction::Add || + BO->getOpcode() == Instruction::Or) && + match(BO, m_c_BinOp(m_LShr(m_Value(X), m_APInt(C1)), + m_ZExt(m_SpecificICmp( + ICmpInst::ICMP_NE, + m_And(m_Deferred(X), m_LowBitMask(C2)), + m_Zero())))) && C2->popcount() == C1->getZExtValue()) return new ICmpInst(Pred, X, ConstantInt::getNullValue(X->getType())); } diff --git a/llvm/test/Transforms/InstCombine/ceil-shift.ll b/llvm/test/Transforms/InstCombine/ceil-shift.ll index 7d47ebb166529..8c24d7474ab94 100644 --- a/llvm/test/Transforms/InstCombine/ceil-shift.ll +++ b/llvm/test/Transforms/InstCombine/ceil-shift.ll @@ -4,12 +4,7 @@ define i1 @ceil_shift4(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 4 @@ -24,12 +19,7 @@ define i1 @ceil_shift4(i32 %arg0) { define i1 @ceil_shift4_add(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_add( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -44,12 +34,7 @@ define i1 @ceil_shift4_add(i32 %arg0) { define i1 @ceil_shift6(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 6 @@ -64,12 +49,7 @@ define i1 @ceil_shift6(i32 %arg0) { define i1 @ceil_shift6_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift6_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -84,12 +64,7 @@ define i1 @ceil_shift6_ne(i32 %arg0) { define i1 @ceil_shift11(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 11 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 2047 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP1]] ; %quot = lshr i32 %arg0, 11 @@ -104,12 +79,7 @@ define i1 @ceil_shift11(i32 %arg0) { define i1 @ceil_shift11_ne(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift11_ne( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 6 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 63 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 6 @@ -139,12 +109,7 @@ define i1 @ceil_shift0(i32 %arg0) { define i1 @ceil_shift4_comm(i32 %arg0) { ; CHECK-LABEL: define i1 @ceil_shift4_comm( ; CHECK-SAME: i32 [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr i32 [[ARG0]], 4 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -163,11 +128,7 @@ define i1 @ceil_shift4_used_1(i32 %arg0) { ; CHECK-SAME: i32 [[ARG0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[ARG0]], 4 ; CHECK-NEXT: call void @use(i32 [[TMP1]]) -; CHECK-NEXT: [[REM:%.*]] = and i32 [[ARG0]], 15 -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne i32 [[REM]], 0 -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or i32 [[TMP1]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[QUOT_OR_REM]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -189,7 +150,7 @@ define i1 @ceil_shift4_used_5(i32 %arg0) { ; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 ; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP1]], [[TMP4]] ; CHECK-NEXT: call void @use(i32 [[TMP5]]) -; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[TMP6]] ; %quot = lshr i32 %arg0, 4 @@ -211,7 +172,7 @@ define i1 @ceil_shift4_used_add_nuw_nsw(i32 %arg0) { ; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext i1 [[HAS_REM]] to i32 ; CHECK-NEXT: [[CEIL:%.*]] = add nuw nsw i32 [[QUOT]], [[ZEXT_HAS_REM]] ; CHECK-NEXT: call void @use(i32 [[CEIL]]) -; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CEIL]], 0 +; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[ARG0]], 0 ; CHECK-NEXT: ret i1 [[RES]] ; %quot = lshr i32 %arg0, 4 @@ -227,12 +188,7 @@ define i1 @ceil_shift4_used_add_nuw_nsw(i32 %arg0) { define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { ; CHECK-LABEL: define <4 x i1> @ceil_shift4_v4i32( ; CHECK-SAME: <4 x i32> [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr <4 x i32> [[ARG0]], splat (i32 16) -; CHECK-NEXT: [[REM:%.*]] = and <4 x i32> [[ARG0]], splat (i32 65535) -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <4 x i32> [[REM]], zeroinitializer -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <4 x i1> [[HAS_REM]] to <4 x i32> -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <4 x i32> [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ARG0]], zeroinitializer ; CHECK-NEXT: ret <4 x i1> [[TMP1]] ; %quot = lshr <4 x i32> %arg0, splat (i32 16) @@ -247,12 +203,7 @@ define <4 x i1> @ceil_shift4_v4i32(<4 x i32> %arg0) { define <8 x i1> @ceil_shift4_v8i16(<8 x i16> %arg0) { ; CHECK-LABEL: define <8 x i1> @ceil_shift4_v8i16( ; CHECK-SAME: <8 x i16> [[ARG0:%.*]]) { -; CHECK-NEXT: [[QUOT:%.*]] = lshr <8 x i16> [[ARG0]], splat (i16 4) -; CHECK-NEXT: [[REM:%.*]] = and <8 x i16> [[ARG0]], splat (i16 15) -; CHECK-NEXT: [[HAS_REM:%.*]] = icmp ne <8 x i16> [[REM]], zeroinitializer -; CHECK-NEXT: [[ZEXT_HAS_REM:%.*]] = zext <8 x i1> [[HAS_REM]] to <8 x i16> -; CHECK-NEXT: [[QUOT_OR_REM:%.*]] = or <8 x i16> [[QUOT]], [[ZEXT_HAS_REM]] -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[QUOT_OR_REM]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <8 x i16> [[ARG0]], zeroinitializer ; CHECK-NEXT: ret <8 x i1> [[TMP1]] ; %quot = lshr <8 x i16> %arg0, splat (i16 4) @@ -324,4 +275,3 @@ define i1 @ceil_shift_not_add_or(i32 %arg0) { %res = icmp eq i32 %quot_and_rem, 0 ret i1 %res } - From e854101347cc23125e3cb5783e6ceba97bc59f16 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sat, 21 Jun 2025 14:24:38 +0800 Subject: [PATCH 5/6] add `stripNullTest` and update `isKnownNonZero` --- llvm/include/llvm/Analysis/ValueTracking.h | 5 +++ llvm/lib/Analysis/ValueTracking.cpp | 26 ++++++++++++++++ .../InstCombine/InstCombineCompares.cpp | 21 +++---------- .../test/Transforms/InstCombine/ceil-shift.ll | 31 +++++++++++++++++++ 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index e215c90b5a72a..4596b2563c1d8 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -999,6 +999,11 @@ LLVM_ABI void findValuesAffectedByCondition(Value *Cond, bool IsAssume, function_ref InsertAffected); +/// Returns the inner value X if the expression has the form f(X) +/// where f(X) == 0 if and only if X == 0, otherwise returns nullptr. +LLVM_ABI Value *stripNullTest(Value *V); +LLVM_ABI const Value *stripNullTest(const Value *V); + } // end namespace llvm #endif // LLVM_ANALYSIS_VALUETRACKING_H diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index a17417cb5189c..3df9af4bc95fe 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3521,6 +3521,9 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts, isKnownNonNullFromDominatingCondition(V, Q.CxtI, Q.DT)) return true; + if (const Value *Stripped = stripNullTest(V)) + return isKnownNonZero(Stripped, DemandedElts, Q, Depth); + return false; } @@ -10170,3 +10173,26 @@ void llvm::findValuesAffectedByCondition( } } } + +const Value *llvm::stripNullTest(const Value *V) { + // (X >> C) or/add (X & mask(C) != 0) + if (const auto *BO = dyn_cast(V)) { + if (BO->getOpcode() == Instruction::Add || + BO->getOpcode() == Instruction::Or) { + const Value *X; + const APInt *C1, *C2; + if (match(BO, m_c_BinOp(m_LShr(m_Value(X), m_APInt(C1)), + m_ZExt(m_SpecificICmp( + ICmpInst::ICMP_NE, + m_And(m_Deferred(X), m_LowBitMask(C2)), + m_Zero())))) && + C2->popcount() == C1->getZExtValue()) + return X; + } + } + return nullptr; +} + +Value *llvm::stripNullTest(Value *V) { + return const_cast(stripNullTest(const_cast(V))); +} diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 04d821ba6fa91..84de0dbe4b197 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1299,22 +1299,11 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { // will fold to a constant elsewhere. } - // icmp eq/ne ((X >> C) or/add (X & mask(C) != 0)), 0 -> icmp eq/ne X, 0 - if (ICmpInst::isEquality(Pred)) { - auto *BO = dyn_cast(Cmp.getOperand(0)); - Value *X; - const APInt *C1, *C2; - if (BO && - (BO->getOpcode() == Instruction::Add || - BO->getOpcode() == Instruction::Or) && - match(BO, m_c_BinOp(m_LShr(m_Value(X), m_APInt(C1)), - m_ZExt(m_SpecificICmp( - ICmpInst::ICMP_NE, - m_And(m_Deferred(X), m_LowBitMask(C2)), - m_Zero())))) && - C2->popcount() == C1->getZExtValue()) - return new ICmpInst(Pred, X, ConstantInt::getNullValue(X->getType())); - } + // (icmp eq/ne f(X), 0) -> (icmp eq/ne X, 0) + // where f(X) == 0 if and only if X == 0 + if (ICmpInst::isEquality(Pred)) + if (Value *Stripped = stripNullTest(Cmp.getOperand(0))) + return new ICmpInst(Pred, Stripped, Cmp.getOperand(1)); return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/ceil-shift.ll b/llvm/test/Transforms/InstCombine/ceil-shift.ll index 8c24d7474ab94..d4b37786bb26f 100644 --- a/llvm/test/Transforms/InstCombine/ceil-shift.ll +++ b/llvm/test/Transforms/InstCombine/ceil-shift.ll @@ -275,3 +275,34 @@ define i1 @ceil_shift_not_add_or(i32 %arg0) { %res = icmp eq i32 %quot_and_rem, 0 ret i1 %res } + +define i32 @ceil_shift_should_infer_ge_zero(i32 %x) { +; CHECK-LABEL: define i32 @ceil_shift_should_infer_ge_zero( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND_NOT:%.*]] = icmp eq i32 [[X]], 0 +; CHECK-NEXT: br i1 [[COND_NOT]], label %[[IF_ELSE:.*]], label %[[IF_THEN:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X]], 20 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X]], 1048575 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 +; CHECK-NEXT: [[TMP5:%.*]] = add nuw nsw i32 [[TMP1]], [[TMP4]] +; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i32 0 +; + %cond = icmp ne i32 %x, 0 + br i1 %cond, label %if.then, label %if.else + +if.then: + %quot = lshr i32 %x, 20 + %rem = and i32 %x, 1048575 + %has_rem = icmp ne i32 %rem, 0 + %zext_has_rem = zext i1 %has_rem to i32 + %ceil = add nuw nsw i32 %quot, %zext_has_rem + %max = call i32 @llvm.umax.i32(i32 %ceil, i32 1) + ret i32 %max + +if.else: + ret i32 0 +} From da1b1d008a1733157f041d9576ce7a25957a024c Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sun, 22 Jun 2025 17:35:50 +0800 Subject: [PATCH 6/6] Update llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp Co-authored-by: Yingwei Zheng --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 84de0dbe4b197..0894ca92086f3 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1303,7 +1303,8 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { // where f(X) == 0 if and only if X == 0 if (ICmpInst::isEquality(Pred)) if (Value *Stripped = stripNullTest(Cmp.getOperand(0))) - return new ICmpInst(Pred, Stripped, Cmp.getOperand(1)); + return new ICmpInst(Pred, Stripped, + Constant::getNullValue(Stripped->getType())); return nullptr; }