From 9423f78240a216e3f38b394a41fe3427dee22c26 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Apr 2021 22:09:15 +0200 Subject: [PATCH] [InstCombine] Fold multiuse shr eq zero The single-use case is handled implicity by converting the icmp into a mask check first. When comparing with zero in particular, we don't need the one-use restriction, as we only produce a single icmp. https://alive2.llvm.org/ce/z/MSixcm https://alive2.llvm.org/ce/z/GwpG0M --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 10 ++++++++++ llvm/test/Transforms/InstCombine/icmp-shr.ll | 8 ++++---- .../Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll | 7 +++---- llvm/test/Transforms/PhaseOrdering/X86/ctlz-loop.ll | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index fda8728..4e3ddae 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2274,6 +2274,16 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp, if (Shr->isExact()) return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, C << ShAmtVal)); + if (C.isNullValue()) { + // == 0 is u< 1. + if (Pred == CmpInst::ICMP_EQ) + return new ICmpInst(CmpInst::ICMP_ULT, X, + ConstantInt::get(ShrTy, (C + 1).shl(ShAmtVal))); + else + return new ICmpInst(CmpInst::ICMP_UGT, X, + ConstantInt::get(ShrTy, (C + 1).shl(ShAmtVal) - 1)); + } + if (Shr->hasOneUse()) { // Canonicalize the shift into an 'and': // icmp eq/ne (shr X, ShAmt), C --> icmp eq/ne (and X, HiMask), (C << ShAmt) diff --git a/llvm/test/Transforms/InstCombine/icmp-shr.ll b/llvm/test/Transforms/InstCombine/icmp-shr.ll index 486c518..d0f7271 100644 --- a/llvm/test/Transforms/InstCombine/icmp-shr.ll +++ b/llvm/test/Transforms/InstCombine/icmp-shr.ll @@ -875,7 +875,7 @@ define i1 @lshr_eq_0_multiuse(i8 %x) { ; CHECK-LABEL: @lshr_eq_0_multiuse( ; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 2 ; CHECK-NEXT: call void @use(i8 [[S]]) -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[S]], 0 +; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[X]], 4 ; CHECK-NEXT: ret i1 [[C]] ; %s = lshr i8 %x, 2 @@ -888,7 +888,7 @@ define i1 @lshr_ne_0_multiuse(i8 %x) { ; CHECK-LABEL: @lshr_ne_0_multiuse( ; CHECK-NEXT: [[S:%.*]] = lshr i8 [[X:%.*]], 2 ; CHECK-NEXT: call void @use(i8 [[S]]) -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[S]], 0 +; CHECK-NEXT: [[C:%.*]] = icmp ugt i8 [[X]], 3 ; CHECK-NEXT: ret i1 [[C]] ; %s = lshr i8 %x, 2 @@ -901,7 +901,7 @@ define i1 @ashr_eq_0_multiuse(i8 %x) { ; CHECK-LABEL: @ashr_eq_0_multiuse( ; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 ; CHECK-NEXT: call void @use(i8 [[S]]) -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[S]], 0 +; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[X]], 4 ; CHECK-NEXT: ret i1 [[C]] ; %s = ashr i8 %x, 2 @@ -914,7 +914,7 @@ define i1 @ashr_ne_0_multiuse(i8 %x) { ; CHECK-LABEL: @ashr_ne_0_multiuse( ; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2 ; CHECK-NEXT: call void @use(i8 [[S]]) -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[S]], 0 +; CHECK-NEXT: [[C:%.*]] = icmp ugt i8 [[X]], 3 ; CHECK-NEXT: ret i1 [[C]] ; %s = ashr i8 %x, 2 diff --git a/llvm/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll b/llvm/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll index 174c4b9..dde8bef 100644 --- a/llvm/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll +++ b/llvm/test/Transforms/InstCombine/icmp_sdiv_with_and_without_range.ll @@ -2,7 +2,7 @@ ; RUN: opt -instcombine -S < %s | FileCheck %s ; Test that presence of range does not cause unprofitable transforms with bit -; arithmetics, and instcombine behaves exactly the same as without the range. +; arithmetics. define i1 @without_range(i32* %A) { ; CHECK-LABEL: @without_range( @@ -18,9 +18,8 @@ define i1 @without_range(i32* %A) { define i1 @with_range(i32* %A) { ; CHECK-LABEL: @with_range( -; CHECK-NEXT: [[A_VAL:%.*]] = load i32, i32* [[A:%.*]], align 8, !range !0 -; CHECK-NEXT: [[B_MASK:%.*]] = and i32 [[A_VAL]], 2147483646 -; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[B_MASK]], 0 +; CHECK-NEXT: [[A_VAL:%.*]] = load i32, i32* [[A:%.*]], align 8, !range [[RNG0:![0-9]+]] +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[A_VAL]], 2 ; CHECK-NEXT: ret i1 [[C]] ; %A.val = load i32, i32* %A, align 8, !range !0 diff --git a/llvm/test/Transforms/PhaseOrdering/X86/ctlz-loop.ll b/llvm/test/Transforms/PhaseOrdering/X86/ctlz-loop.ll index 67aa30f..6cb8702 100644 --- a/llvm/test/Transforms/PhaseOrdering/X86/ctlz-loop.ll +++ b/llvm/test/Transforms/PhaseOrdering/X86/ctlz-loop.ll @@ -32,7 +32,7 @@ define i32 @ctlz_loop_with_abs(i32 %n) { ; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ [[INC:%.*]], [[WHILE_BODY]] ], [ 0, [[WHILE_BODY_PREHEADER]] ] ; CHECK-NEXT: [[TMP1]] = lshr i32 [[N_ADDR_03]], 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_02]], 1 -; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp ult i32 [[N_ADDR_03]], 2 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[WHILE_END]], label [[WHILE_BODY]] ; CHECK: while.end: ; CHECK-NEXT: [[I_0_LCSSA:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC]], [[WHILE_BODY]] ] -- 2.7.4