diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index c6f317a668cfe..9df08553d86e4 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(LHSI))) - return NV; - break; case Instruction::IntToPtr: // icmp pred inttoptr(X), null -> icmp pred X, 0 if (RHSC->isNullValue() && @@ -7699,6 +7695,13 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) { if (Instruction *New = foldSignBitTest(I)) return New; + if (auto *PN = dyn_cast(Op0)) + if (Instruction *NV = foldOpIntoPhi(I, PN)) + return NV; + if (auto *PN = dyn_cast(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 new file mode 100644 index 0000000000000..73fb93f3c9d3b --- /dev/null +++ b/llvm/test/Transforms/InstCombine/fold-icmp-without-constant-into-phi.ll @@ -0,0 +1,159 @@ +; 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_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:%.*]]) { +; 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 +} + +define i1 @test_which_optimizes_to_select(i1 %cond, i64 %left, i64 %right) { +; CHECK-LABEL: define i1 @test_which_optimizes_to_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 +}