[LLVMdev] Does nounwind have semantics?

Kuperstein, Michael M
Thu, 25 Jul 2013 07:17:26 -0000

A patch is attached.

Not sure I'm happy with this due to the aforementioned orthogonality
concerns, but I really don't have any better ideas. If anyone does, feel
free to offer them, I don't mind throwing this patch into the trash.
(Also, not happy with the name, using "speculatable" as Nick
suggested, for the lack of other options. If the name stays I'll add it to
the documentation.)

Regarding auditing the intrinsics - I'd prefer to do this in stages.
Here I'm just preserving the current behavior by marking intrinsics that
used to be explicitly handled in isSafeToSpeculativelyExecute(), so there should
be no functional change.

From: Nick Lewycky [mailto:nlewycky at google.com]
Sent: Tuesday, July 23, 2013 02:29
To: Kuperstein, Michael M
Cc: Nick Lewycky; llvmdev at cs.uiuc.edu
Subject: Re: [LLVMdev] Does nounwind have semantics?

On 22 July 2013 01:11, Kuperstein, Michael M <michael.m.kuperstein at
intel.com<mailto:michael.m.kuperstein at intel.com>> wrote:
Of course frontends are free to put attributes, but it would be nice if
optimizations actually used them. ;-)
My use case is that of proprietary frontend that happens to know some library
function calls - which are only resolved at link time - have no side effects and
are safe to execute speculatively, and wants to tell the optimizer it can move
them around however it likes. I'll gladly submit a patch that uses these
hints, but I'd like to reach some consensus on what the desired attributes
actually are first. The last thing I want is to add attributes that are only
useful to myself.

Regarding having several orthogonal attributes vs. things like
"safetospeculate":

To know a function is safe to speculatively execute, I need at least:
1) readnone (readonly is insufficient, unless I know all accessed pointers are
valid)
2) nounwind
3) nolongjmp (I guess?)
4) no undefined behavior. This includes things like "halting" and
"no division by zero", but that's not, by far, an exhaustive list.

I guess there are several ways to handle (4).
Ideally, I agree with you, we'd like a set of orthogonal attributes that,
taken together, imply that the function's behavior is not undefined.
But that requires mapping all sources of undefined behavior (I don't think
this is currently documented for LLVM IR, at least not in a centralized fashion)
and adding a very specific attribute for each of them. I'm not sure having
function declarations with "readnone, nounwind, nolongjmp, halting,
nodivbyzero, nopoisonval, nocomparelabels, nounreachable, ..." is
desirable.

We could also have a "welldefined" attribute and a "halting"
attribute where "welldefined" subsumes "halting", if the
specific case of a function which halts but may have undefined behavior is
important.
While the two are not orthogonal, it's similar to the situation with
"readnone" and "readonly". Does that sound reasonable?

You're entirely right. I forgot about undefined behaviour.

If you want a 'speculatable' attribute, I would review that patch.
Please audit the intrinsics (at least the target-independent ones) and
appropriate library functions for whether you can apply this attribute to them.
I think the only optimization that it can trigger is that
"isSafeToSpeculativelyExecute" returns true on it. Anything else? Is
it safe to infer readnone and nounwind from speculatable?

I should mention that speculatable functions are extraordinarily limited in what
they can do in the general (non-LLVM-as-a-library) case. They may be hoisted
above calls to fork or pthread_create, they may be moved into global
constructors (and thus can't depend on global state), etc. However, since
you have a specific library you want to generate code against, you have the
power to make use of it. I don't expect clang or dragonegg to be able to
make use of it.

Nick

-----Original Message-----
From: Nick Lewycky [mailto:nicholas at mxc.ca<mailto:nicholas at mxc.ca>]
Sent: Monday, July 22, 2013 10:24
To: Kuperstein, Michael M
Cc: Andrew Trick; llvmdev at cs.uiuc.edu<mailto:llvmdev at cs.uiuc.edu>
Subject: Re: [LLVMdev] Does nounwind have semantics?

Kuperstein, Michael M wrote:
> I'm not sure I understand why it's blocked on that, by the way.

It blocks our ability to automatically deduce the halting attribute in the
optimizer, which was necessary for the use case I had at the time.
If you have a use case of your own, feel free to propose the patch!

(Technically it's not *blocked* -- see how my patch does it! -- but the
workarounds are too horrible to be committed.)

> Even if we can't apply the attribute ourselves, I don't see why we
wouldn't expose that ability to frontends.

Frontends are free to put attributes on functions if they want to. Go for it!

> I'm not entirely sure "halting" is the right attribute
either, by the way.
> What I, personally, would like to see is a way to specify a function call
is safe to speculatively execute. That implies readnone (not just readonly),
nounwind, halting - and Eris knows what else. Nick, is that too strong for you?

I strongly prefer the approach of having orthogonal attributes. There are
optimizations that you can do with each of these attributes on their own. In
particular I think that readonly+halting+nounwind+nolongjmp is going to be
common and I'd feel  silly if we had a special case for
readnone+halting+nounwind+nolongjmp and thus couldn't optimize the more
common case.

That said, I'm also going to feel silly if we don't end up with enough
attributes to allow isSafeToSpeculate to deduce it, which is where we
are right now. I was planning to get back to fixing this after
Chandler's promised PassManager work.

Nick

>
> Michael
>
> -----Original Message-----
> From: llvmdev-bounces at cs.uiuc.edu<mailto:llvmdev-bounces at
cs.uiuc.edu> [mailto:llvmdev-bounces at cs.uiuc.edu<mailto:llvmdev-bounces
at cs.uiuc.edu>] On Behalf Of Nick Lewycky
> Sent: Monday, July 22, 2013 07:08
> To: Andrew Trick
> Cc: llvmdev at cs.uiuc.edu<mailto:llvmdev at cs.uiuc.edu>
> Subject: Re: [LLVMdev] Does nounwind have semantics?
>
> Andrew Trick wrote:
>> Does 'nounwind' have semantics that inform optimization passes?
It seems to in some cases, but not consistently. For example...
>>
>> int32_t foo(int32_t* ptr) {
>>     int i = 0;
>>     int result;
>>     do {
>>       bar(ptr);
>>       result = *ptr;
>>       bar(ptr);
>>     } while (i++<   *ptr);
>>     return result;
>> }
>>
>> Say we have a front end that declares bar as...
>>
>> declare void @bar(i32*) readonly;
>>
>> So 'bar' is 'readonly' and 'may-unwind'.
>>
>> When LICM tries to hoist the load it interprets the
'may-unwind' as "MayThrow" in LICM-language and bails.
However, when it tries to sink the call itself it sees the 'readonly',
assumes no side effects and sinks it below the loads. Hmm...
>>
>> There doesn't appear to be a way to declare a function that is
guaranteed not to write to memory in a way that affects the caller, but may have
another well-defined side effect like aborting the program. This is interesting,
because that is the way runtime checks for safe languages would like to be
defined. I'm perfectly happy telling front ends to generate control flow for
well-defined traps, since I like lots of basic blocks in my IR. But I'm
still curious how others deal with this.
>
> Yes, we went through a phase where people would try to use
"nounwind+readonly == no side-effects" to optimize. All such
optimizations are wrong. Unless otherwise proven, a function may inf-loop,
terminate the program, or longjmp.
>
> I tried to add 'halting' to help solve part of this a long time
ago, but it never went in. The problem is that determining whether you have
loops requires a FunctionPass (LoopInfo to find loops and SCEV to determine an
upper bound) and applying function attributes is an SCC operation (indeed, an
SCC is itself a loop), so it's all blocked behind fixing the PassManager to
allow CGSGGPasses to depend on FunctionPasses.
>
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20100705/103670.html
>
> I'm now in a similar situation where I want 'nounwind' to mean
"only exits by terminating the program or a return instruction" but
unfortunately functions which longjmp are considered nounwind. I would like to
change llvm to make longjmp'ing a form of unwinding (an exceptional exit to
the function), but if I were to apply that rule today then we'd start
putting dwarf eh tables on all our C code, oops.
>
> Nick
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu<mailto:LLVMdev at cs.uiuc.edu>
http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
> ---------------------------------------------------------------------
> Intel Israel (74) Limited
>
> This e-mail and any attachments may contain confidential material for
> the sole use of the intended recipient(s). Any review or distribution
> by others is strictly prohibited. If you are not the intended
> recipient, please contact the sender and delete all copies.
>
>

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


_______________________________________________
LLVM Developers mailing list
LLVMdev at cs.uiuc.edu<mailto:LLVMdev at cs.uiuc.edu>
http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20130725/eac3a329/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: speculatable.diff
Type: application/octet-stream
Size: 19923 bytes
Desc: speculatable.diff
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20130725/eac3a329/attachment.obj>