This is an archive of the discontinued LLVM Phabricator instance.

Add must alias info to ModRefInfo.
ClosedPublic

Authored by asbirlea on Oct 12 2017, 3:39 PM.

Details

Summary

Add an additional bit to ModRefInfo, MRI_Must, to be set for known must aliases.
Conservatively this bit will not be set (equivalent to MayAlias or NoAlias).

Notes:

  • MRI_Must is almost entirely set in the AAResults methods, the remaining changes are trying to preserve it.
  • Only some small changes to make custom AA passes set MRI_Must (BasicAA).
  • GlobalsModRef already declares a bit of the same value as MRI_Must (MayReadAnyGlobal). No changes to shift the value of MayReadAnyGlobal (see AlignedMap). FunctionInfo.getModRef() masks out everything except MRI_ModRef, so correctness is preserved, but the MRI_Must info is not set/used.
  • There are cases where the MRI_Must is not set, e.g. 2 calls that only read will return MRI_NoModRef, though they may read from exactly the same location.

Event Timeline

asbirlea created this revision.Oct 12 2017, 3:39 PM
lib/Analysis/AliasAnalysis.cpp
128

Probably-silly question: what's the difference between Result == MRI_NoModRef and Result == MRI_Must?

(If the answer is "nothing", should we ever really see MRI_Must on its own?)

asbirlea added inline comments.Oct 12 2017, 5:36 PM
lib/Analysis/AliasAnalysis.cpp
128

Not silly at all. In theory Result == MRI_Must can happen when checking ModRefInfo for 2 locations that alias each other, and both only read.
I updated the check for safety. I am not sure we should see MRI_Must on its own, but there is nothing preventing it right now.

hfinkel edited edge metadata.Oct 25 2017, 6:04 PM

This certainly needs some test cases.

include/llvm/Analysis/AliasAnalysis.h
109

We should explicitly document here whether this is only for complete overlap, or whether it includes partial overlaps.

lib/Analysis/AliasAnalysis.cpp
128

Right, we currently don't consider read/read aliasing. With this change, we do. Why? (And this should be documented explicitly).

151

How is including MR's Must bit useful? What if the call has multiple pointer-typed arguments?

529

This still needs to be fixed?

lib/Analysis/AliasAnalysisEvaluator.cpp
248

We'll need to print the information for testing.

lib/Analysis/BasicAliasAnalysis.cpp
780

Why is this useful? If we don't know which operand it is, I don't see how we use the information that it must alias one of the operands.

lib/Analysis/GlobalsModRef.cpp
87

I think that, if passes want to define their own "local" bits, we should create a well-defined way to make this happen. Define some enum, something like MRI_FirstUserBit, or similar, and use that to define the bit number here.

dberlin added inline comments.Oct 25 2017, 7:44 PM
lib/Analysis/AliasAnalysis.cpp
151

See below.
If you are trying to move a call, knowing that another call mustaliases everything you do, means that you don't have to give up and not move it. you can instead try to move it as well.

lib/Analysis/BasicAliasAnalysis.cpp
780

So, i gave an example earlier of how must information can be useful in the llvm-dev thread that i'll copy herre.
It's true you don't know what operand it is, but you can ask for the location for each operand.
Because it doesn't matter what the values are, only what they alias:

*a = something
foo(a)
b = *a

If foo mustalias a, not only can you possibly move foo with a, you can actually possibly clone foo here, change it to be pass-by-value, and promote the argument inside of it (if you wanted to).
IE it's just as useful as known noalias for the memorylocation, and you have to do the same thing with the data.

If you make it

*a = something
foo (a, c)
b = *a

You can only do anything if you know they are all must-alias or no-alias anyway.

So to me, this API is as bad/good for noalias as it is for mustalias.

It costs nothing to give MRI_Must, and while we don't currrently take advantage of such info, it *is* actually useful IMHO.

hfinkel added inline comments.Oct 25 2017, 8:12 PM
lib/Analysis/AliasAnalysis.cpp
151

That makes sense. MRI_Must on a call will mean that all operands must alias. We should make that clear in the documentation.

lib/Analysis/BasicAliasAnalysis.cpp
780

I can certainly see this being useful if it means that all arguments must alias the given location. What's the useful thing to do here for call vs. call queries? Do we add MRI_Must only if all arguments must alias all other arguments, or is it enough if at least one argument on the LHS must alias an argument on the RHS?

806

Or PartialAlias?

asbirlea updated this revision to Diff 121080.Oct 31 2017, 4:18 PM

Documented purpose of MRI_Must in enum declaration.
Updated when MRI_Must is set on getModRef(CS, MLoc) and getModRef(CS, CS).
Updated testing accordingly.

asbirlea updated this revision to Diff 121083.Oct 31 2017, 4:34 PM
asbirlea marked 11 inline comments as done.

Minor updates.

asbirlea marked an inline comment as done.Oct 31 2017, 4:45 PM

While updating the tests, I cannot see an obvious test scenario I missed.

include/llvm/Analysis/AliasAnalysis.h
109

Please let me know if the info I added here is reasonable.

lib/Analysis/AliasAnalysis.cpp
529

I want this to be the intended behavior, replaced with "Note"

lib/Analysis/BasicAliasAnalysis.cpp
780

I'm sorry if this is a stupid question, I don't know what you mean by call queries.

lib/Analysis/GlobalsModRef.cpp
87

I'd be happy with that approach, but not sure how to fix this particular case, since it appears to rely on that particular value, i.e. it looks like it needs that additional bit for alignment correctness.
I didn't get this to work with updated values, perhaps I'm missing something obvious.

asbirlea updated this revision to Diff 121957.Nov 7 2017, 12:39 PM
asbirlea marked an inline comment as done.

Add testcase for Call-Loc to test Must alias is set when no May alias is found, only MustAlias or NoAlias.
@dberlin: could you please confirm this is the right sematics?

Remaining issue (that I don't know whether to address in this patch): other passes adding their own bits (GlobalsModRef).

sanjoy requested changes to this revision.Nov 21 2017, 11:33 AM
sanjoy added inline comments.
include/llvm/Analysis/AliasAnalysis.h
113

*accesses

119

These last two sentences probably also belong on getArgModRefInfo and callCapturesBefore ?

I'd also wordsmith this a bit -- something like:

We usually do not try our best to infer MRI_Must, instead it is merely another piece of "free' information that is presented when available.  For instance:

 - (Your RAR example)
 - (Other examples)
lib/Analysis/AliasAnalysis.cpp
151

Can just be MR | MRI_ModRef.

226

This pattern (here and later) looks a little weird to me -- either downstream passes don't care about distinguishing between MRI_NoModRef and MRI_Must or they do. If the former is true then we should stop iterating early only when we see a MRI_Must and if the latter is true we should be returning Result & MRI_ModRef. Otherwise I suspect we'll see hard to explain performance bugs where (e.g.):

  • Transform X optimizes better if AA returns MRI_Must
  • We know that alias analysis P returns MRI_Must for the case we're trying to optimize
  • But alias analysis Q prevents P's MRI_Must from being propagated by returning MRI_NoModRef (which is correct but not optimal).

What do you think?

279

is *not* found

308

"ArgMask never has MRI_Must set." -> is that incidental, or a fundamental property? In any case, if you're relying on it, then please add an assert.

418

Here and elsewhere - please end sentences with a period.

503

Unrelated to your change, but the name of this function is odd.

528

I think this is cleaner to track as bool MustAlias.

lib/Analysis/BasicAliasAnalysis.cpp
780

Perhaps this is cleaner to track as a bool IsMustAlias?

lib/Analysis/GlobalsModRef.cpp
87

How many of these do we have in the worst case (in a clang LTO bootstrap, say)? I'd be tempted to just have two words here.

136

I think it is better to Info.setInt(Info.getInt() | (NewMRI & MRI_ModRef));. That way we won't get surprising behaviors where making AA smarter to infer MRI_Must regresses because that bit aliases (pun intended!) with MayReadAnyGlobal.

lib/Analysis/MemoryDependenceAnalysis.cpp
696

Nit: how about switching on MR & MRI_ModRef?

This revision now requires changes to proceed.Nov 21 2017, 11:33 AM
asbirlea updated this revision to Diff 123985.Nov 22 2017, 10:53 AM
asbirlea edited edge metadata.
asbirlea marked 11 inline comments as done.

Address comments.

Some comments and renaming in getModRef(ImmutableCallSite, ImmutableCallSite) for easier understanding of the code.

lib/Analysis/AliasAnalysis.cpp
226

Downstream passes shouldn't rely on having MRI_Must set, since this bit is best effort. Yes, you could have different optimizations if that particular optimization relies on AA setting MRI_Must. What you should *not* have, is a performance penalty to set MRI_Must.

We stop iterating regardless of MRI_Must, because we do not want to incur penalty from calling other AA passes that may set MRI_Must.
And conversely, we do not return Result & MRI_ModRef, because if MRI_Must is set, the additional 'free' info should be kept.

I also updated comments in getModRef(2 callsites) hoping to clarify this.

If later on we see that MRI_Must is so useful that we want to fully rely on it for optimizations, then I'm happy with changing this check. Right now it's not used, so the cost of stopping only after MRI_Must is set is not justified.

Please let me know if this makes sense.

308

Right now getArgModRefInfo never sets MRI_Must.
I tried to document this in ModRef enum and before getArgModRefInfo method declaration. Do you think I should also add an assert here (and above) ?

503

Ack, not planning to change in this patch though.

528

I find it easier to read having the logical OR on the final result: ModRefInfo(R | M), and I think if we track it as bool the check MustAlias?MRI_Must:MRI_NoModRef either needs another variable or a more complex return statement.
I'm inclined to keep as is, but both are ok.
What do you think?

lib/Analysis/BasicAliasAnalysis.cpp
780

Same as above. Whatever we decide on that, I will apply to this one too.

lib/Analysis/GlobalsModRef.cpp
87

I'm confused. If MayReadAnyGlobal = 2, it will trigger the static assert below for overlapping with MRI_ModRef.

nlopes added a subscriber: nlopes.Nov 23 2017, 2:56 AM
nlopes added inline comments.
lib/Analysis/AliasAnalysis.cpp
468

AtomicCmpXchgInst must read, but may not write (depending on the value read).
I think the only safe value here is MRI_ModRef, since the current lattice doesn't have a more precise value for MustRead & MayReadWithMustAlias.

nlopes added inline comments.Nov 23 2017, 2:58 AM
lib/Analysis/AliasAnalysis.cpp
468

gah, I meant MustRef & MayModWithMustAlias.

(We've discussed the meat of this patch offline, but I had some stray comments from earlier)

lib/Analysis/AliasAnalysis.cpp
308

If your code will be incorrect when someone changes getArgModRefInfo to return results with MRI_Must set then you should definitely assert this.

528

Here's a reason for why I think a bool is better here -- right now looking at just the return statement in isolation, ModRefInfo(R | M), it isn't obvious that we're at most adding the MRI_Must bit to R (since M could be MRI_Mod, for instance). But if we have ModRefInfo(R | (MustAlias ? MRI_Must : MRI_NoModeRef)) then just by looking at the expression and nothing else we know that we're at most setting the MRI_Must bit.

asbirlea updated this revision to Diff 125646.Dec 5 2017, 4:17 PM

Rebase and address comments.

asbirlea marked 10 inline comments as done.Dec 5 2017, 4:28 PM

Updated, PTAL.

lib/Analysis/AliasAnalysis.cpp
308

Should not be an issue anymore. If getArgModRefInfo returns results with MRI_Must, result should still be correct.

468

I updated the comments above for the MRI_Must* bits. MustRef & MayModWithMustAlias should have Must bit set.

528

Ack, updated.

asbirlea updated this revision to Diff 125652.Dec 5 2017, 4:31 PM
asbirlea marked 3 inline comments as done.

Nit: periods.

sanjoy requested changes to this revision.Dec 5 2017, 9:18 PM

Some minor nits inline, but I thought we were going with making bitwise MRI_Must be 0 (and MRI_NoModRef be 4) so that & works as expected?

include/llvm/Analysis/AliasAnalysis.h
109

(Minor) I'd remove "conservative" -- it is understood that these things are conservatively correct.

113

This is for calls that are known to be argmemonly, right?

120

I think this comment can be improved.

  • Instead of starting with details on how we infer MRI_Must let's first describe what it means, followed by this note.
  • I don't think we need a laundry list of examples here. I think it is better to just mention that we don't always return the most precise possible and add a "c.f. getArgModRefInfo, callCapturesBefore etc.".
125

"default" is a bit confusing here. How about just leaving out the second part, and commenting "MRI_Must is provided for completeness, but no routines will return only MRI_Must today".

583

The comma is unnecessary.

lib/Analysis/AliasAnalysisEvaluator.cpp
264

Unnecessary move? (Not a big deal, but avoid this will make the diff slightly smaller)

This revision now requires changes to proceed.Dec 5 2017, 9:18 PM
asbirlea updated this revision to Diff 126437.Dec 11 2017, 1:34 PM
asbirlea edited edge metadata.
asbirlea marked 4 inline comments as done.

Address comments and rebase on ToT.

sanjoy requested changes to this revision.Dec 11 2017, 10:56 PM

Unless you have a specific reason not to, I think we should merge https://reviews.llvm.org/D41091 into this one -- that'll make the patch easier to review (usually these kinds of things go the other way -- splitting the patch makes it easier to review :) ).

Meanwhile, I have some minor comments inline.

include/llvm/Analysis/AliasAnalysis.h
116

Nit s/MRI_Must/ModRefInfo::Must/ here and elsewhere

lib/Analysis/BasicAliasAnalysis.cpp
820

Add a comment here on why tracking MustAlias this way is correct despite the early exit (IIUC this is because if Result = ModRefInfo::ModRef the we don't use MustAlias)?

lib/Analysis/GlobalsModRef.cpp
133

This isn't clearing the must bit though, right? It is clearing the MayReadAnyGlobal bit?

Also the inline here is redundant -- member functions defined within their class are implicitly inline.

This revision now requires changes to proceed.Dec 11 2017, 10:56 PM
asbirlea updated this revision to Diff 126801.Dec 13 2017, 11:56 AM

Address comments and merge in D41091.

asbirlea updated this revision to Diff 126805.Dec 13 2017, 12:03 PM
asbirlea marked 2 inline comments as done.

Remove remaining MRI_ instances.

Issue (?): rephrase comments to clarify Must is cleared not set when MustAlias exists.
Possible reverse clearMust si setMust?

asbirlea updated this revision to Diff 126833.Dec 13 2017, 1:54 PM

Added comment to clarify what setting Must means.

Ready for review, PTAL.

sanjoy requested changes to this revision.Dec 14 2017, 12:56 AM

I think we can break this patch up further -- how about this breakdown:

  1. Remove the changes related to calls from this patch and do something conservative there. That'll reduce the complexity of this patch a bit. I also have a comment about our treatment of calls inline, which we can discuss on the subsequent patch that proper support for calls. (Let me know if splitting this up will be annoying, and we can think of some other strategy.)
  2. Make the refactoring I suggested inline in GlobalsModRef.cpp and rebase on top of it.

With both (1) and (2) done, this patch should be ready to go in modulo minor nits.

include/llvm/Analysis/AliasAnalysis.h
111

How about moving this meta-comment and the definition of Must to the end of the enum?

lib/Analysis/AliasAnalysis.cpp
197

I'm not sure about this treatment of calls. For a query between instructions like stores and loads that only touch one location the meaning of Must is pretty clear -- MustRef (say) means the store does not write to any location other than the location the load reads from. However, generalizing this to calls seems to mean that a MustRef between a call and a load would imply that the call does not write to any location other than what the load reads. This means we can't ignore NoAlias arguments -- a NoAlias (as opposed to Must) result should also set MayAlias to false.

499

It may be better to instead add this as a comment on the return instruction, as "Not returning MustModRef since we've not seen all the arguments" etc.

529

"incomplete" is a bit vague -- how about just leaving a comment on the return statement as "Not returning MustModRef since we've not seen all the arguments" or something like that?

lib/Analysis/GlobalsModRef.cpp
137

I wouldn't break the abstraction here this way. Instead, I think it is better to have:

int ModRefInfoToInteger(ModRefInfo mri) {
  switch (clearMust(mri)) {
  case NoModRef:
    return 0;
  case Mod:
    return 1;
  case Ref:
    return 2;
  case ModRef:
    return 3;
  }
}

int IntegerToModRef(ModRefInfo mri) {
  // Inverse of the above
}

and use these to "encode" and "decode" an opaque ModRefInfo instance to a 2 bit integer and back.

(You may even want to do this as a separate NFC change and land it independently.)

This revision now requires changes to proceed.Dec 14 2017, 12:56 AM
asbirlea updated this revision to Diff 127043.Dec 14 2017, 4:10 PM
asbirlea marked 3 inline comments as done.

Address comments.

PTAL.

lib/Analysis/AliasAnalysis.cpp
197

Having looked at this again, it appears safe to set Must in this case, but I'm also quite ok with separating this into a separate patch.
I added the path to set MayAlias here and below getMRI(CS, CS), and these can be removed in a subsequent patch.

lib/Analysis/GlobalsModRef.cpp
137

I tried this and ended up with a more confusing code, and harder to maintain.
The general idea of encoding 2 bits and using that in GlobalsModRef is tempting for me, but in practice it looks like it complicates the code unnecessarily. I can be convinced otherwise, and this can be an add-on clean-up patch in that case.

sanjoy requested changes to this revision.Dec 18 2017, 1:33 PM

Mostly minor stuff. The main non-nit comment I have is that the various places we're handling calls don't seem consistent with each other.

lib/Analysis/AliasAnalysis.cpp
202

How about:

bool MustAlias = true;
AliasResult ArgAlias = ...
MustAlias &= ArgAlias == MustAlias;

?

275–277

Unrelated to your change, but this is the second time I've been confused by this phrase. The variable Result sounds like it is the value we're going to return. But it isn't -- it is just the ModRef information we've computed till before this algorithm on arguments.

What do you think about (in a separate change) splitting out this loop (and the one after) into a separate function, in which Result will be passed as an argument with a more mnemonic name? Of course, this is totally unrelated to your change, so I'll understand if you don't think it is a good use of your time. :)

279

Given that you're setting MustAliasFound even if !isMustSet(ModRefCS1) perhaps it should be called something else?

Secondly, how about structuring this as:

bool MustAlias = true;
MustAias &= isMustSet(ModRefCS1);

?

Finally, I don't think MustAliasFound is necessary anymore -- if there were no MustAlias results and there was at least one argument, then we'd have cleared out MustAlias, so no need to track MustAliasFound I think?

281

I think we can simplify this a bit -- just keep track of the number of arguments you've seen to be MustAlias, and check that it is equal to the number of actual function args. That way we're not using MayAlias to track "have seen a may-alias OR have early exited".

317

The comments I made on the previous loop also apply here.

547–549

Should you be clearing MustAlias even if AR == NoAlias like you're doing in the other cases?

lib/Analysis/BasicAliasAnalysis.cpp
806

Same comment here w.r.t. setting MustAlias when AR == NoAlias.

858

Going by our current definition ("Must means no other location is Ref'ed or Mod'ed") this can't return Must right?

This revision now requires changes to proceed.Dec 18 2017, 1:33 PM
asbirlea updated this revision to Diff 127914.Dec 21 2017, 10:44 AM
asbirlea marked 20 inline comments as done.

Address comments.

lib/Analysis/AliasAnalysis.cpp
275–277

Feedback noted. I may do this in a future patch :).

279

Also renamed bool MustAlias to bool IsMustAlias to avoid confusion with AliasResult MustAlias.

281

I think that actually complicates the code. Either keeping track of the number of arguments seen so far, or of all must alias arguments, or setting a different variable on early exit, they add more baggage than using a bool to track "have seen a may-alias OR have early exited".
The comment should make this choice clear.

sanjoy accepted this revision.Dec 21 2017, 11:15 AM

lgtm!

include/llvm/Analysis/AliasAnalysisEvaluator.h
41 ↗(On Diff #127914)

Another cleanup that might be worth doing as a separate change -- change these fields to use the C++11 member initializer like int64_6 MustCount = 0;.

This revision is now accepted and ready to land.Dec 21 2017, 11:15 AM
This revision was automatically updated to reflect the committed changes.
thakis added a subscriber: thakis.Apr 27 2018, 12:02 PM

A slightly late review comment:

llvm/trunk/lib/Analysis/AliasAnalysis.cpp
551 ↗(On Diff #127936)

You need IsMustAlias (or AllOperandsMustAlias or what have you) here too; as is this shadows the MustAlias AliasResult, and AR != MustAlias below on line 568 now compares with this bool instead of with the enum value as intended. (Are we missing test coverage here?)

(found by msvc warning 4805 which I had enabled locally for a bit.)

asbirlea marked an inline comment as done.Apr 30 2018, 1:18 PM
asbirlea added inline comments.
llvm/trunk/lib/Analysis/AliasAnalysis.cpp
551 ↗(On Diff #127936)

Should be fixed in r331222, thanks for the catch!
I'll look into expanding test coverage when starting to use the Must info.

asbirlea marked 2 inline comments as done.Apr 30 2018, 1:19 PM