[LLVMdev] readonly and infinite loops
Daniel Berlin
dberlin at dberlin.org
Thu Jul 9 13:32:36 PDT 2015
I guess it's also worth pointing out that 9 years ago in GCC, starting
to do this instead of treating all infinite loops as "always exiting"
cost 3% geomean on SPEC.
(How useful this is as a measure for LLVM, no idea :P)
On Thu, Jul 9, 2015 at 1:26 PM, Daniel Berlin <dberlin at dberlin.org> wrote:
> This is going to be pretty annoying.
> At the *LLVM IR* level, i'm not aware of us having guarantees that
> match the C/C++ standard rules.
> If we do, i don't see them documented :)
>
> Unless someone shows me different, this looks legal at the LLVM IR,
> and thus, a but in clang for generating LLVM ir that doesn't represent
> the semantics of hte language properly :)
>
> (I'm half-joking)
>
> Note at the LLVM IR level, t he only way to deal with this in general
> would be to mark every loop that has a non-computable set of bounds as
> maybe infinite.
> Then, using metadata that contains the set of rules or something, mark
> as finite those that meet those rules (ie it contains no volatile
> loads, and ... and ... etc).
>
> Note that execution and termination are, as sanjoy demonstrates, two
> separate issues completely.
>
> Given a program that says:
>
> while (a)
> volatile load
>
> while (b)
> nothing special
>
>
>
> The second loop is guaranteed to terminate in C++, but not guaranteed
> to *execute*.
>
> Unless the standard believes that termination implies execution as
> well ( (i can't find it anwhere) )
>
>
>
>
>
> On Thu, Jul 9, 2015 at 12:29 PM, Sanjoy Das
> <sanjoy at playingwithpointers.com> wrote:
>> Here's a fun spin on this same topic (I can't file a bug at this
>> moment since llvm.org is down).
>>
>> Consider:
>>
>> define i32 @x(i32* %x, i1* %y) {
>> entry:
>> br label %loop
>>
>> loop:
>> %v = phi i32 [ 0 , %entry ], [ %v.inc, %exit.inner ], [ %v, %loop ]
>> %c = load volatile i1, i1* %y
>> br i1 %c, label %exit.inner, label %loop
>>
>> exit.inner:
>> %c1 = load volatile i1, i1* %y
>> %x.val = load i32, i32* %x
>> %v.inc = add i32 %v, %x.val
>> br i1 %c1, label %exit.real, label %loop
>>
>> exit.real:
>> ret i32 %v
>> }
>>
>> Now if %c is false every time, %x is never dereferenced. Since this
>> is an infinitely looping program that does a volatile load in every
>> iteration, it is well defined (going by what Hal said).
>>
>> However, opt -licm transforms this to
>>
>> ; ModuleID = '/Users/sanjoy/tmp/inf.ll'
>>
>> define i32 @x(i32* %x, i1* %y) {
>> entry:
>> %x.val = load i32, i32* %x
>> br label %loop.outer
>>
>> loop.outer: ; preds = %exit.inner, %entry
>> %v.ph = phi i32 [ %v.inc, %exit.inner ], [ 0, %entry ]
>> br label %loop
>>
>> loop: ; preds = %loop.outer, %loop
>> %c = load volatile i1, i1* %y
>> br i1 %c, label %exit.inner, label %loop
>>
>> exit.inner: ; preds = %loop
>> %c1 = load volatile i1, i1* %y
>> %v.inc = add i32 %v.ph, %x.val
>> br i1 %c1, label %exit.real, label %loop.outer
>>
>> exit.real: ; preds = %exit.inner
>> %v.ph.lcssa = phi i32 [ %v.ph, %exit.inner ]
>> ret i32 %v.ph.lcssa
>> }
>>
>> where it unconditionally dereferences %x, effectively introducing UB
>> if %x is not dereferenceable.
>>
>>
>> The bug is in isGuaranteedToExecute. It assumes that if an
>> instruction dominates all the loop exits then it will always be
>> executed by the loop "on its way out". But there may never be a way
>> out of the loop.
>>
>> -- Sanjoy
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
More information about the llvm-dev
mailing list