[llvm] 0863abe - [InstCombine] Fold icmp of select with non-constant operand

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri May 6 07:04:48 PDT 2022


Author: Nikita Popov
Date: 2022-05-06T16:04:39+02:00
New Revision: 0863abe3ac47c281fdd35dc87d83c495cf741da0

URL: https://github.com/llvm/llvm-project/commit/0863abe3ac47c281fdd35dc87d83c495cf741da0
DIFF: https://github.com/llvm/llvm-project/commit/0863abe3ac47c281fdd35dc87d83c495cf741da0.diff

LOG: [InstCombine] Fold icmp of select with non-constant operand

Try to push an icmp into a select even if the icmp operand isn't
constant - perform a generic SimplifyICmpInst instead.

This doesn't appear to impact compile-time much, and forming
logical and/or is generally profitable, as we have very good
support for them.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/icmp-select.ll
    llvm/test/Transforms/InstCombine/shift.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index dc4849b04592..06e6f255bc7c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3448,30 +3448,14 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstantNotInt(ICmpInst &I) {
 Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
                                               SelectInst *SI, Value *RHS,
                                               const ICmpInst &I) {
-  // If either operand of the select is a constant, we can fold the
-  // comparison into the select arms, which will cause one to be
-  // constant folded and the select turned into a bitwise or.
-  auto *RHSC = dyn_cast<Constant>(RHS);
-  if (!RHSC)
-    return nullptr;
-
-  auto SimplifyOp = [&](Value *V) {
-    Value *Op = nullptr;
-    if (Constant *C = dyn_cast<Constant>(V)) {
-      Op = ConstantExpr::getICmp(Pred, C, RHSC);
-    } else if (RHSC->isNullValue()) {
-      // If null is being compared, check if it can be further simplified.
-      Op = SimplifyICmpInst(Pred, V, RHSC, SQ);
-    }
-    return Op;
-  };
-
+  // Try to fold the comparison into the select arms, which will cause the
+  // select to be converted into a logical and/or.
   ConstantInt *CI = nullptr;
-  Value *Op1 = SimplifyOp(SI->getOperand(1));
+  Value *Op1 = SimplifyICmpInst(Pred, SI->getOperand(1), RHS, SQ);
   if (Op1)
     CI = dyn_cast<ConstantInt>(Op1);
 
-  Value *Op2 = SimplifyOp(SI->getOperand(2));
+  Value *Op2 = SimplifyICmpInst(Pred, SI->getOperand(2), RHS, SQ);
   if (Op2)
     CI = dyn_cast<ConstantInt>(Op2);
 
@@ -3498,9 +3482,9 @@ Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
   }
   if (Transform) {
     if (!Op1)
-      Op1 = Builder.CreateICmp(Pred, SI->getOperand(1), RHSC, I.getName());
+      Op1 = Builder.CreateICmp(Pred, SI->getOperand(1), RHS, I.getName());
     if (!Op2)
-      Op2 = Builder.CreateICmp(Pred, SI->getOperand(2), RHSC, I.getName());
+      Op2 = Builder.CreateICmp(Pred, SI->getOperand(2), RHS, I.getName());
     return SelectInst::Create(SI->getOperand(0), Op1, Op2);
   }
 
@@ -6116,6 +6100,9 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (auto *SI = dyn_cast<SelectInst>(Op0))
     if (Instruction *NI = foldSelectICmp(I.getPredicate(), SI, Op1, I))
       return NI;
+  if (auto *SI = dyn_cast<SelectInst>(Op1))
+    if (Instruction *NI = foldSelectICmp(I.getSwappedPredicate(), SI, Op0, I))
+      return NI;
 
   // Try to optimize equality comparisons against alloca-based pointers.
   if (Op0->getType()->isPointerTy() && I.isEquality()) {

diff  --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll
index 36d364563af3..215aa974625b 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select.ll
@@ -19,8 +19,8 @@ define i1 @icmp_select_const(i8 %x, i8 %y) {
 define i1 @icmp_select_var(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @icmp_select_var(
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[SEL]], [[Z]]
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %cmp1 = icmp eq i8 %x, 0
@@ -33,8 +33,8 @@ define i1 @icmp_select_var_commuted(i8 %x, i8 %y, i8 %_z) {
 ; CHECK-LABEL: @icmp_select_var_commuted(
 ; CHECK-NEXT:    [[Z:%.*]] = udiv i8 42, [[_Z:%.*]]
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[Z]], [[SEL]]
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Z]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %z = udiv i8 42, %_z ; thwart complexity-based canonicalization
@@ -46,10 +46,11 @@ define i1 @icmp_select_var_commuted(i8 %x, i8 %y, i8 %_z) {
 
 define i1 @icmp_select_var_select(i8 %x, i8 %y, i1 %c) {
 ; CHECK-LABEL: @icmp_select_var_select(
-; CHECK-NEXT:    [[Z:%.*]] = select i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[Z]], [[SEL]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP212:%.*]] = icmp eq i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[CMP1]], i1 true, i1 [[NOT_C]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 [[CMP212]]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %z = select i1 %c, i8 %x, i8 %y
@@ -104,9 +105,9 @@ define i1 @icmp_select_var_both_fold_extra_use(i8 %x, i8 %y, i8 %_z) {
 
 define i1 @icmp_select_var_pred_ne(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @icmp_select_var_pred_ne(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z:%.*]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ne i8 [[SEL]], [[Z]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp ne i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %cmp1 = icmp eq i8 %x, 0
@@ -119,8 +120,8 @@ define i1 @icmp_select_var_pred_ult(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @icmp_select_var_pred_ult(
 ; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 [[SEL]], [[Z1]]
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp ugt i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %z1 = add nuw i8 %z, 2
@@ -133,9 +134,9 @@ define i1 @icmp_select_var_pred_ult(i8 %x, i8 %y, i8 %z) {
 define i1 @icmp_select_var_pred_uge(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @icmp_select_var_pred_uge(
 ; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 [[SEL]], [[Z1]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp ule i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %z1 = add nuw i8 %z, 2
@@ -149,8 +150,8 @@ define i1 @icmp_select_var_pred_uge_commuted(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @icmp_select_var_pred_uge_commuted(
 ; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 [[Y:%.*]]
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i8 [[Z1]], [[SEL]]
+; CHECK-NEXT:    [[CMP21:%.*]] = icmp uge i8 [[Z1]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
 ; CHECK-NEXT:    ret i1 [[CMP2]]
 ;
   %z1 = add nuw i8 %z, 2

diff  --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index 491f9a73500a..8d9b1ec9f954 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -673,8 +673,8 @@ entry:
 define i32 @test40(i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: @test40(
 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[B:%.*]], 2
-; CHECK-NEXT:    [[DIV:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
-; CHECK-NEXT:    ret i32 [[DIV]]
+; CHECK-NEXT:    [[DIV1:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[DIV1]]
 ;
   %shl1 = shl i32 1, %b
   %shl2 = shl i32 %shl1, 2
@@ -717,8 +717,8 @@ define <2 x i32> @test42vec(<2 x i32> %a, <2 x i32> %b) {
 define i32 @test43(i32 %a, i32 %b) nounwind {
 ; CHECK-LABEL: @test43(
 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[B:%.*]], 12
-; CHECK-NEXT:    [[DIV2:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
-; CHECK-NEXT:    ret i32 [[DIV2]]
+; CHECK-NEXT:    [[DIV21:%.*]] = lshr i32 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i32 [[DIV21]]
 ;
   %div = shl i32 4096, %b    ; must be exact otherwise we'd divide by zero
   %div2 = udiv i32 %a, %div
@@ -1716,8 +1716,8 @@ define void @ashr_out_of_range(i177* %A) {
 ; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i64 -1, i64 -2
 ; CHECK-NEXT:    [[G11:%.*]] = getelementptr i177, i177* [[A]], i64 [[TMP2]]
 ; CHECK-NEXT:    [[L7:%.*]] = load i177, i177* [[G11]], align 4
-; CHECK-NEXT:    [[B36:%.*]] = select i1 [[TMP1]], i177 0, i177 [[L7]]
-; CHECK-NEXT:    [[C17:%.*]] = icmp sgt i177 [[B36]], [[L7]]
+; CHECK-NEXT:    [[C171:%.*]] = icmp slt i177 [[L7]], 0
+; CHECK-NEXT:    [[C17:%.*]] = select i1 [[TMP1]], i1 [[C171]], i1 false
 ; CHECK-NEXT:    [[TMP3:%.*]] = sext i1 [[C17]] to i64
 ; CHECK-NEXT:    [[G62:%.*]] = getelementptr i177, i177* [[G11]], i64 [[TMP3]]
 ; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i177 [[L7]], -1


        


More information about the llvm-commits mailing list