Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4861,15 +4861,23 @@ // (X >s Y) ? 0 : Z ==> (Z >s 0) ? 0 : Z ==> SMIN(Z, 0) // (X (Z SMAX(Z, 0) if (match(TrueVal, m_Zero()) && - match(FalseVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) + match(FalseVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) { + // Skip degenerate X - 0 to avoid InstCombine min/max canonicalization loop. + if (match(CmpRHS, m_Zero())) + return {SPF_UNKNOWN, SPNB_NA, false}; return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false}; + } // Z = X -nsw Y // (X >s Y) ? Z : 0 ==> (Z >s 0) ? Z : 0 ==> SMAX(Z, 0) // (X (Z SMIN(Z, 0) if (match(FalseVal, m_Zero()) && - match(TrueVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) + match(TrueVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) { + // Skip degenerate X - 0 to avoid InstCombine min/max canonicalization loop. + if (match(CmpRHS, m_Zero())) + return {SPF_UNKNOWN, SPNB_NA, false}; return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false}; + } const APInt *C1; if (!match(CmpRHS, m_APInt(C1))) Index: llvm/test/Transforms/InstCombine/pr44541.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/pr44541.ll @@ -0,0 +1,25 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instcombine -expensive-combines=0 -instcombine-infinite-loop-threshold=3 < %s | FileCheck %s + +; This test used to cause an infinite combine loop. + +define i16 @passthru(i16 returned %x) { +; CHECK-LABEL: @passthru( +; CHECK-NEXT: ret i16 [[X:%.*]] +; + ret i16 %x +} + +define i16 @test(i16 %arg) { +; CHECK-LABEL: @test( +; CHECK-NEXT: [[ZERO:%.*]] = call i16 @passthru(i16 0) +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i16 [[ARG:%.*]], 0 +; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP1]], i16 [[ARG]], i16 0 +; CHECK-NEXT: ret i16 [[RET]] +; + %zero = call i16 @passthru(i16 0) + %sub = sub nuw nsw i16 %arg, %zero + %cmp = icmp slt i16 %sub, 0 + %ret = select i1 %cmp, i16 0, i16 %sub + ret i16 %ret +}