Skip to content

[SimplifyCFG] Improve FoldTwoEntryPHINode when one of phi values is undef #69021

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Oct 13, 2023

When converting select-like branches into a select, we can just use one phi value instead of creating a select if it is guaranteed not to be poison and another phi value is undef. After converting to select, we will lose information from the dominator tree.

Alive2: https://alive2.llvm.org/ce/z/rheXK4

Fixes #67342.

@llvmbot
Copy link
Member

llvmbot commented Oct 13, 2023

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

When converting select-like branches into a select, we can just use one phi value instead of creating a select if it is guaranteed not to be poison and another phi value is undef. After converting to select, we will lose information from the dominator tree.

Alive2: https://alive2.llvm.org/ce/z/rheXK4

Fixes #67342.


Full diff: https://github.com/llvm/llvm-project/pull/69021.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+16-3)
  • (added) llvm/test/Transforms/SimplifyCFG/pr67342.ll (+50)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 35fead111aa9666..bab5363e63a85eb 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3543,9 +3543,22 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI,
     Value *TrueVal = PN->getIncomingValueForBlock(IfTrue);
     Value *FalseVal = PN->getIncomingValueForBlock(IfFalse);
 
-    Value *Sel = Builder.CreateSelect(IfCond, TrueVal, FalseVal, "", DomBI);
-    PN->replaceAllUsesWith(Sel);
-    Sel->takeName(PN);
+    Value *ReplaceVal = nullptr;
+    if (isa<UndefValue>(TrueVal) &&
+        isGuaranteedNotToBePoison(FalseVal, /*AC*/ nullptr,
+                                  IfFalse->getTerminator(),
+                                  DTU ? &DTU->getDomTree() : nullptr, 0)) {
+      ReplaceVal = FalseVal;
+    } else if (isa<UndefValue>(FalseVal) &&
+               isGuaranteedNotToBePoison(
+                   TrueVal, /*AC*/ nullptr, IfFalse->getTerminator(),
+                   DTU ? &DTU->getDomTree() : nullptr, 0)) {
+      ReplaceVal = TrueVal;
+    } else {
+      ReplaceVal = Builder.CreateSelect(IfCond, TrueVal, FalseVal, "", DomBI);
+      ReplaceVal->takeName(PN);
+    }
+    PN->replaceAllUsesWith(ReplaceVal);
     PN->eraseFromParent();
   }
 
diff --git a/llvm/test/Transforms/SimplifyCFG/pr67342.ll b/llvm/test/Transforms/SimplifyCFG/pr67342.ll
new file mode 100644
index 000000000000000..c2c9f460d8e5f9e
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/pr67342.ll
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt -S -passes=simplifycfg < %s | FileCheck %s
+
+; Tests from PR67342
+define i16 @test1(i32 %err) {
+; CHECK-LABEL: define i16 @test1(
+; CHECK-SAME: i32 [[ERR:%.*]]) {
+; CHECK-NEXT:  bb3:
+; CHECK-NEXT:    [[_3:%.*]] = icmp slt i32 [[ERR]], 0
+; CHECK-NEXT:    [[OK:%.*]] = trunc i32 [[ERR]] to i16
+; CHECK-NEXT:    ret i16 [[OK]]
+;
+  %_3 = icmp slt i32 %err, 0
+  br i1 %_3, label %bb1, label %bb2
+
+bb2:
+  %ok = trunc i32 %err to i16
+  br label %bb3
+
+bb1:
+  br label %bb3
+
+bb3:
+  %r.sroa.3.0 = phi i16 [ undef, %bb1 ], [ %ok, %bb2 ]
+  ret i16 %r.sroa.3.0
+}
+
+; commuted test
+define i16 @test2(i32 %err) {
+; CHECK-LABEL: define i16 @test2(
+; CHECK-SAME: i32 [[ERR:%.*]]) {
+; CHECK-NEXT:  bb3:
+; CHECK-NEXT:    [[_3:%.*]] = icmp slt i32 [[ERR]], 0
+; CHECK-NEXT:    [[OK:%.*]] = trunc i32 [[ERR]] to i16
+; CHECK-NEXT:    ret i16 [[OK]]
+;
+  %_3 = icmp slt i32 %err, 0
+  br i1 %_3, label %bb1, label %bb2
+
+bb2:
+  br label %bb3
+
+bb1:
+  %ok = trunc i32 %err to i16
+  br label %bb3
+
+bb3:
+  %r.sroa.3.0 = phi i16 [ %ok, %bb1 ], [ undef, %bb2 ]
+  ret i16 %r.sroa.3.0
+}

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not allowed to use the DominatorTree inside SimplifyCFG, only to preserve it.

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Oct 23, 2023

Ping.

@nikic
Copy link
Contributor

nikic commented Oct 24, 2023

So this now works via programUndefinedIfPoison, which is going to make this quite fragile. It's going to work if this is the first branch in the function, but not in a later one.

Also, while #67342 reported this without the noundef attribute, the original in rust-lang/rust#116150 does have it, so I don't think you're even fixing the right issue here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missed optimization
3 participants