This is an archive of the discontinued LLVM Phabricator instance.

[llvm] Removing writeonly and readnone incompatibility.
AbandonedPublic

Authored by homerdin on Apr 29 2018, 2:11 PM.

Details

Reviewers
reames
hfinkel
Summary

It seems writeonly is a subset of readnone and are compatible. This corresponds to the beginning of the documentation on readnone.

On a function, this attribute indicates that the function computes its result (or decides to unwind an exception) based strictly on its arguments, without dereferencing any pointer arguments or otherwise accessing any mutable state (e.g. memory, control registers, etc) visible to caller functions.

However the next part of readnone's documentation seems unrelated to the readnone attribute and would conflict with writeonly.

It does not write through any pointer arguments (including byval arguments) and never changes any state visible to callers.

This patch would remove the conflict between writeonly and readnone.

Diff Detail

Event Timeline

homerdin created this revision.Apr 29 2018, 2:11 PM
homerdin updated this revision to Diff 144497.Apr 29 2018, 4:40 PM
reames requested changes to this revision.Apr 30 2018, 11:53 AM

This patch makes no sense. The LangRef text is completely reasonable as far as I can tell. What is your actual intent here? What problem are you trying to solve?

To be very explicit, this patch should not land without either a sign off from me or another knowledgeable reviewer.

This revision now requires changes to proceed.Apr 30 2018, 11:53 AM

Thanks for the review, I should have provided my intent from the beginning.

I am working to enable functions that only write to memory to be hoisted out of loops and to combined by EarlyCSE, more specifically I am working to mark the math functions that only write to errno as writeonly then have them handled as writeonly functions.

It seems I was mislead by the name readnone, when it is intended as read none and write no visible state.

I will abandon this change and look to see why functions are being marked as both writeonly and readnone with my changes when the function writes.

Any thoughts on how we can enable the changes I am working towards would be appreciated.

homerdin abandoned this revision.Apr 30 2018, 1:03 PM

I am working to enable functions that only write to memory to be hoisted out of loops and to combined by EarlyCSE, more specifically I am working to mark the math functions that only write to errno as writeonly then have them handled as writeonly functions.

You'll need something a bit stronger than an aliasing property. You're going to specifically need to model *what* is written to errno. At the moment, we don't have a good way to model a function which writes only to one specific global (errno) or to model what those writes are.

One thing you could explore is to build in "DSE" for builtin functions. Once you got a basic design worked out in rough patch form, we could look to see what attributes might make sense to extract.

It seems I was mislead by the name readnone, when it is intended as read none and write no visible state.

readnone is intended to be the intersection of readonly and writeonly. Naming wise, readnone pre-existed the existence of writeonly.

I will abandon this change and look to see why functions are being marked as both writeonly and readnone with my changes when the function writes.

Any thoughts on how we can enable the changes I am working towards would be appreciated.

See above. I'd start this by working with builtin's via TLI and DSE, then go from there.

I am working to enable functions that only write to memory to be hoisted out of loops and to combined by EarlyCSE, more specifically I am working to mark the math functions that only write to errno as writeonly then have them handled as writeonly functions.

You'll need something a bit stronger than an aliasing property. You're going to specifically need to model *what* is written to errno. At the moment, we don't have a good way to model a function which writes only to one specific global (errno) or to model what those writes are.

I'm not sure that's true. If a function only writes, then what it writes must always be a function only of its arguments. So if I have:

foo(int, int*) writeonly;

foo(a, b);
foo(a, b);

then, I think, we can CSE these calls to foo. foo might write to its second argument somewhere, and might write to globals, but since the arguments are the same (and it doesn't read any state otherwise), it must write the same thing each time.

One thing you could explore is to build in "DSE" for builtin functions. Once you got a basic design worked out in rough patch form, we could look to see what attributes might make sense to extract.

It seems I was mislead by the name readnone, when it is intended as read none and write no visible state.

readnone is intended to be the intersection of readonly and writeonly. Naming wise, readnone pre-existed the existence of writeonly.

I will abandon this change and look to see why functions are being marked as both writeonly and readnone with my changes when the function writes.

Yea, readnone also means non-writing. I suppose the naming is now a bit unfortunate.

Any thoughts on how we can enable the changes I am working towards would be appreciated.

See above. I'd start this by working with builtin's via TLI and DSE, then go from there.

reames added a comment.May 1 2018, 8:56 AM

I am working to enable functions that only write to memory to be hoisted out of loops and to combined by EarlyCSE, more specifically I am working to mark the math functions that only write to errno as writeonly then have them handled as writeonly functions.

You'll need something a bit stronger than an aliasing property. You're going to specifically need to model *what* is written to errno. At the moment, we don't have a good way to model a function which writes only to one specific global (errno) or to model what those writes are.

I'm not sure that's true. If a function only writes, then what it writes must always be a function only of its arguments. So if I have:

foo(int, int*) writeonly;

foo(a, b);
foo(a, b);

then, I think, we can CSE these calls to foo. foo might write to its second argument somewhere, and might write to globals, but since the arguments are the same (and it doesn't read any state otherwise), it must write the same thing each time.

Good point. I agree this works and likely forms a good basis for what the errno case.