[llvm-commits] [llvm] r126081 - in /llvm/trunk: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp test/Transforms/InstCombine/or-xor.ll

Benjamin Kramer benny.kra at googlemail.com
Sun Feb 20 05:23:43 PST 2011


Author: d0k
Date: Sun Feb 20 07:23:43 2011
New Revision: 126081

URL: http://llvm.org/viewvc/llvm-project?rev=126081&view=rev
Log:
InstCombine: Add a bunch of combines of the form x | (y ^ z).

We usually catch this kind of optimization through InstSimplify's distributive
magic, but or doesn't distribute over xor in general.

"A | ~(A | B) -> A | ~B" hits 24 times on gcc.c.

Added:
    llvm/trunk/test/Transforms/InstCombine/or-xor.ll
Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp?rev=126081&r1=126080&r2=126081&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Sun Feb 20 07:23:43 2011
@@ -1897,6 +1897,47 @@
         return BinaryOperator::CreateNot(And);
       }
 
+  // Canonicalize xor to the RHS.
+  if (match(Op0, m_Xor(m_Value(), m_Value())))
+    std::swap(Op0, Op1);
+
+  // A | ( A ^ B) -> A |  B
+  // A | (~A ^ B) -> A | ~B
+  if (match(Op1, m_Xor(m_Value(A), m_Value(B)))) {
+    if (Op0 == A || Op0 == B)
+      return BinaryOperator::CreateOr(A, B);
+
+    if (Op1->hasOneUse() && match(A, m_Not(m_Specific(Op0)))) {
+      Value *Not = Builder->CreateNot(B, B->getName()+".not");
+      return BinaryOperator::CreateOr(Not, Op0);
+    }
+    if (Op1->hasOneUse() && match(B, m_Not(m_Specific(Op0)))) {
+      Value *Not = Builder->CreateNot(A, A->getName()+".not");
+      return BinaryOperator::CreateOr(Not, Op0);
+    }
+  }
+
+  // A | ~(A | B) -> A | ~B
+  // A | ~(A ^ B) -> A | ~B
+  // A | ~(A & B) -> -1
+  if (match(Op1, m_Not(m_Value(A))))
+    if (BinaryOperator *B = dyn_cast<BinaryOperator>(A))
+      if (Op0 == B->getOperand(0) || Op0 == B->getOperand(1))
+        switch (B->getOpcode()) {
+        default: break;
+        case Instruction::Or:
+        case Instruction::Xor:
+          if (Op1->hasOneUse()) {
+            Value *NotOp = Op0 == B->getOperand(0) ? B->getOperand(1) :
+                                                     B->getOperand(0);
+            Value *Not = Builder->CreateNot(NotOp, NotOp->getName()+".not");
+            return BinaryOperator::CreateOr(Not, Op0);
+          }
+          break;
+        case Instruction::And:
+          return ReplaceInstUsesWith(I, Constant::getAllOnesValue(I.getType()));
+        }
+
   if (ICmpInst *RHS = dyn_cast<ICmpInst>(I.getOperand(1)))
     if (ICmpInst *LHS = dyn_cast<ICmpInst>(I.getOperand(0)))
       if (Value *Res = FoldOrOfICmps(LHS, RHS))

Added: llvm/trunk/test/Transforms/InstCombine/or-xor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/or-xor.ll?rev=126081&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/or-xor.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/or-xor.ll Sun Feb 20 07:23:43 2011
@@ -0,0 +1,94 @@
+; RUN: opt -S -instcombine < %s | FileCheck %s
+
+define i32 @test1(i32 %x, i32 %y) nounwind {
+  %or = or i32 %x, %y
+  %not = xor i32 %or, -1
+  %z = or i32 %x, %not
+  ret i32 %z
+; CHECK: @test1
+; CHECK-NEXT: %y.not = xor i32 %y, -1
+; CHECK-NEXT: %z = or i32 %y.not, %x
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test2(i32 %x, i32 %y) nounwind {
+  %or = or i32 %x, %y
+  %not = xor i32 %or, -1
+  %z = or i32 %y, %not
+  ret i32 %z
+; CHECK: @test2
+; CHECK-NEXT: %x.not = xor i32 %x, -1
+; CHECK-NEXT: %z = or i32 %x.not, %y
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test3(i32 %x, i32 %y) nounwind {
+  %xor = xor i32 %x, %y
+  %not = xor i32 %xor, -1
+  %z = or i32 %x, %not
+  ret i32 %z
+; CHECK: @test3
+; CHECK-NEXT: %y.not = xor i32 %y, -1
+; CHECK-NEXT: %z = or i32 %y.not, %x
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test4(i32 %x, i32 %y) nounwind {
+  %xor = xor i32 %x, %y
+  %not = xor i32 %xor, -1
+  %z = or i32 %y, %not
+  ret i32 %z
+; CHECK: @test4
+; CHECK-NEXT: %x.not = xor i32 %x, -1
+; CHECK-NEXT: %z = or i32 %x.not, %y
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test5(i32 %x, i32 %y) nounwind {
+  %and = and i32 %x, %y
+  %not = xor i32 %and, -1
+  %z = or i32 %x, %not
+  ret i32 %z
+; CHECK: @test5
+; CHECK-NEXT: ret i32 -1
+}
+
+define i32 @test6(i32 %x, i32 %y) nounwind {
+  %and = and i32 %x, %y
+  %not = xor i32 %and, -1
+  %z = or i32 %y, %not
+  ret i32 %z
+; CHECK: @test6
+; CHECK-NEXT: ret i32 -1
+}
+
+define i32 @test7(i32 %x, i32 %y) nounwind {
+  %xor = xor i32 %x, %y
+  %z = or i32 %y, %xor
+  ret i32 %z
+; CHECK: @test7
+; CHECK-NEXT: %z = or i32 %x, %y
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test8(i32 %x, i32 %y) nounwind {
+  %not = xor i32 %y, -1
+  %xor = xor i32 %x, %not
+  %z = or i32 %y, %xor
+  ret i32 %z
+; CHECK: @test8
+; CHECK-NEXT: %x.not = xor i32 %x, -1
+; CHECK-NEXT: %z = or i32 %x.not, %y
+; CHECK-NEXT: ret i32 %z
+}
+
+define i32 @test9(i32 %x, i32 %y) nounwind {
+  %not = xor i32 %x, -1
+  %xor = xor i32 %not, %y
+  %z = or i32 %x, %xor
+  ret i32 %z
+; CHECK: @test9
+; CHECK-NEXT: %y.not = xor i32 %y, -1
+; CHECK-NEXT: %z = or i32 %y.not, %x
+; CHECK-NEXT: ret i32 %z
+}





More information about the llvm-commits mailing list