[PATCH] Clarify wording in the LangRef around !invariant.load
Andrew Trick
atrick at apple.com
Fri Nov 21 01:36:37 PST 2014
On Nov 20, 2014, at 11:05 PM, Sanjoy Das <sanjoy at playingwithpointers.com> wrote:
>> This intrinsic would be control dependent, and only reads from its argument (I think).
>
> This would get DCE'ed if it is marked as nounwind, so we'll have to
> figure out a way to get llvm to have readonly functions that can
> throw. But in principle, I think this can be made to work.
>
>> I claim that this sequence involving !invariant.load metadata:
>> ---
>> int *p = <known dereferenceable>
>> ...
>> <any arbitrary operations or control flow>
>> ...
>> m = load(p) !invariant.load
>> ---
>> Is equivalent to this sequence, given the definition of assume_attribute above:
>> ---
>> int *p = <known dereferenceable>
>> llvm_assume_attribute(p) invariant
>> ...
>> <any arbitrary operations or control flow>
>> ...
>> m = load(x)
>
> Agreed.
>
>> ---
>> The semantic hole arises because we could have two pointer definitions:
>> ---
>> int *p1 = <known dereferenceable>
>> ...
>> int *p2 = <known dereferenceable>
>> ...
>> <any arbitrary operations or control flow>
>> ...
>> if (p1 == p2)
>> m = load(p2) !invariant.load
>> —
>>
>> Substituting p1 for p2 in the load now changes the semantics.
>
> This is not the semantic issue I was trying to get at, though they may
> be related in a way I don't see yet. What I was trying to say was
> that we should be able to reason that adding "if ($false) { XXX; }" to
> a CFG, for any value of 'XXX' and any value of $false that will always
> be false should be legal and semantically irrelevant, because XXX is
> never executed. However, in the current scheme for invariant loads,
> if XXX is an invariant load,
> adding this "never taken" control flow changes semantics. This is not
> a problem in theory, or in an abstract sense (it is perfectly sound
> semantics, AFAICT); but practically it means we won't be able to
> reason about transforms on the IR as "we added this bit of LLVM IR,
> but it never executes so it doesn't matter" because things that don't
> execute do matter sometimes.
>
> For example, if I have the IR:
>
> %p = < known dereferenceable >
> if ($always-false-at-runtime) {
> call undef(%p)
> }
>
> I cannot replace undef with a function that has an invariant load on
> the first argument.
I understand. I was pointing out something totally unrelated.
Regarding the issue you raise - most metadata and flags hold true for only for the original uses of the value (IIUC). For example, if a load with range is hoisted and CSEd with a normal load, the range would need to be dropped.
What I'm proposing with invariant is a stronger condition. I think it is consistent with Philip's langref wording, but inconsistent with usual metadata rules.
I would actually be fine with more conservative semantics - the load is only invariant with respect to its original uses - because it won't affect optimization in practice. But this won't decompose nicely as an assume-invariant intrinsic plus normal load. Assume-invariant ties control and memory dependence together. A conservative invariant load would be effectively control dependent but not memory dependent.
Not the same thing as:
%p = < known dereferenceable >
Store // alias with %p
if ( something)
assume_invariant(%p)
Load(%p)
Andy
>
> -- Sanjoy
More information about the llvm-commits
mailing list