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