Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -4604,23 +4604,31 @@ const APInt *C1; if (match(CmpRHS, m_APInt(C1))) { - if ((CmpLHS == TrueVal && match(FalseVal, m_Neg(m_Specific(CmpLHS)))) || - (CmpLHS == FalseVal && match(TrueVal, m_Neg(m_Specific(CmpLHS))))) { + // Sign-extending LHS does not change its sign, so TrueVal/FalseVal can + // match against either LHS or sext(LHS). + auto MaybeSExtLHS = m_CombineOr(m_Specific(CmpLHS), + m_SExt(m_Specific(CmpLHS))); + if ((match(TrueVal, MaybeSExtLHS) && + match(FalseVal, m_Neg(MaybeSExtLHS))) || + (match(FalseVal, MaybeSExtLHS) && + match(TrueVal, m_Neg(MaybeSExtLHS)))) { + bool LHSIsTrueVal = match(TrueVal, MaybeSExtLHS); + // Set RHS to the negate operand. LHS was assigned to CmpLHS earlier. - RHS = (CmpLHS == TrueVal) ? FalseVal : TrueVal; + RHS = LHSIsTrueVal ? FalseVal : TrueVal; // ABS(X) ==> (X >s 0) ? X : -X and (X >s -1) ? X : -X // NABS(X) ==> (X >s 0) ? -X : X and (X >s -1) ? -X : X if (Pred == ICmpInst::ICMP_SGT && (C1->isNullValue() || C1->isAllOnesValue())) { - return {(CmpLHS == TrueVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false}; + return {LHSIsTrueVal ? SPF_ABS : SPF_NABS, SPNB_NA, false}; } // ABS(X) ==> (X (X isNullValue() || C1->isOneValue())) { - return {(CmpLHS == FalseVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false}; + return {!LHSIsTrueVal ? SPF_ABS : SPF_NABS, SPNB_NA, false}; } } } Index: test/Transforms/LoopIdiom/ARM/ctlz.ll =================================================================== --- test/Transforms/LoopIdiom/ARM/ctlz.ll +++ test/Transforms/LoopIdiom/ARM/ctlz.ll @@ -199,3 +199,48 @@ while.end: ; preds = %while.cond ret i32 %i.0 } + +; Recognize CTLZ builtin pattern. +; Here it will replace the loop - +; assume builtin is always profitable. +; +; int ctlz_sext(short in) +; { +; int n = in; +; if (in < 0) +; n = -n; +; int i = 0; +; while(n >>= 1) { +; i++; +; } +; return i; +; } +; +; ALL: entry +; ALL: %0 = ashr i32 %abs_n, 1 +; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) +; ALL-NEXT: %2 = sub i32 32, %1 +; ALL-NEXT: %3 = add i32 %2, 1 +; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ] +; ALL: ret i32 %i.0.lcssa + +; Function Attrs: norecurse nounwind readnone uwtable +define i32 @ctlz_sext(i16 %in) { +entry: + %n = sext i16 %in to i32 + %c = icmp sgt i16 %in, 0 + %negn = sub nsw i32 0, %n + %abs_n = select i1 %c, i32 %n, i32 %negn + br label %while.cond + +while.cond: ; preds = %while.cond, %entry + %n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ] + %shr = ashr i32 %n.addr.0, 1 + %tobool = icmp eq i32 %shr, 0 + %inc = add nsw i32 %i.0, 1 + br i1 %tobool, label %while.end, label %while.cond + +while.end: ; preds = %while.cond + ret i32 %i.0 +} Index: test/Transforms/LoopIdiom/X86/ctlz.ll =================================================================== --- test/Transforms/LoopIdiom/X86/ctlz.ll +++ test/Transforms/LoopIdiom/X86/ctlz.ll @@ -200,6 +200,51 @@ ret i32 %i.0 } +; Recognize CTLZ builtin pattern. +; Here it will replace the loop - +; assume builtin is always profitable. +; +; int ctlz_sext(short in) +; { +; int n = in; +; if (in < 0) +; n = -n; +; int i = 0; +; while(n >>= 1) { +; i++; +; } +; return i; +; } +; +; ALL: entry +; ALL: %0 = ashr i32 %abs_n, 1 +; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) +; ALL-NEXT: %2 = sub i32 32, %1 +; ALL-NEXT: %3 = add i32 %2, 1 +; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ] +; ALL: ret i32 %i.0.lcssa + +; Function Attrs: norecurse nounwind readnone uwtable +define i32 @ctlz_sext(i16 %in) { +entry: + %n = sext i16 %in to i32 + %c = icmp sgt i16 %in, 0 + %negn = sub nsw i32 0, %n + %abs_n = select i1 %c, i32 %n, i32 %negn + br label %while.cond + +while.cond: ; preds = %while.cond, %entry + %n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ] + %shr = ashr i32 %n.addr.0, 1 + %tobool = icmp eq i32 %shr, 0 + %inc = add nsw i32 %i.0, 1 + br i1 %tobool, label %while.end, label %while.cond + +while.end: ; preds = %while.cond + ret i32 %i.0 +} + ; This loop contains a volatile store. If x is initially negative, ; the code will be an infinite loop because the ashr will eventually produce ; all ones and continue doing so. This prevents the loop from terminating. If