This is an archive of the discontinued LLVM Phabricator instance.

[LangRef] Limit read/writeonly attrs to memory visible to caller
ClosedPublic

Authored by fhahn on Apr 20 2022, 2:07 PM.

Details

Summary

This patch unifies the wording used for both readonly and writeonly
attributes. Both descriptions more specifically refer to memory visible
to caller functions, like in the first paragraph of the readonly
definition.

The motivation for the clarification is D123473.

Diff Detail

Event Timeline

fhahn created this revision.Apr 20 2022, 2:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 20 2022, 2:07 PM
Herald added a subscriber: jdoerfert. · View Herald Transcript
fhahn requested review of this revision.Apr 20 2022, 2:07 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 20 2022, 2:07 PM
fhahn updated this revision to Diff 424022.Apr 20 2022, 2:09 PM

Use caller functions for the last paragraphs of both writeonly and readonly.

Not sure it's sufficient to restrict to the callers. Essentially we want to assert that these functions don't have state, so any read/writes they do is to locally allocated memory. No other function in the program can access that memory.

"readonly" really has to encompass memory visible to the whole unit of optimization (the current translation unit, plus any other translation units involved in LTO) to justify the way we reason about it. For example, suppose we have a function that's logically doesn't have any state, but it contains a mutable cache of results. Then suppose we inline one call to it: now the "readonly" function touches state that matters to the caller.

"caller functions" is also a bit imprecise if callbacks are involved.

It might be possible to extend LLVM IR to define some memory as "internal" to some particular set of functions, and opaque to outside functions, but that currently doesn't exist.

Oh, just took a look at D123473. I see what you're trying to do... yes, we should allow writing to memory that's allocated/deallocated within a function.

I think the only way to make the requirement here clear is to spell out the distinction between memory allocations that continue to be accessible after the function returns, vs. temporary memory allocations in the implementation. Maybe something like the following:

"We define 'local memory' to be memory that is allocated after entry to a function, deallocated before control flow returns to the caller. If a readonly function writes to memory that is not local memory, or has other side effects, the behavior is undefined."

(I'm not sure if we need to explicitly restrict accesses to local memory from other threads? I guess other threads don't have any way to construct a pointer to local memory, so that's probably okay.)

fhahn updated this revision to Diff 424419.Apr 22 2022, 2:34 AM

Oh, just took a look at D123473. I see what you're trying to do... yes, we should allow writing to memory that's allocated/deallocated within a function.

I think the only way to make the requirement here clear is to spell out the distinction between memory allocations that continue to be accessible after the function returns, vs. temporary memory allocations in the implementation. Maybe something like the following:

"We define 'local memory' to be memory that is allocated after entry to a function, deallocated before control flow returns to the caller. If a readonly function writes to memory that is not local memory, or has other side effects, the behavior is undefined."

(I'm not sure if we need to explicitly restrict accesses to local memory from other threads? I guess other threads don't have any way to construct a pointer to local memory, so that's probably okay.)

Thanks @nlopes & @efriedma! I agree that caller functions is not sufficient in general. I updated the wording to use visible outside the function . This would also disallow accessing memory that has been allocated outside the function and gets deallocated in the function.

Eli's wording for local memory looks good to me too, but if we use it for multiple attributes it would be good to define it once and refer back to it, to avoid duplication. I couldn't find a good place to move such a definition, hence I only updated the wording to visible outside the function for now. Happy to move things around if needed.

In practice I think local memory will likely not include dynamically allocated memory, even if it is deallocated before exiting the function, as most allocators will modify state visible outside the function.

nlopes accepted this revision.Apr 22 2022, 4:34 AM

LGTM, I think it reads well.

This revision is now accepted and ready to land.Apr 22 2022, 4:34 AM
This revision was landed with ongoing or failed builds.Apr 25 2022, 3:33 AM
This revision was automatically updated to reflect the committed changes.

"outside the function" doesn't really make it clear that you're talking about a dynamic invocation of the function, as opposed to instructions inside the function's body. But maybe it's close enough.

fhahn added a comment.Apr 27 2022, 1:58 PM

"outside the function" doesn't really make it clear that you're talking about a dynamic invocation of the function, as opposed to instructions inside the function's body. But maybe it's close enough.

Hmm, maybe it could be even clearer. Do you have any suggestions? I guess we could try to spell out a definition of function-local memory somewhere and refer back to it, but I am not sure where the best place would be;

It might make sense to have a separate LangRef section for "memory-related function attributes", to describe all the assumptions we're making in one place.