[llvm-dev] RFC: Allow readnone and readonly functions to throw exceptions

Sanjoy Das via llvm-dev
Thu, 05 Jan 2017 20:03:40 -0000

On Thu, Jan 5, 2017 at 11:43 AM, Hal Finkel <hfinkel at anl.gov>
wrote:
>
> On 01/05/2017 01:20 PM, Sanjoy Das wrote:
>>
>> Hi Hal,
>>
>> On Thu, Jan 5, 2017 at 11:10 AM, Hal Finkel via llvm-dev
>> <llvm-dev at lists.llvm.org> wrote:
>>>
>>> It is still only a function of its arguments, so it can be
CSE'd.
>>
>> That's a good example -- we can CSE it without worrying about the
>> memory state flowing in.
>>
>> In fact, if we have:
>>
>> *a = 10;
>> call @readnone_may_unwind()
>> *a = 20;
>> call @readnone_may_unwind()
>> *a = 30;
>>
>> then we can first transform this to:
>>
>> *a = 10;
>> call @readnone_may_unwind()
>> *a = 20;
>> call @readnone_may_unwind()  nounwind // only on this call (since we
>> returned normally)
>> *a = 30;
>>
>> and then DSE:
>>
>> *a = 10;
>> call @readnone_may_unwind()
>> // *a = 20;
>> call @readnone_may_unwind()  nounwind // only on this call
>> *a = 30;
>>
>>
>>> Also, if I have this:
>>>
>>>   *a = 10;
>>>   b = a_readnone_unwind_func();
>>>   *a = 10;
>>>
>>> I can still conclude that this last store is redundant and can be
>>> removed. I
>>> know that the readnone function does not touch it, and if it
unwinds,
>>> than
>>> the later store is dead. If I know that &*a has not escaped to
where an
>>> exception handler might access it, then I know that the first store
than
>>> be
>>> removed.
>>
>> That's not specific to readnone though, right?  Even if the
function
>> was readonly-mayunwind, the optimization would be legal.
>
> Yes, unless the readonly-mayunwind functions takes the memory as a
> parameter, in which case the latter sentence does not apply.

I'm not a 100% sure I understand what you meant to say, but I don't
think that part is specific to readonly either.  Neither readonly nor
readnone functions can escape pointers by writing them to memory
(within their body).  However, both readnone or readonly functions
could resume with a pointer they take as an argument which the
exception handler could read from.  That is:

  void f(i32* %ptr) { // either readnone or readonly
    resume %ptr
  }

  void g() {
    %p = malloc()
    *%p = 20;  // can't DSE this because ...
    f(%p)
  }

... we could have this further up the stack

  void h() {
    invoke g() to %normal unwind %unwind
  unwind:
    %ptr = landingpad
    assert(*%ptr == 20)
  }