[llvm] [InstCombine] Missed optimization for select a%2==0, (a/2*2)*(a/2*2), 0 (PR #92658)

Jorge Botto via llvm-commits llvm-commits at lists.llvm.org
Sat May 18 09:44:06 PDT 2024


https://github.com/jf-botto created https://github.com/llvm/llvm-project/pull/92658

This is my first PR contributing to LLVM. 
I'm more than happy to take any advice on board so that I can improve my future contributions.

Fixes #71533 
Proof: https://alive2.llvm.org/ce/z/PCkT2L

>From af9d4e8e41369a9f70014c53b2e9abe77e0d8a8b Mon Sep 17 00:00:00 2001
From: Jorge Botto <jorge.botto.16 at ucl.ac.uk>
Date: Fri, 17 May 2024 18:53:07 +0100
Subject: [PATCH 1/2] Initial tests precommit

---
 llvm/test/Transforms/InstCombine/select.ll | 75 ++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 2ade6faa99be3..b5360c152eec8 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -1456,6 +1456,81 @@ define <2 x i32> @select_icmp_slt0_xor_vec(<2 x i32> %x) {
   ret <2 x i32> %x.xor
 }
 
+define i8 @select_icmp_eq_mul_and(i8 noundef %a, i8 %b)  {
+; CHECK-LABEL: @select_icmp_eq_mul_and(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[DIV7]], [[DIV7]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[MUL]], i8 [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[RETVAL_0]]
+;
+  %1 = and i8 %a, 1
+  %cmp = icmp eq i8 %1, 0
+  %div7 = and i8 %a, -2
+  %mul = mul i8 %div7, %div7
+  %retval.0 = select i1 %cmp, i8 %mul, i8 %b
+  ret i8 %retval.0
+}
+
+define i8 @select_icmp_eq_shl_and(i8 noundef %a, i8 %b)  {
+; CHECK-LABEL: @select_icmp_eq_shl_and(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[DIV7]], [[DIV7]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[SHL]], i8 [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[RETVAL_0]]
+;
+  %1 = and i8 %a, 1
+  %cmp = icmp eq i8 %1, 0
+  %div7 = and i8 %a, -2
+  %shl = shl i8 %div7, %div7
+  %retval.0 = select i1 %cmp, i8 %shl, i8 %b
+  ret i8 %retval.0
+}
+
+define i8 @select_icmp_eq_and(i8 noundef %a, i8 %b)  {
+; CHECK-LABEL: @select_icmp_eq_and(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[DIV7]], i8 [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[RETVAL_0]]
+;
+  %1 = and i8 %a, 1
+  %cmp = icmp eq i8 %1, 0
+  %div7 = and i8 %a, -2
+  %retval.0 = select i1 %cmp, i8 %div7, i8 %b
+  ret i8 %retval.0
+}
+
+;negative test
+define i8 @select_and(i8 noundef %a, i8 %b, i1 %cmp)  {
+; CHECK-LABEL: @select_and(
+; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A:%.*]], -2
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP:%.*]], i8 [[DIV7]], i8 [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[RETVAL_0]]
+;
+  %div7 = and i8 %a, -2
+  %retval.0 = select i1 %cmp, i8 %div7, i8 %b
+  ret i8 %retval.0
+}
+
+;negative test
+define i8 @select_mul_and(i8 noundef %a, i8 %b, i1 %cmp)  {
+; CHECK-LABEL: @select_mul_and(
+; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A:%.*]], -2
+; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[DIV7]], [[DIV7]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP:%.*]], i8 [[MUL]], i8 [[B:%.*]]
+; CHECK-NEXT:    ret i8 [[RETVAL_0]]
+;
+  %div7 = and i8 %a, -2
+  %mul = mul i8 %div7, %div7
+  %retval.0 = select i1 %cmp, i8 %mul, i8 %b
+  ret i8 %retval.0
+}
+
 define <4 x i32> @canonicalize_to_shuffle(<4 x i32> %a, <4 x i32> %b) {
 ; CHECK-LABEL: @canonicalize_to_shuffle(
 ; CHECK-NEXT:    [[SEL:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>

>From 23407760f4316b58c1e8df401492b02910cb9e90 Mon Sep 17 00:00:00 2001
From: Jorge Botto <jorge.botto.16 at ucl.ac.uk>
Date: Sat, 18 May 2024 16:57:33 +0100
Subject: [PATCH 2/2] Adding missed optimisation

---
 .../InstCombine/InstCombineSelect.cpp         | 39 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/select.ll    | 13 +++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index a3ddb402bf662..e0cb7d951fb5f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1073,6 +1073,41 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
   return nullptr;
 }
 
+// (A % 2 == 0) ? (A/2*2) : B --> (A % 2 == 0) ? A : B
+// (A % 2 == 0) ? BinOp (A/2*2), (A/2*2) : B --> (A % 2 == 0) ? BinOp A, A : B
+static Value *foldSelectWithIcmpEqAndPattern(ICmpInst *Cmp, Value *TVal,
+                                             Value *FVal,
+                                             InstCombiner::BuilderTy &Builder) {
+  Value *A;
+  ConstantInt *MaskedConstant;
+  ICmpInst::Predicate Pred = Cmp->getPredicate();
+
+  // Checks if the comparison is (A % 2 == 0) and A is not undef.
+  if (!(Pred == ICmpInst::ICMP_EQ &&
+        match(Cmp->getOperand(0), m_And(m_Value(A), m_SpecificInt(1))) &&
+        match(Cmp->getOperand(1), m_SpecificInt(0)) &&
+        isGuaranteedNotToBeUndef(A)))
+    return nullptr;
+
+  // Checks if true branch matches (A % 2).
+  if (match(TVal,
+            m_OneUse(m_And(m_Specific(A), m_ConstantInt(MaskedConstant)))) &&
+      MaskedConstant->getValue().getSExtValue() == -2)
+    return Builder.CreateSelect(Cmp, A, FVal);
+
+  // Checks if true branch matches nested (A % 2) within a binary operation.
+  Value *MulVal;
+  if (match(TVal, m_OneUse(m_BinOp(m_Value(MulVal), m_Deferred(MulVal)))))
+    if (match(MulVal, m_And(m_Specific(A), m_ConstantInt(MaskedConstant))) &&
+        MaskedConstant->getValue().getSExtValue() == -2) {
+      Instruction::BinaryOps OpCode = cast<BinaryOperator>(TVal)->getOpcode();
+      Value *NewBinop = Builder.CreateBinOp(OpCode, A, A);
+      return Builder.CreateSelect(Cmp, NewBinop, FVal);
+    }
+
+  return nullptr;
+}
+
 /// Fold the following code sequence:
 /// \code
 ///   int a = ctlz(x & -x);
@@ -1933,6 +1968,10 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
   if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
     return replaceInstUsesWith(SI, V);
 
+  if (Value *V =
+          foldSelectWithIcmpEqAndPattern(ICI, TrueVal, FalseVal, Builder))
+    return replaceInstUsesWith(SI, V);
+
   return Changed ? &SI : nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index b5360c152eec8..a913552dc6cff 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -1460,9 +1460,8 @@ define i8 @select_icmp_eq_mul_and(i8 noundef %a, i8 %b)  {
 ; CHECK-LABEL: @select_icmp_eq_mul_and(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
-; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[DIV7]], [[DIV7]]
-; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[MUL]], i8 [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = mul i8 [[A]], [[A]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[TMP2]], i8 [[B:%.*]]
 ; CHECK-NEXT:    ret i8 [[RETVAL_0]]
 ;
   %1 = and i8 %a, 1
@@ -1477,9 +1476,8 @@ define i8 @select_icmp_eq_shl_and(i8 noundef %a, i8 %b)  {
 ; CHECK-LABEL: @select_icmp_eq_shl_and(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
-; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
-; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[DIV7]], [[DIV7]]
-; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[SHL]], i8 [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = shl i8 [[A]], [[A]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[TMP2]], i8 [[B:%.*]]
 ; CHECK-NEXT:    ret i8 [[RETVAL_0]]
 ;
   %1 = and i8 %a, 1
@@ -1494,8 +1492,7 @@ define i8 @select_icmp_eq_and(i8 noundef %a, i8 %b)  {
 ; CHECK-LABEL: @select_icmp_eq_and(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[A:%.*]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
-; CHECK-NEXT:    [[DIV7:%.*]] = and i8 [[A]], -2
-; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[DIV7]], i8 [[B:%.*]]
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = select i1 [[CMP]], i8 [[A]], i8 [[B:%.*]]
 ; CHECK-NEXT:    ret i8 [[RETVAL_0]]
 ;
   %1 = and i8 %a, 1



More information about the llvm-commits mailing list