Index: llvm/trunk/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/trunk/lib/Analysis/ValueTracking.cpp +++ llvm/trunk/lib/Analysis/ValueTracking.cpp @@ -4604,23 +4604,35 @@ 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))))) { - // Set RHS to the negate operand. LHS was assigned to CmpLHS earlier. - RHS = (CmpLHS == TrueVal) ? FalseVal : TrueVal; + // 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(m_Specific(TrueVal)))) || + (match(FalseVal, MaybeSExtLHS) && + match(TrueVal, m_Neg(m_Specific(FalseVal))))) { + // Set LHS and RHS so that RHS is the negated operand of the select + if (match(TrueVal, MaybeSExtLHS)) { + LHS = TrueVal; + RHS = FalseVal; + } else { + LHS = FalseVal; + RHS = 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 {(LHS == TrueVal) ? 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 {(LHS == FalseVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false}; } } } Index: llvm/trunk/test/Transforms/LoopIdiom/ARM/ctlz.ll =================================================================== --- llvm/trunk/test/Transforms/LoopIdiom/ARM/ctlz.ll +++ llvm/trunk/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: llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll =================================================================== --- llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll +++ llvm/trunk/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