-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[InstCombine] Expand redundant phi cycle elimination #67968
Conversation
@llvm/pr-subscribers-llvm-transforms ChangesThere is a combine in instcombine that will look for phi cycles that only have
This currently doesn't handle if %othervalue is a phi though, as the algorithm Full diff: https://github.com/llvm/llvm-project/pull/67968.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index 5b8b74c8648b8c0..3ce500517bc2d7b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -996,7 +996,7 @@ static bool isDeadPHICycle(PHINode *PN,
/// Return true if this phi node is always equal to NonPhiInVal.
/// This happens with mutually cyclic phi nodes like:
/// z = some value; x = phi (y, z); y = phi (x, z)
-static bool PHIsEqualValue(PHINode *PN, Value *NonPhiInVal,
+static bool PHIsEqualValue(PHINode *PN, Value *&NonPhiInVal,
SmallPtrSetImpl<PHINode*> &ValueEqualPHIs) {
// See if we already saw this PHI node.
if (!ValueEqualPHIs.insert(PN).second)
@@ -1010,8 +1010,13 @@ static bool PHIsEqualValue(PHINode *PN, Value *NonPhiInVal,
// the value.
for (Value *Op : PN->incoming_values()) {
if (PHINode *OpPN = dyn_cast<PHINode>(Op)) {
- if (!PHIsEqualValue(OpPN, NonPhiInVal, ValueEqualPHIs))
- return false;
+ if (!PHIsEqualValue(OpPN, NonPhiInVal, ValueEqualPHIs)) {
+ if (NonPhiInVal)
+ return false;
+ else {
+ NonPhiInVal = OpPN;
+ }
+ }
} else if (Op != NonPhiInVal)
return false;
}
@@ -1478,7 +1483,9 @@ Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) {
// z = some value; x = phi (y, z); y = phi (x, z)
// where the phi nodes don't necessarily need to be in the same block. Do a
// quick check to see if the PHI node only contains a single non-phi value, if
- // so, scan to see if the phi cycle is actually equal to that value.
+ // so, scan to see if the phi cycle is actually equal to that value. If the
+ // phi has no non-phi values then allow the "NonPhiInVal" to be set later if
+ // one of the phis itself does not have a single input.
{
unsigned InValNo = 0, NumIncomingVals = PN.getNumIncomingValues();
// Scan for the first non-phi operand.
@@ -1486,25 +1493,25 @@ Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) {
isa<PHINode>(PN.getIncomingValue(InValNo)))
++InValNo;
- if (InValNo != NumIncomingVals) {
- Value *NonPhiInVal = PN.getIncomingValue(InValNo);
+ Value *NonPhiInVal =
+ InValNo != NumIncomingVals ? PN.getIncomingValue(InValNo) : nullptr;
- // Scan the rest of the operands to see if there are any conflicts, if so
- // there is no need to recursively scan other phis.
+ // Scan the rest of the operands to see if there are any conflicts, if so
+ // there is no need to recursively scan other phis.
+ if (NonPhiInVal)
for (++InValNo; InValNo != NumIncomingVals; ++InValNo) {
Value *OpVal = PN.getIncomingValue(InValNo);
if (OpVal != NonPhiInVal && !isa<PHINode>(OpVal))
break;
}
- // If we scanned over all operands, then we have one unique value plus
- // phi values. Scan PHI nodes to see if they all merge in each other or
- // the value.
- if (InValNo == NumIncomingVals) {
- SmallPtrSet<PHINode*, 16> ValueEqualPHIs;
- if (PHIsEqualValue(&PN, NonPhiInVal, ValueEqualPHIs))
- return replaceInstUsesWith(PN, NonPhiInVal);
- }
+ // If we scanned over all operands, then we have one unique value plus
+ // phi values. Scan PHI nodes to see if they all merge in each other or
+ // the value.
+ if (InValNo == NumIncomingVals) {
+ SmallPtrSet<PHINode*, 16> ValueEqualPHIs;
+ if (PHIsEqualValue(&PN, NonPhiInVal, ValueEqualPHIs))
+ return replaceInstUsesWith(PN, NonPhiInVal);
}
}
diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll
index a5cab8a71d3f711..710c99033394bdc 100644
--- a/llvm/test/Transforms/InstCombine/phi.ll
+++ b/llvm/test/Transforms/InstCombine/phi.ll
@@ -837,6 +837,60 @@ end:
ret i1 %z
}
+; Same as above, but the input is also a phi
+define i1 @test25b(i1 %ci, i64 %ai, i64 %bi) {
+; CHECK-LABEL: @test25b(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[CI:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: br label [[ELSE]]
+; CHECK: else:
+; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[AI:%.*]], [[ENTRY:%.*]] ], [ [[BI:%.*]], [[THEN]] ]
+; CHECK-NEXT: [[B:%.*]] = call i1 @test25a()
+; CHECK-NEXT: br i1 [[B]], label [[ONE:%.*]], label [[TWO:%.*]]
+; CHECK: one:
+; CHECK-NEXT: [[C:%.*]] = call i1 @test25a()
+; CHECK-NEXT: br i1 [[C]], label [[TWO]], label [[END:%.*]]
+; CHECK: two:
+; CHECK-NEXT: [[D:%.*]] = call i1 @test25a()
+; CHECK-NEXT: br i1 [[D]], label [[ONE]], label [[END]]
+; CHECK: end:
+; CHECK-NEXT: [[G:%.*]] = inttoptr i64 [[I]] to ptr
+; CHECK-NEXT: store i32 10, ptr [[G]], align 4
+; CHECK-NEXT: [[Z:%.*]] = call i1 @test25a()
+; CHECK-NEXT: ret i1 [[Z]]
+;
+entry:
+ br i1 %ci, label %then, label %else
+
+then:
+ br label %else
+
+else:
+ %i = phi i64 [ %ai, %entry ], [ %bi, %then ]
+ %b = call i1 @test25a()
+ br i1 %b, label %one, label %two
+
+one:
+ %x = phi i64 [%y, %two], [%i, %else]
+ %c = call i1 @test25a()
+ br i1 %c, label %two, label %end
+
+two:
+ %y = phi i64 [%x, %one], [%i, %else]
+ %d = call i1 @test25a()
+ br i1 %d, label %one, label %end
+
+end:
+ %f = phi i64 [ %x, %one], [%y, %two]
+ ; Change the %f to %i, and the optimizer suddenly becomes a lot smarter
+ ; even though %f must equal %i at this point
+ %g = inttoptr i64 %f to ptr
+ store i32 10, ptr %g
+ %z = call i1 @test25a()
+ ret i1 %z
+}
+
declare i1 @test26a()
define i1 @test26(i32 %n) {
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
543e8ea
to
b916ba5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
if (!PHIsEqualValue(OpPN, NonPhiInVal, ValueEqualPHIs)) { | ||
if (NonPhiInVal) | ||
return false; | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No else after return.
There is a combine in instcombine that will look for phi cycles that only have a single incoming value: %0 = phi i64 [ %3, %exit ], [ %othervalue, %preheader ] %3 = phi i64 [ %0, %body ], [ %othervalue, %body2 ] This currently doesn't handle if %othervalue is a phi though, as the algorithm will recurse into the phi and fail with multiple incoming values. This adjusts the algorithm, not requiring the initial value to be found immediately, allowing it to be set to the value of one of the phis that would otherwise fail due to having multiple input values.
b916ba5
to
7972e77
Compare
There is a combine in instcombine that will look for phi cycles that only have
a single incoming value:
This currently doesn't handle if %othervalue is a phi though, as the algorithm
will recurse into the phi and fail with multiple incoming values. This adjusts
the algorithm, not requiring the initial value to be found immediately,
allowing it to be set to the value of one of the phis that would otherwise fail
due to having multiple input values.