[llvm] [InstCombine] foldOpIntoPhi should apply to icmp with non-constant operand (PR #147676)
Ross Kirsling via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 9 04:16:21 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
----------------
rkirsling wrote:
Hmm, there is such folding for `sle`, but my aim in choosing `slt` was that it wouldn't be so easy to reason about whether `%right` is in fact greater than `%left`.
With `-passes=instcombine`:
```
define i1 @test(i1 %cond, i64 %left, i64 %right) {
start:
br i1 %cond, label %cond.true, label %cond.false
cond.true: ; preds = %start
%cmp.not = icmp sgt i64 %right, %left
br i1 %cmp.not, label %cond.false, label %end
cond.false: ; preds = %cond.true, %start
br label %end
end: ; preds = %cond.false, %cond.true
%result = phi i1 [ false, %cond.true ], [ %cond, %cond.false ]
ret i1 %result
}
```
With `-Os`:
```
define i1 @src(i1 %cond, i64 %left, i64 %right) local_unnamed_addr #0 {
start:
%cmp.not = icmp sgt i64 %right, %left
%spec.select = select i1 %cond, i1 %cmp.not, i1 false
ret i1 %spec.select
}
```
https://github.com/llvm/llvm-project/pull/147676
More information about the llvm-commits
mailing list