[llvm-branch-commits] [llvm] 38ca7fa - [InstSimplify] reduce logic with inverted add/sub ops

Sanjay Patel via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Dec 21 06:19:09 PST 2020


Author: Sanjay Patel
Date: 2020-12-21T08:51:43-05:00
New Revision: 38ca7face67e8488d482b66a999d0a685806879f

URL: https://github.com/llvm/llvm-project/commit/38ca7face67e8488d482b66a999d0a685806879f
DIFF: https://github.com/llvm/llvm-project/commit/38ca7face67e8488d482b66a999d0a685806879f.diff

LOG: [InstSimplify] reduce logic with inverted add/sub ops

https://llvm.org/PR48559
This could be part of a larger ValueTracking API,
but I don't see that currently.

https://rise4fun.com/Alive/gR0

  Name: and
  Pre: C1 == ~C2
  %sub = add i8 %x, C1
  %sub1 = sub i8 C2, %x
  %r = and i8 %sub, %sub1
  =>
  %r = 0

  Name: or
  Pre: C1 == ~C2
  %sub = add i8 %x, C1
  %sub1 = sub i8 C2, %x
  %r = or i8 %sub, %sub1
  =>
  %r = -1

  Name: xor
  Pre: C1 == ~C2
  %sub = add i8 %x, C1
  %sub1 = sub i8 C2, %x
  %r = xor i8 %sub, %sub1
  =>
  %r = -1

Added: 
    

Modified: 
    llvm/lib/Analysis/InstructionSimplify.cpp
    llvm/test/Transforms/InstSimplify/AndOrXor.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 55f3bc4f2923..27b73a5a8236 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1999,6 +1999,30 @@ static Value *omitCheckForZeroBeforeInvertedMulWithOverflow(Value *Op0,
   return NotOp1;
 }
 
+/// Given a bitwise logic op, check if the operands are add/sub with a common
+/// source value and inverted constant (identity: C - X -> ~(X + ~C)).
+static Value *simplifyLogicOfAddSub(Value *Op0, Value *Op1,
+                                    Instruction::BinaryOps Opcode) {
+  assert(Op0->getType() == Op1->getType() && "Mismatched binop types");
+  assert(BinaryOperator::isBitwiseLogicOp(Opcode) && "Expected logic op");
+  Value *X;
+  Constant *C1, *C2;
+  if ((match(Op0, m_Add(m_Value(X), m_Constant(C1))) &&
+       match(Op1, m_Sub(m_Constant(C2), m_Specific(X)))) ||
+      (match(Op1, m_Add(m_Value(X), m_Constant(C1))) &&
+       match(Op0, m_Sub(m_Constant(C2), m_Specific(X))))) {
+    if (ConstantExpr::getNot(C1) == C2) {
+      // (X + C) & (~C - X) --> (X + C) & ~(X + C) --> 0
+      // (X + C) | (~C - X) --> (X + C) | ~(X + C) --> -1
+      // (X + C) ^ (~C - X) --> (X + C) ^ ~(X + C) --> -1
+      Type *Ty = Op0->getType();
+      return Opcode == Instruction::And ? ConstantInt::getNullValue(Ty)
+                                        : ConstantInt::getAllOnesValue(Ty);
+    }
+  }
+  return nullptr;
+}
+
 /// Given operands for an And, see if we can fold the result.
 /// If not, this returns null.
 static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
@@ -2035,6 +2059,9 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   if (match(Op1, m_c_Or(m_Specific(Op0), m_Value())))
     return Op0;
 
+  if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::And))
+    return V;
+
   // A mask that only clears known zeros of a shifted value is a no-op.
   Value *X;
   const APInt *Mask;
@@ -2194,6 +2221,9 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   if (match(Op1, m_Not(m_c_And(m_Specific(Op0), m_Value()))))
     return Constant::getAllOnesValue(Op0->getType());
 
+  if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::Or))
+    return V;
+
   Value *A, *B;
   // (A & ~B) | (A ^ B) -> (A ^ B)
   // (~B & A) | (A ^ B) -> (A ^ B)
@@ -2323,6 +2353,9 @@ static Value *SimplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
       match(Op1, m_Not(m_Specific(Op0))))
     return Constant::getAllOnesValue(Op0->getType());
 
+  if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::Xor))
+    return V;
+
   // Try some generic simplifications for associative operations.
   if (Value *V = SimplifyAssociativeBinOp(Instruction::Xor, Op0, Op1, Q,
                                           MaxRecurse))

diff  --git a/llvm/test/Transforms/InstSimplify/AndOrXor.ll b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
index 9e549ebefc6b..e23262835c3c 100644
--- a/llvm/test/Transforms/InstSimplify/AndOrXor.ll
+++ b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
@@ -1053,10 +1053,7 @@ define <2 x i32> @shl_or_and3v(<2 x i16> %a, <2 x i16> %b) {
 
 define i8 @and_add_sub(i8 %x) {
 ; CHECK-LABEL: @and_add_sub(
-; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], -1
-; CHECK-NEXT:    [[S:%.*]] = sub i8 0, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[S]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 0
 ;
   %a = add i8 %x, -1
   %s = sub i8 0, %x
@@ -1066,10 +1063,7 @@ define i8 @and_add_sub(i8 %x) {
 
 define <2 x i8> @and_sub_add(<2 x i8> %x) {
 ; CHECK-LABEL: @and_sub_add(
-; CHECK-NEXT:    [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -4, i8 -4>
-; CHECK-NEXT:    [[S:%.*]] = sub <2 x i8> <i8 3, i8 3>, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i8> [[S]], [[A]]
-; CHECK-NEXT:    ret <2 x i8> [[R]]
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
 ;
   %a = add <2 x i8> %x, <i8 -4, i8 -4>
   %s = sub <2 x i8> <i8 3, i8 3>, %x
@@ -1079,10 +1073,7 @@ define <2 x i8> @and_sub_add(<2 x i8> %x) {
 
 define i89 @or_add_sub(i89 %x) {
 ; CHECK-LABEL: @or_add_sub(
-; CHECK-NEXT:    [[A:%.*]] = add i89 [[X:%.*]], 5
-; CHECK-NEXT:    [[S:%.*]] = sub i89 -6, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = or i89 [[A]], [[S]]
-; CHECK-NEXT:    ret i89 [[R]]
+; CHECK-NEXT:    ret i89 -1
 ;
   %a = add i89 %x, 5
   %s = sub i89 -6, %x
@@ -1092,10 +1083,7 @@ define i89 @or_add_sub(i89 %x) {
 
 define <3 x i8> @or_sub_add(<3 x i8> %x) {
 ; CHECK-LABEL: @or_sub_add(
-; CHECK-NEXT:    [[A:%.*]] = add <3 x i8> [[X:%.*]], <i8 42, i8 -12, i8 0>
-; CHECK-NEXT:    [[S:%.*]] = sub <3 x i8> <i8 -43, i8 11, i8 -1>, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = or <3 x i8> [[S]], [[A]]
-; CHECK-NEXT:    ret <3 x i8> [[R]]
+; CHECK-NEXT:    ret <3 x i8> <i8 -1, i8 -1, i8 -1>
 ;
   %a = add <3 x i8> %x, <i8 42, i8 -12, i8 0>
   %s = sub <3 x i8> <i8 -43, i8 11, i8 -1>, %x
@@ -1106,10 +1094,7 @@ define <3 x i8> @or_sub_add(<3 x i8> %x) {
 
 define <2 x i17> @xor_add_sub(<2 x i17> %x) {
 ; CHECK-LABEL: @xor_add_sub(
-; CHECK-NEXT:    [[A:%.*]] = add <2 x i17> [[X:%.*]], <i17 3000, i17 23>
-; CHECK-NEXT:    [[S:%.*]] = sub <2 x i17> <i17 -3001, i17 -24>, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = xor <2 x i17> [[A]], [[S]]
-; CHECK-NEXT:    ret <2 x i17> [[R]]
+; CHECK-NEXT:    ret <2 x i17> <i17 -1, i17 -1>
 ;
   %a = add <2 x i17> %x, <i17 3000, i17 23>
   %s = sub <2 x i17> <i17 -3001, i17 -24>, %x
@@ -1119,10 +1104,7 @@ define <2 x i17> @xor_add_sub(<2 x i17> %x) {
 
 define i8 @xor_sub_add(i8 %x) {
 ; CHECK-LABEL: @xor_sub_add(
-; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], 33
-; CHECK-NEXT:    [[S:%.*]] = sub i8 -34, [[X]]
-; CHECK-NEXT:    [[R:%.*]] = xor i8 [[S]], [[A]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 -1
 ;
   %a = add i8 %x, 33
   %s = sub i8 -34, %x
@@ -1130,6 +1112,8 @@ define i8 @xor_sub_add(i8 %x) {
   ret i8 %r
 }
 
+; Negative test
+
 define i8 @and_add_sub_wrong_const(i8 %x) {
 ; CHECK-LABEL: @and_add_sub_wrong_const(
 ; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], 6
@@ -1143,6 +1127,8 @@ define i8 @and_add_sub_wrong_const(i8 %x) {
   ret i8 %r
 }
 
+; Negative test
+
 define i8 @or_add_sub_wrong_var(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_add_sub_wrong_var(
 ; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], 5
@@ -1156,6 +1142,8 @@ define i8 @or_add_sub_wrong_var(i8 %x, i8 %y) {
   ret i8 %r
 }
 
+; Negative test
+
 define i8 @xor_add_sub_wrong_op(i8 %x) {
 ; CHECK-LABEL: @xor_add_sub_wrong_op(
 ; CHECK-NEXT:    [[A:%.*]] = add i8 [[X:%.*]], 5


        


More information about the llvm-branch-commits mailing list