[PATCH] D28147: [LICM] Allow promotion of some stores that are not guaranteed to execute

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 1 18:32:44 PST 2017


Hi Daniel,

On Sat, Dec 31, 2016 at 7:57 PM, Daniel Berlin <dberlin at dberlin.org> wrote:
>
>
> On Sat, Dec 31, 2016 at 5:54 PM, Sanjoy Das <sanjoy at playingwithpointers.com>
> wrote:
>>
>> Hi Daniel,
>>
>> On Sat, Dec 31, 2016 at 4:44 PM, Daniel Berlin <dberlin at dberlin.org>
>> wrote:
>> [snip]
>> > 2. I have no problem with us with deciding what we mean in either
>> > direction.
>> > I just believe it's worth having a real mailing list discussion about it
>> > not
>> > buried in this particular thread, before making such a patch.
>>
>> (For brevity, when I say readnone, I mean readnone / readonly)
>>
>> I think LLVM today already has a strong bent towards "readnone
>> functions *can* unwind".
>
> How does one unwind without writing memory?

Exactly like one returns without writing memory. :)

Semantically a `resume <value>` is an intra-frame control flow
transfer, like a `ret <value>`, which just happens to resume execution
at an abnormal continuation.

In fact, `resume <value>` (and thus `_Unwind_Resume`) *cannot* write
to memory in an observable manner (or have any other side effects)
since otherwise we would not be able to inline @f into @g in

define void @f(i32 %x) personality i32 3 {
  resume i32 %x
}

define i32 @g(i32 %x) personality i32 3 {
entry:
  invoke void @f(i32 %x) to label %normal unwind label %unwind

normal:
  ret i32 0

unwind:
  %t = landingpad i32 cleanup
  ret i32 %t
}

Today opt -inline -simplifycfg reduces @g to "ret i32 %x", which would
not be observationally equivalent to the original IR if "resume" was
side effecting.


To avoid stores at the ABI level, you could create a convention that
the exceptional continuation address is stored to a TLS address before
a call, and arrange for the (exception throwing) callee to put the
exception object in %RAX and return to this address.  However, I'd say
it isn't necessary to make the throwing action store-less at the ABI
level, as long as whatever we do is observably readonly / readnone
(writing to spill slots is allowed even in readnone functions, for
instance).

>> a. We don't CSE the call to @f() in
>>
>>   declare void @f() readnone
>>
>>   define void @g() {
>>     call void @f()
>>     ret void
>>   }
>>
>> unless @f is also marked nounwind.
>
> One can argue these are missed opts :)

Sure, but the code is specific enough that I'd think the missed
optimizations are intentional (i.e. not just oversights):

bool mayHaveSideEffects() const { return mayWriteToMemory() || mayThrow(); }

-- Sanjoy


More information about the llvm-commits mailing list