[llvm] 7ab0a87 - [InstCombine] Try to freely invert phi nodes (#80804)

via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 7 05:39:16 PST 2024


Author: Yingwei Zheng
Date: 2024-02-07T21:39:12+08:00
New Revision: 7ab0a871431375cb966b0653b9f5caaba15cb6d9

URL: https://github.com/llvm/llvm-project/commit/7ab0a871431375cb966b0653b9f5caaba15cb6d9
DIFF: https://github.com/llvm/llvm-project/commit/7ab0a871431375cb966b0653b9f5caaba15cb6d9.diff

LOG: [InstCombine] Try to freely invert phi nodes (#80804)

This patch tries to invert phi nodes if all incoming values are either
constants or nots.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/test/Transforms/InstCombine/free-inversion.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 651e852bf6ed0..9e8bcbc8e156e 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2360,6 +2360,33 @@ Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
     }
   }
 
+  if (PHINode *PN = dyn_cast<PHINode>(V)) {
+    SmallVector<std::pair<Value *, BasicBlock *>, 8> IncomingValues;
+    for (Use &U : PN->operands()) {
+      BasicBlock *IncomingBlock = PN->getIncomingBlock(U);
+      Value *NewIncomingVal = getFreelyInvertedImpl(
+          U.get(), /*WillInvertAllUses=*/false,
+          /*Builder=*/nullptr, DoesConsume, MaxAnalysisRecursionDepth - 1);
+      if (NewIncomingVal == nullptr)
+        return nullptr;
+      // Make sure that we can safely erase the original PHI node.
+      if (NewIncomingVal == V)
+        return nullptr;
+      if (Builder != nullptr)
+        IncomingValues.emplace_back(NewIncomingVal, IncomingBlock);
+    }
+    if (Builder != nullptr) {
+      IRBuilderBase::InsertPointGuard Guard(*Builder);
+      Builder->SetInsertPoint(PN);
+      PHINode *NewPN =
+          Builder->CreatePHI(PN->getType(), PN->getNumIncomingValues());
+      for (auto [Val, Pred] : IncomingValues)
+        NewPN->addIncoming(Val, Pred);
+      return NewPN;
+    }
+    return NonNull;
+  }
+
   return nullptr;
 }
 

diff  --git a/llvm/test/Transforms/InstCombine/free-inversion.ll b/llvm/test/Transforms/InstCombine/free-inversion.ll
index be9bedbf79859..a89887a586b58 100644
--- a/llvm/test/Transforms/InstCombine/free-inversion.ll
+++ b/llvm/test/Transforms/InstCombine/free-inversion.ll
@@ -9,6 +9,7 @@ declare i8 @llvm.umax.i8(i8, i8)
 declare void @llvm.assume(i1)
 
 declare void @use.i8(i8)
+declare void @use.i1(i1)
 
 define i8 @xor_1(i8 %a, i1 %c, i8 %x, i8 %y) {
 ; CHECK-LABEL: @xor_1(
@@ -544,11 +545,198 @@ define i8 @lshr_not_nneg(i8 %x, i8 %y) {
 define i8 @lshr_not_nneg2(i8 %x) {
 ; CHECK-LABEL: @lshr_not_nneg2(
 ; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[SHR_NOT1:%.*]] = or disjoint i8 [[SHR]], -128
-; CHECK-NEXT:    ret i8 [[SHR_NOT1]]
+; CHECK-NEXT:    [[SHR_NOT:%.*]] = or disjoint i8 [[SHR]], -128
+; CHECK-NEXT:    ret i8 [[SHR_NOT]]
 ;
   %x.not = xor i8 %x, -1
   %shr = lshr i8 %x.not, 1
   %shr.not = xor i8 %shr, -1
   ret i8 %shr.not
 }
+
+define i1 @test_inv_free(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
+; CHECK-LABEL: @test_inv_free(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
+; CHECK:       b1:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
+; CHECK:       b2:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       b3:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[VAL_NOT:%.*]] = phi i1 [ false, [[B1]] ], [ true, [[B2]] ], [ [[C3:%.*]], [[B3]] ]
+; CHECK-NEXT:    [[COND_NOT:%.*]] = and i1 [[VAL_NOT]], [[C4:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[B5:%.*]], label [[B4:%.*]]
+; CHECK:       b4:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       b5:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  br i1 %c1, label %b1, label %b2
+b1:
+  br i1 %c2, label %exit, label %b3
+b2:
+  br label %exit
+b3:
+  %invc3 = xor i1 %c3, true
+  br label %exit
+exit:
+  %val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ]
+  %inv = xor i1 %c4, true
+  %cond = or i1 %val, %inv
+  br i1 %cond, label %b4, label %b5
+b4:
+  ret i1 true
+b5:
+  ret i1 false
+}
+
+define i32 @test_inv_free_i32(i1 %c1, i1 %c2, i32 %c3, i32 %c4) {
+; CHECK-LABEL: @test_inv_free_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
+; CHECK:       b1:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
+; CHECK:       b2:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       b3:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i32 [ 0, [[B1]] ], [ -1, [[B2]] ], [ [[C3:%.*]], [[B3]] ]
+; CHECK-NEXT:    [[COND:%.*]] = xor i32 [[TMP0]], [[C4:%.*]]
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+entry:
+  br i1 %c1, label %b1, label %b2
+b1:
+  br i1 %c2, label %exit, label %b3
+b2:
+  br label %exit
+b3:
+  %invc3 = xor i32 %c3, -1
+  br label %exit
+exit:
+  %val = phi i32 [ -1, %b1 ], [ 0, %b2 ], [ %invc3, %b3 ]
+  %inv = xor i32 %c4, -1
+  %cond = xor i32 %val, %inv
+  ret i32 %cond
+}
+
+; Negative tests
+
+define i1 @test_inv_free_multiuse(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
+; CHECK-LABEL: @test_inv_free_multiuse(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
+; CHECK:       b1:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
+; CHECK:       b2:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       b3:
+; CHECK-NEXT:    [[INVC3:%.*]] = xor i1 [[C3:%.*]], true
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[VAL:%.*]] = phi i1 [ true, [[B1]] ], [ false, [[B2]] ], [ [[INVC3]], [[B3]] ]
+; CHECK-NEXT:    call void @use.i1(i1 [[VAL]])
+; CHECK-NEXT:    [[INV:%.*]] = xor i1 [[C4:%.*]], true
+; CHECK-NEXT:    [[COND:%.*]] = or i1 [[VAL]], [[INV]]
+; CHECK-NEXT:    br i1 [[COND]], label [[B4:%.*]], label [[B5:%.*]]
+; CHECK:       b4:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       b5:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  br i1 %c1, label %b1, label %b2
+b1:
+  br i1 %c2, label %exit, label %b3
+b2:
+  br label %exit
+b3:
+  %invc3 = xor i1 %c3, true
+  br label %exit
+exit:
+  %val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ]
+  call void @use.i1(i1 %val)
+  %inv = xor i1 %c4, true
+  %cond = or i1 %val, %inv
+  br i1 %cond, label %b4, label %b5
+b4:
+  ret i1 true
+b5:
+  ret i1 false
+}
+
+define i32 @test_inv_free_i32_newinst(i1 %c1, i1 %c2, i32 %c3, i32 %c4) {
+; CHECK-LABEL: @test_inv_free_i32_newinst(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
+; CHECK:       b1:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
+; CHECK:       b2:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       b3:
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 -8, [[C3:%.*]]
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[VAL:%.*]] = phi i32 [ -1, [[B1]] ], [ 0, [[B2]] ], [ [[ASHR]], [[B3]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = xor i32 [[VAL]], [[C4:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = xor i32 [[TMP0]], -1
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+entry:
+  br i1 %c1, label %b1, label %b2
+b1:
+  br i1 %c2, label %exit, label %b3
+b2:
+  br label %exit
+b3:
+  %ashr = ashr i32 -8, %c3
+  br label %exit
+exit:
+  %val = phi i32 [ -1, %b1 ], [ 0, %b2 ], [ %ashr, %b3 ]
+  %inv = xor i32 %c4, -1
+  %cond = xor i32 %val, %inv
+  ret i32 %cond
+}
+
+define i1 @test_inv_free_loop(i1 %c1, i1 %c2, i1 %c3, i1 %c4) {
+; CHECK-LABEL: @test_inv_free_loop(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[B1:%.*]], label [[B2:%.*]]
+; CHECK:       b1:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[EXIT:%.*]], label [[B3:%.*]]
+; CHECK:       b2:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       b3:
+; CHECK-NEXT:    [[INVC3:%.*]] = xor i1 [[C3:%.*]], true
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[VAL:%.*]] = phi i1 [ true, [[B1]] ], [ false, [[B2]] ], [ [[INVC3]], [[B3]] ], [ [[NOT:%.*]], [[EXIT]] ]
+; CHECK-NEXT:    [[INV:%.*]] = xor i1 [[C4:%.*]], true
+; CHECK-NEXT:    [[COND:%.*]] = or i1 [[VAL]], [[INV]]
+; CHECK-NEXT:    [[NOT]] = xor i1 [[VAL]], true
+; CHECK-NEXT:    br i1 [[COND]], label [[EXIT]], label [[B4:%.*]]
+; CHECK:       b4:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  br i1 %c1, label %b1, label %b2
+b1:
+  br i1 %c2, label %exit, label %b3
+b2:
+  br label %exit
+b3:
+  %invc3 = xor i1 %c3, true
+  br label %exit
+exit:
+  %val = phi i1 [ true, %b1 ], [ false, %b2 ], [ %invc3, %b3 ], [ %not, %exit ]
+  %inv = xor i1 %c4, true
+  %cond = or i1 %val, %inv
+  %not = xor i1 %val, true
+  br i1 %cond, label %exit, label %b4
+b4:
+  ret i1 true
+}


        


More information about the llvm-commits mailing list