[llvm] r336509 - [LoopIdiomRecognize] Support for converting loops that use LSHR to CTLZ.
Wei Mi via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 11 13:43:29 PDT 2018
Hi,
We run into a SEGV in a testcase. Here is a reproducible. Please take a
look.
----------- 1.cc -------------
unsigned foo(unsigned input) {
unsigned num = 0;
do {
++num;
input >>= 1;
} while (input != 0);
return num;
}
int main() {
__builtin_printf("%u\n", foo(0));
}
---------------------------------
~/workarea/llvm-r336508/rbuild/bin/clang -O2 1.cc -o good.out; ./good.out
1
~/workarea/llvm-r336509/rbuild/bin/clang -O2 1.cc -o bad.out; ./bad.out
0
Thanks,
Wei.
On Sat, Jul 7, 2018 at 6:45 PM, Craig Topper via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: ctopper
> Date: Sat Jul 7 18:45:47 2018
> New Revision: 336509
>
> URL: http://llvm.org/viewvc/llvm-project?rev=336509&view=rev
> Log:
> [LoopIdiomRecognize] Support for converting loops that use LSHR to CTLZ.
>
> In the 'detectCTLZIdiom' function support for loops that use LSHR
> instruction instead of ASHR has been added.
>
> This supports creating ctlz from the following code.
>
> int lzcnt(int x) {
> int count = 0;
> while (x > 0) {
> count++;
> x = x >> 1;
> }
> return count;
> }
>
> Patch by Olga Moldovanova
>
> Differential Revision: https://reviews.llvm.org/D48354
>
> Modified:
> llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
> llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll
>
> Modified: llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/
> LoopIdiomRecognize.cpp?rev=336509&r1=336508&r2=336509&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/LoopIdiomRecognize.cpp Sat Jul 7
> 18:45:47 2018
> @@ -188,8 +188,9 @@ private:
> PHINode *CntPhi, Value *Var);
> bool recognizeAndInsertCTLZ();
> void transformLoopToCountable(BasicBlock *PreCondBB, Instruction
> *CntInst,
> - PHINode *CntPhi, Value *Var, const
> DebugLoc &DL,
> - bool ZeroCheck, bool
> IsCntPhiUsedOutsideLoop);
> + PHINode *CntPhi, Value *Var, Instruction
> *DefX,
> + const DebugLoc &DL, bool ZeroCheck,
> + bool IsCntPhiUsedOutsideLoop);
>
> /// @}
> };
> @@ -1316,8 +1317,8 @@ static bool detectCTLZIdiom(Loop *CurLoo
> return false;
>
> // step 2: detect instructions corresponding to "x.next = x >> 1"
> - // TODO: Support loops that use LShr.
> - if (!DefX || DefX->getOpcode() != Instruction::AShr)
> + if (!DefX || (DefX->getOpcode() != Instruction::AShr &&
> + DefX->getOpcode() != Instruction::LShr))
> return false;
> ConstantInt *Shft = dyn_cast<ConstantInt>(DefX->getOperand(1));
> if (!Shft || !Shft->isOne())
> @@ -1401,8 +1402,7 @@ bool LoopIdiomRecognize::recognizeAndIns
>
> // Make sure the initial value can't be negative otherwise the ashr in
> the
> // loop might never reach zero which would make the loop infinite.
> - // TODO: Support loops that use lshr and wouldn't need this check.
> - if (!isKnownNonNegative(InitX, *DL))
> + if (DefX->getOpcode() == Instruction::AShr &&
> !isKnownNonNegative(InitX, *DL))
> return false;
>
> // If we check X != 0 before entering the loop we don't need a zero
> @@ -1433,8 +1433,9 @@ bool LoopIdiomRecognize::recognizeAndIns
> TargetTransformInfo::TCC_Basic)
> return false;
>
> - transformLoopToCountable(PH, CntInst, CntPhi, InitX,
> DefX->getDebugLoc(),
> - ZeroCheck, IsCntPhiUsedOutsideLoop);
> + transformLoopToCountable(PH, CntInst, CntPhi, InitX, DefX,
> + DefX->getDebugLoc(), ZeroCheck,
> + IsCntPhiUsedOutsideLoop);
> return true;
> }
>
> @@ -1547,7 +1548,8 @@ static CallInst *createCTLZIntrinsic(IRB
> /// If CntInst and DefX are not used in LOOP_BODY they will be removed.
> void LoopIdiomRecognize::transformLoopToCountable(
> BasicBlock *Preheader, Instruction *CntInst, PHINode *CntPhi, Value
> *InitX,
> - const DebugLoc &DL, bool ZeroCheck, bool IsCntPhiUsedOutsideLoop) {
> + Instruction *DefX, const DebugLoc &DL, bool ZeroCheck,
> + bool IsCntPhiUsedOutsideLoop) {
> BranchInst *PreheaderBr = cast<BranchInst>(Preheader->getTerminator());
>
> // Step 1: Insert the CTLZ instruction at the end of the preheader block
> @@ -1558,10 +1560,16 @@ void LoopIdiomRecognize::transformLoopTo
> Builder.SetCurrentDebugLocation(DL);
> Value *CTLZ, *Count, *CountPrev, *NewCount, *InitXNext;
>
> - if (IsCntPhiUsedOutsideLoop)
> - InitXNext = Builder.CreateAShr(InitX,
> - ConstantInt::get(InitX->getType(),
> 1));
> - else
> + if (IsCntPhiUsedOutsideLoop) {
> + if (DefX->getOpcode() == Instruction::AShr)
> + InitXNext =
> + Builder.CreateAShr(InitX, ConstantInt::get(InitX->getType(),
> 1));
> + else if (DefX->getOpcode() == Instruction::LShr)
> + InitXNext =
> + Builder.CreateLShr(InitX, ConstantInt::get(InitX->getType(),
> 1));
> + else
> + llvm_unreachable("Unexpected opcode!");
> + } else
> InitXNext = InitX;
> CTLZ = createCTLZIntrinsic(Builder, InitXNext, DL, ZeroCheck);
> Count = Builder.CreateSub(
>
> Modified: llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/
> Transforms/LoopIdiom/X86/ctlz.ll?rev=336509&r1=336508&r2=336509&view=diff
> ============================================================
> ==================
> --- llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll (original)
> +++ llvm/trunk/test/Transforms/LoopIdiom/X86/ctlz.ll Sat Jul 7 18:45:47
> 2018
> @@ -119,6 +119,52 @@ while.end:
> ; Here it will replace the loop -
> ; assume builtin is always profitable.
> ;
> +; int ctlz_zero_check_lshr(int n)
> +; {
> +; int i = 0;
> +; while(n) {
> +; n >>= 1;
> +; i++;
> +; }
> +; return i;
> +; }
> +;
> +; ALL: entry
> +; ALL: %0 = call i32 @llvm.ctlz.i32(i32 %n, i1 true)
> +; ALL-NEXT: %1 = sub i32 32, %0
> +; ALL: %inc.lcssa = phi i32 [ %1, %while.body ]
> +; ALL: %i.0.lcssa = phi i32 [ 0, %entry ], [ %inc.lcssa,
> %while.end.loopexit ]
> +; ALL: ret i32 %i.0.lcssa
> +
> +; Function Attrs: norecurse nounwind readnone uwtable
> +define i32 @ctlz_zero_check_lshr(i32 %n) {
> +entry:
> + %tobool4 = icmp eq i32 %n, 0
> + br i1 %tobool4, label %while.end, label %while.body.preheader
> +
> +while.body.preheader: ; preds = %entry
> + br label %while.body
> +
> +while.body: ; preds =
> %while.body.preheader, %while.body
> + %i.06 = phi i32 [ %inc, %while.body ], [ 0, %while.body.preheader ]
> + %n.addr.05 = phi i32 [ %shr, %while.body ], [ %n, %while.body.preheader
> ]
> + %shr = lshr i32 %n.addr.05, 1
> + %inc = add nsw i32 %i.06, 1
> + %tobool = icmp eq i32 %shr, 0
> + br i1 %tobool, label %while.end.loopexit, label %while.body
> +
> +while.end.loopexit: ; preds = %while.body
> + br label %while.end
> +
> +while.end: ; preds =
> %while.end.loopexit, %entry
> + %i.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.end.loopexit ]
> + ret i32 %i.0.lcssa
> +}
> +
> +; Recognize CTLZ builtin pattern.
> +; Here it will replace the loop -
> +; assume builtin is always profitable.
> +;
> ; int ctlz(int n)
> ; {
> ; n = n >= 0 ? n : -n;
> @@ -161,6 +207,44 @@ while.end:
> ; Here it will replace the loop -
> ; assume builtin is always profitable.
> ;
> +; int ctlz_lshr(int n)
> +; {
> +; int i = 0;
> +; while(n >>= 1) {
> +; i++;
> +; }
> +; return i;
> +; }
> +;
> +; ALL: entry
> +; ALL: %0 = lshr i32 %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_lshr(i32 %n) {
> +entry:
> + br label %while.cond
> +
> +while.cond: ; preds = %while.cond,
> %entry
> + %n.addr.0 = phi i32 [ %n, %entry ], [ %shr, %while.cond ]
> + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ]
> + %shr = lshr 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
> +}
> +
> +; Recognize CTLZ builtin pattern.
> +; Here it will replace the loop -
> +; assume builtin is always profitable.
> +;
> ; int ctlz_add(int n, int i0)
> ; {
> ; n = n >= 0 ? n : -n;
> @@ -204,6 +288,45 @@ while.end:
> ; Here it will replace the loop -
> ; assume builtin is always profitable.
> ;
> +; int ctlz_add_lshr(int n, int i0)
> +; {
> +; int i = i0;
> +; while(n >>= 1) {
> +; i++;
> +; }
> +; return i;
> +; }
> +;
> +; ALL: entry
> +; ALL: %0 = lshr i32 %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-NEXT: %4 = add i32 %2, %i0
> +; ALL: %i.0.lcssa = phi i32 [ %4, %while.cond ]
> +; ALL: ret i32 %i.0.lcssa
> +;
> +; Function Attrs: norecurse nounwind readnone uwtable
> +define i32 @ctlz_add_lshr(i32 %n, i32 %i0) {
> +entry:
> + br label %while.cond
> +
> +while.cond: ; preds = %while.cond,
> %entry
> + %n.addr.0 = phi i32 [ %n, %entry ], [ %shr, %while.cond ]
> + %i.0 = phi i32 [ %i0, %entry ], [ %inc, %while.cond ]
> + %shr = lshr 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
> +}
> +
> +; Recognize CTLZ builtin pattern.
> +; Here it will replace the loop -
> +; assume builtin is always profitable.
> +;
> ; int ctlz_sext(short in)
> ; {
> ; int n = in;
> @@ -240,6 +363,45 @@ while.cond:
> %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
> +}
> +
> +; Recognize CTLZ builtin pattern.
> +; Here it will replace the loop -
> +; assume builtin is always profitable.
> +;
> +; int ctlz_sext_lshr(short in)
> +; {
> +; int i = 0;
> +; while(in >>= 1) {
> +; i++;
> +; }
> +; return i;
> +; }
> +;
> +; ALL: entry
> +; ALL: %0 = lshr i32 %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_lshr(i16 %in) {
> +entry:
> + %n = sext i16 %in to i32
> + br label %while.cond
> +
> +while.cond: ; preds = %while.cond,
> %entry
> + %n.addr.0 = phi i32 [ %n, %entry ], [ %shr, %while.cond ]
> + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ]
> + %shr = lshr 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
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180711/20480348/attachment.html>
More information about the llvm-commits
mailing list