[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:12 PDT 2025
https://github.com/rkirsling updated https://github.com/llvm/llvm-project/pull/147676
>From c639d1c3b007fa16812fe4db8485c075babae113 Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Wed, 9 Jul 2025 18:00:43 +0900
Subject: [PATCH 1/2] [InstCombine] foldOpIntoPhi should apply to icmp with
non-constant operand
---
.../InstCombine/InstCombineCompares.cpp | 8 +-
.../fold-icmp-without-constant-into-phi.ll | 98 +++++++++++++++++++
2 files changed, 102 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c6f317a668cfe..e753af73886f3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4305,10 +4305,6 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstantNotInt(ICmpInst &I) {
return nullptr;
switch (LHSI->getOpcode()) {
- case Instruction::PHI:
- if (Instruction *NV = foldOpIntoPhi(I, cast<PHINode>(LHSI)))
- return NV;
- break;
case Instruction::IntToPtr:
// icmp pred inttoptr(X), null -> icmp pred X, 0
if (RHSC->isNullValue() &&
@@ -7699,6 +7695,10 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
if (Instruction *New = foldSignBitTest(I))
return New;
+ if (auto *PN = dyn_cast<PHINode>(Op0))
+ if (Instruction *NV = foldOpIntoPhi(I, PN))
+ return NV;
+
if (Instruction *Res = foldICmpInstWithConstantNotInt(I))
return Res;
diff --git a/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll b/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
new file mode 100644
index 0000000000000..7c0c1a39d00f7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
@@ -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
+ br label %end
+
+end:
+ %result = phi i1 [ false, %cond.true ], [ %false, %cond.false ]
+ ret i1 %result
+}
>From a95585b20d7d0b5545530b3a4a8ef068c98c8bdd Mon Sep 17 00:00:00 2001
From: Ross Kirsling <ross.kirsling at sony.com>
Date: Wed, 9 Jul 2025 20:16:00 +0900
Subject: [PATCH 2/2] Address feedback.
---
.../InstCombine/InstCombineCompares.cpp | 3 +
.../fold-icmp-without-constant-into-phi.ll | 61 +++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index e753af73886f3..9df08553d86e4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7698,6 +7698,9 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
if (auto *PN = dyn_cast<PHINode>(Op0))
if (Instruction *NV = foldOpIntoPhi(I, PN))
return NV;
+ if (auto *PN = dyn_cast<PHINode>(Op1))
+ if (Instruction *NV = foldOpIntoPhi(I, PN))
+ return NV;
if (Instruction *Res = foldICmpInstWithConstantNotInt(I))
return Res;
diff --git a/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll b/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
index 7c0c1a39d00f7..f037ba2b65bc9 100644
--- a/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
+++ b/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll
@@ -31,6 +31,36 @@ end:
ret i1 %result
}
+define i1 @test_commuted(i1 %cond, i64 %left, i64 %right) {
+; CHECK-LABEL: define i1 @test_commuted(
+; 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 slt i64 %left, %left_or_right
+ 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:%.*]]) {
@@ -96,3 +126,34 @@ end:
%result = phi i1 [ false, %cond.true ], [ %false, %cond.false ]
ret i1 %result
}
+
+define i1 @test_which_optimizes_to_select(i1 %cond, i64 %left, i64 %right) {
+; CHECK-LABEL: define i1 @test_which_folds_to_a_select(
+; 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_NOT:%.*]] = icmp sgt i64 [[RIGHT]], [[LEFT]]
+; CHECK-NEXT: br i1 [[CMP_NOT]], label %[[COND_FALSE]], label %[[END:.*]]
+; CHECK: [[COND_FALSE]]:
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[COND_TRUE]] ], [ [[COND]], %[[COND_FALSE]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+start:
+ br i1 %cond, label %cond.true, label %cond.false
+
+cond.true:
+ %cmp = icmp sle 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
+}
More information about the llvm-commits
mailing list