diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -2416,11 +2416,19 @@ static bool hoistMinMax(Instruction &I, Loop &L, ICFLoopSafetyInfo &SafetyInfo, MemorySSAUpdater &MSSAU) { bool Inverse = false; + bool IsLogical = false; using namespace PatternMatch; Value *Cond1, *Cond2; if (match(&I, m_Or(m_Value(Cond1), m_Value(Cond2)))) Inverse = true; - else if (!match(&I, m_And(m_Value(Cond1), m_Value(Cond2)))) + else if (match(&I, m_LogicalOr(m_Value(Cond1), m_Value(Cond2)))) { + Inverse = true; + IsLogical = true; + } else if (match(&I, m_And(m_Value(Cond1), m_Value(Cond2)))) { + // Do nothing + } else if (match(&I, m_LogicalAnd(m_Value(Cond1), m_Value(Cond2)))) + IsLogical = true; + else return false; auto MatchICmpAgainstInvariant = [&](Value *C, ICmpInst::Predicate &P, @@ -2460,6 +2468,12 @@ auto *Preheader = L.getLoopPreheader(); assert(Preheader && "Loop is not in simplify form?"); IRBuilder<> Builder(Preheader->getTerminator()); + // We are about to create a new guaranteed use for RHS2 which might not exist + // before (if it was a non-taken input of logical and/or instruction). If it + // was poison, we need to freeze it. Note that no new use for LHS and RHS1 are + // introduced, so they don't need this. + if (IsLogical) + RHS2 = Builder.CreateFreeze(RHS2, RHS2->getName() + ".fr"); Value *NewRHS = Builder.CreateBinaryIntrinsic( id, RHS1, RHS2, nullptr, StringRef("invariant.") + (ICmpInst::isSigned(P1) ? "s" : "u") + diff --git a/llvm/test/Transforms/LICM/min_max.ll b/llvm/test/Transforms/LICM/min_max.ll --- a/llvm/test/Transforms/LICM/min_max.ll +++ b/llvm/test/Transforms/LICM/min_max.ll @@ -752,17 +752,17 @@ ret i32 %iv } -; TODO: inv_2 needs freeze because hoisted umax would create a new use that didn't exist before. +; inv_2 needs freeze because hoisted umax would create a new use that didn't exist before. ; Counter-example: %cmp_1 = false, %inv_2 = poison. define i32 @test_logical_and_ult_needs_freeze(i32 %start, i32 %inv_1, i32 %inv_2) { ; CHECK-LABEL: @test_logical_and_ult_needs_freeze( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[INV_2_FR:%.*]] = freeze i32 [[INV_2:%.*]] +; CHECK-NEXT: [[INVARIANT_UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[INV_1:%.*]], i32 [[INV_2_FR]]) ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CMP_1:%.*]] = icmp ult i32 [[IV]], [[INV_1:%.*]] -; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[IV]], [[INV_2:%.*]] -; CHECK-NEXT: [[LOOP_COND:%.*]] = select i1 [[CMP_1]], i1 [[CMP_2]], i1 false +; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV]], [[INVARIANT_UMIN]] ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: @@ -784,17 +784,17 @@ ret i32 %iv } -; TODO: turn to %iv