[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