[llvm] r301848 - [InstCombine] check one-use before applying DeMorgan nor/nand folds

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon May 1 15:25:42 PDT 2017


Author: spatel
Date: Mon May  1 17:25:42 2017
New Revision: 301848

URL: http://llvm.org/viewvc/llvm-project?rev=301848&view=rev
Log:
[InstCombine] check one-use before applying DeMorgan nor/nand folds

If we have ~(~X & Y), it only makes sense to transform it to (X | ~Y) when we do not need 
the intermediate (~X & Y) value. In that case, we would need an extra instruction to 
generate ~Y + 'or' (as shown in the test changes).

It's ok if we have multiple uses of ~X or Y, however. In those cases, we may not reduce the
instruction count or critical path, but we might improve throughput because we can generate 
~X and ~Y in parallel. Whether that actually makes perf sense or not for a target is something 
we can't answer in IR.

Differential Revision: https://reviews.llvm.org/D32703

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/trunk/test/Transforms/InstCombine/demorgan.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp?rev=301848&r1=301847&r2=301848&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Mon May  1 17:25:42 2017
@@ -2438,16 +2438,20 @@ Instruction *InstCombiner::visitXor(Bina
   if (match(&I, m_Not(m_BinOp(NotOp)))) {
     if (NotOp->getOpcode() == Instruction::And ||
         NotOp->getOpcode() == Instruction::Or) {
-      // ~(~X & Y) --> (X | ~Y) - De Morgan's Law
-      // ~(~X | Y) === (X & ~Y) - De Morgan's Law
-      if (dyn_castNotVal(NotOp->getOperand(1)))
-        NotOp->swapOperands();
-      if (Value *Op0NotVal = dyn_castNotVal(NotOp->getOperand(0))) {
-        Value *NotY = Builder->CreateNot(
-            NotOp->getOperand(1), NotOp->getOperand(1)->getName() + ".not");
-        if (NotOp->getOpcode() == Instruction::And)
-          return BinaryOperator::CreateOr(Op0NotVal, NotY);
-        return BinaryOperator::CreateAnd(Op0NotVal, NotY);
+      // We must eliminate the and/or for this transform to not increase the
+      // instruction count.
+      if (NotOp->hasOneUse()) {
+        // ~(~X & Y) --> (X | ~Y) - De Morgan's Law
+        // ~(~X | Y) === (X & ~Y) - De Morgan's Law
+        if (dyn_castNotVal(NotOp->getOperand(1)))
+          NotOp->swapOperands();
+        if (Value *Op0NotVal = dyn_castNotVal(NotOp->getOperand(0))) {
+          Value *NotY = Builder->CreateNot(
+              NotOp->getOperand(1), NotOp->getOperand(1)->getName() + ".not");
+          if (NotOp->getOpcode() == Instruction::And)
+            return BinaryOperator::CreateOr(Op0NotVal, NotY);
+          return BinaryOperator::CreateAnd(Op0NotVal, NotY);
+        }
       }
 
       // ~(X & Y) --> (~X | ~Y) - De Morgan's Law

Modified: llvm/trunk/test/Transforms/InstCombine/demorgan.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/demorgan.ll?rev=301848&r1=301847&r2=301848&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/demorgan.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/demorgan.ll Mon May  1 17:25:42 2017
@@ -286,8 +286,7 @@ define i8 @demorgan_nor_use2c(i8 %A, i8
 ; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
 ; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
 ; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
-; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
-; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
 ; CHECK-NEXT:    [[R:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
@@ -330,8 +329,7 @@ define i8 @demorgan_nor_use2ac(i8 %A, i8
 ; CHECK-NEXT:    [[USE2A:%.*]] = mul i8 [[NOTA]], 17
 ; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
 ; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
-; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
-; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
 ; CHECK-NEXT:    [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
 ; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[R1]], [[USE2A]]
 ; CHECK-NEXT:    ret i8 [[R2]]
@@ -354,8 +352,7 @@ define i8 @demorgan_nor_use2bc(i8 %A, i8
 ; CHECK-NEXT:    [[NOTA:%.*]] = xor i8 %A, -1
 ; CHECK-NEXT:    [[C:%.*]] = or i8 [[NOTA]], %B
 ; CHECK-NEXT:    [[USE2C:%.*]] = mul i8 [[C]], 23
-; CHECK-NEXT:    [[B_NOT:%.*]] = xor i8 %B, -1
-; CHECK-NEXT:    [[NOTC:%.*]] = and i8 [[B_NOT]], %A
+; CHECK-NEXT:    [[NOTC:%.*]] = xor i8 [[C]], -1
 ; CHECK-NEXT:    [[R1:%.*]] = sdiv i8 [[NOTC]], [[USE2C]]
 ; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[R1]], [[USE2B]]
 ; CHECK-NEXT:    ret i8 [[R2]]




More information about the llvm-commits mailing list