[llvm] [InstCombine] foldOpIntoPhi should apply to icmp with non-constant operand (PR #147676)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 9 02:10:37 PDT 2025
================
@@ -0,0 +1,98 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @test(i1 %cond, i64 %left, i64 %right) {
+; CHECK-LABEL: define i1 @test(
+; CHECK-SAME: i1 [[COND:%.*]], i64 [[LEFT:%.*]], i64 [[RIGHT:%.*]]) {
+; CHECK-NEXT: [[START:.*:]]
+; CHECK-NEXT: br i1 [[COND]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[RIGHT]], [[LEFT]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[END:.*]], label %[[COND_FALSE]]
+; CHECK: [[COND_FALSE]]:
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: ret i1 false
+;
+start:
+ br i1 %cond, label %cond.true, label %cond.false
+
+cond.true:
+ %cmp = icmp sgt i64 %right, %left
+ br i1 %cmp, label %end, label %cond.false
+
+cond.false:
+ %left_or_right = phi i64 [ %left, %start ], [ %right, %cond.true ]
+ %false = icmp sgt i64 %left_or_right, %left
+ br label %end
+
+end:
+ %result = phi i1 [ false, %cond.true ], [ %false, %cond.false ]
+ ret i1 %result
+}
+
+define i1 @test_with_wrong_icmp(i1 %cond, i64 %left, i64 %right) {
+; CHECK-LABEL: define i1 @test_with_wrong_icmp(
+; CHECK-SAME: i1 [[COND:%.*]], i64 [[LEFT:%.*]], i64 [[RIGHT:%.*]]) {
+; CHECK-NEXT: [[START:.*]]:
+; CHECK-NEXT: br i1 [[COND]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[RIGHT]], [[LEFT]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[END:.*]], label %[[COND_FALSE]]
+; CHECK: [[COND_FALSE]]:
+; CHECK-NEXT: [[LEFT_OR_RIGHT:%.*]] = phi i64 [ [[LEFT]], %[[START]] ], [ [[RIGHT]], %[[COND_TRUE]] ]
+; CHECK-NEXT: [[FALSE:%.*]] = icmp sge i64 [[LEFT_OR_RIGHT]], [[LEFT]]
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[COND_TRUE]] ], [ [[FALSE]], %[[COND_FALSE]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ br i1 %cond, label %cond.true, label %cond.false
+
+cond.true:
+ %cmp = icmp sgt i64 %right, %left
+ br i1 %cmp, label %end, label %cond.false
+
+cond.false:
+ %left_or_right = phi i64 [ %left, %start ], [ %right, %cond.true ]
+ %false = icmp sge i64 %left_or_right, %left
+ br label %end
+
+end:
+ %result = phi i1 [ false, %cond.true ], [ %false, %cond.false ]
+ ret i1 %result
+}
+
+define i1 @test_with_unfoldable_phi(i1 %cond, i64 %left, i64 %right) {
+; CHECK-LABEL: define i1 @test_with_unfoldable_phi(
+; CHECK-SAME: i1 [[COND:%.*]], i64 [[LEFT:%.*]], i64 [[RIGHT:%.*]]) {
+; CHECK-NEXT: [[START:.*]]:
+; CHECK-NEXT: br i1 [[COND]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[RIGHT]], [[LEFT]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[END:.*]], label %[[COND_FALSE]]
+; CHECK: [[COND_FALSE]]:
+; CHECK-NEXT: [[LEFT_OR_RIGHT:%.*]] = phi i64 [ [[LEFT]], %[[START]] ], [ [[RIGHT]], %[[COND_TRUE]] ]
+; CHECK-NEXT: [[FALSE:%.*]] = icmp sgt i64 [[LEFT_OR_RIGHT]], [[LEFT]]
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[COND_TRUE]] ], [ [[FALSE]], %[[COND_FALSE]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ br i1 %cond, label %cond.true, label %cond.false
+
+cond.true:
+ %cmp = icmp slt i64 %right, %left ; slt instead of sgt here
+ br i1 %cmp, label %end, label %cond.false
+
+cond.false:
+ %left_or_right = phi i64 [ %left, %start ], [ %right, %cond.true ]
+ %false = icmp sgt i64 %left_or_right, %left
----------------
nikic wrote:
I wonder why this case doesn't fold. I'd expect one of the phi operands to become false and the other to be the result of moving the icmp up into the cond.true block.
https://github.com/llvm/llvm-project/pull/147676
More information about the llvm-commits
mailing list