[InstCombine] add support for multi-use Y of (X op Y) op Z --> (Y op Z) op X
authorChenbing Zheng <Chenbing.Zheng@streamcomputing.com>
Wed, 31 Aug 2022 02:49:58 +0000 (10:49 +0800)
committerChenbing Zheng <Chenbing.Zheng@streamcomputing.com>
Wed, 31 Aug 2022 02:55:05 +0000 (10:55 +0800)
For (X op Y) op Z --> (Y op Z) op X
we can still do transform when Y is multi-use. In D131356 limit it to one-use,
this patch remove this limit.

This is still not a complete solution, I add a todo test to show it.
In this case, X and Y are both multi use, we can't differentiate how to convert based on this.
But at least we don't make the code worse,and it can solve half the scenarios.

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and-or-not.ll

index 0dac7c3..b011c5f 100644 (file)
@@ -1752,15 +1752,20 @@ static Instruction *reassociateForUses(BinaryOperator &BO,
                                        InstCombinerImpl::BuilderTy &Builder) {
   Instruction::BinaryOps Opcode = BO.getOpcode();
   Value *X, *Y, *Z;
-  if (match(&BO, m_c_BinOp(Opcode,
-                           m_OneUse(m_c_BinOp(Opcode, m_Value(X),
-                                              m_OneUse(m_Value(Y)))),
-                           m_OneUse(m_Value(Z))))) {
-    // (X op Y) op Z --> (Y op Z) op X
-    if (!isa<Constant>(X) && !isa<Constant>(Y) && !isa<Constant>(Z) &&
-        !X->hasOneUse()) {
-      Value *YZ = Builder.CreateBinOp(Opcode, Y, Z);
-      return BinaryOperator::Create(Opcode, YZ, X);
+  if (match(&BO,
+            m_c_BinOp(Opcode, m_OneUse(m_BinOp(Opcode, m_Value(X), m_Value(Y))),
+                      m_OneUse(m_Value(Z))))) {
+    if (!isa<Constant>(X) && !isa<Constant>(Y) && !isa<Constant>(Z)) {
+      // (X op Y) op Z --> (Y op Z) op X
+      if (!X->hasOneUse()) {
+        Value *YZ = Builder.CreateBinOp(Opcode, Y, Z);
+        return BinaryOperator::Create(Opcode, YZ, X);
+      }
+      // (X op Y) op Z --> (X op Z) op Y
+      if (!Y->hasOneUse()) {
+        Value *XZ = Builder.CreateBinOp(Opcode, X, Z);
+        return BinaryOperator::Create(Opcode, XZ, Y);
+      }
     }
   }
 
index 73cb2f2..3622981 100644 (file)
@@ -747,12 +747,8 @@ define <2 x i4> @simplify_and_common_op_commute3(<2 x i4> %x, <2 x i4> %y, <2 x
 
 define i4 @simplify_and_common_op_use1(i4 %x, i4 %y, i4 %z)  {
 ; CHECK-LABEL: @simplify_and_common_op_use1(
-; CHECK-NEXT:    [[XY:%.*]] = or i4 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    call void @use(i4 [[Y]])
-; CHECK-NEXT:    [[XYZ:%.*]] = or i4 [[XY]], [[Z:%.*]]
-; CHECK-NEXT:    [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1
-; CHECK-NEXT:    [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]]
-; CHECK-NEXT:    ret i4 [[R]]
+; CHECK-NEXT:    call void @use(i4 [[Y:%.*]])
+; CHECK-NEXT:    ret i4 0
 ;
   %xy = or i4 %x, %y
   call void @use(i4 %y)
@@ -766,6 +762,25 @@ define i4 @simplify_and_common_op_use1(i4 %x, i4 %y, i4 %z)  {
 
 define i4 @simplify_and_common_op_use2(i4 %x, i4 %y, i4 %z)  {
 ; CHECK-LABEL: @simplify_and_common_op_use2(
+; CHECK-NEXT:    call void @use(i4 [[Y:%.*]])
+; CHECK-NEXT:    [[TMP1:%.*]] = or i4 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[XYZ:%.*]] = or i4 [[TMP1]], [[Y]]
+; CHECK-NEXT:    [[NOT_XYZ:%.*]] = xor i4 [[XYZ]], -1
+; CHECK-NEXT:    [[R:%.*]] = and i4 [[NOT_XYZ]], [[X]]
+; CHECK-NEXT:    ret i4 [[R]]
+;
+  %xy = or i4 %y, %x
+  call void @use(i4 %y)
+  %xyz = or i4 %xy, %z
+  %not_xyz = xor i4 %xyz, -1
+  %r = and i4 %not_xyz, %x
+  ret i4 %r
+}
+
+; TODO: This should simplify.
+
+define i4 @simplify_and_common_op_use3(i4 %x, i4 %y, i4 %z)  {
+; CHECK-LABEL: @simplify_and_common_op_use3(
 ; CHECK-NEXT:    [[XY:%.*]] = or i4 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[XYZ:%.*]] = or i4 [[XY]], [[Z:%.*]]
 ; CHECK-NEXT:    call void @use(i4 [[Z]])