This is an archive of the discontinued LLVM Phabricator instance.

Allow None as a MemoryLocation to getModRefInfo, use it to start cleaning up interfaces and uses
AcceptedPublic

Authored by dberlin on Feb 24 2017, 6:34 PM.

Details

Summary

Currently, we have instructions which affect memory but have no memory
location. If you call, for example, MemoryLocation::get on a fence,
it asserts. This means things specifically have to avoid that. It
also means we end up with a copy of each API, one taking a memory
location, one not.

This starts to fix that.

We add MemoryLocation::getOrNone as a new call, and reimplement the
old asserting version in terms of it.

We make MemoryLocation optional in the (Instruction, MemoryLocation)
version of getModRefInfo, and kill the old one argument version in
favor of passing None (it had one caller). Now both can handle fences
because you can just use MemoryLocation::getOrNone on an instruction
and it will return a correct answer.

We use all this to clean up part of MemorySSA that had to handle this difference.

Note that literally every actual getModRefInfo interface we have could be made private and replaced with:

getModRefInfo(Instruction, Optional<MemoryLocation>)
and
getModRefInfo(Instruction, Optional<MemoryLocation>, Instruction, Optional<MemoryLocation>)

and delegating to the right ones, if we wanted to.

I have not attempted to do this yet.

Event Timeline

dberlin created this revision.Feb 24 2017, 6:34 PM
dberlin added inline comments.Feb 24 2017, 6:37 PM
include/llvm/Analysis/AliasAnalysis.h
550

This got clang-formatted when i reformatted the function.

lib/Transforms/Utils/MemorySSA.cpp
110

Sadly, we have to implement all of this because Optional has a non-trivial destructor/etc

dblaikie added inline comments.
include/llvm/Analysis/MemoryLocation.h
71–72
71–72

Consider a switch over the inst kind enum to reduce the work repeatedly done by dyn_cast (at least it seems like LLVM code often uses a switch over enum rather than chained dyn_cast - I don't actually know if the overhead is real)

72

This is using reference lifetime extension probably unintentionally, may be better to write it more directly as:

Optional<MemoryLocation> Loc = ...;
73–74

Optional already has the assert in it, so unless you particularly want that assert text/message, you could write this as:

return *MemoryLocation.getOrNone(Inst);
lib/Transforms/Utils/MemorySSA.cpp
146

You can write this as "return *Loc;" if you like.

149

Should this assert !IsCall?

162–163

Does !IsCall imply that Loc.hasValue() ? (or can the "None" state of Loc be used in some cases) Judging by "getLoc" I'm guessing it does imply that.

If it does imply that, then Optional's hasValue tracking is wasted space. Wonder if there's a nice abstraction that should exist for this case, but I'm not sure.

I ask partly because the use of Optional maybe makes that invariant non-obvious so a better matched abstraction may make the code easier to understand.

dberlin marked 2 inline comments as done.Feb 27 2017, 9:35 AM
dberlin added inline comments.
include/llvm/Analysis/MemoryLocation.h
71–72

So i didn't write this, and i'm happy to clean it up in a future patch, but i want to not touch it here if that's okay, as i would like the patch to change as little as possible :)

If you stare at MemoryLocation.cpp, you'll see that basically all of these are doing the same thing, and probably could stand a bit of templating.

Honestly, at this point, we may just want to make the memory instructions able to return a memorylocation in Instructions.h.
Who knows.

73–74

I was trying to duplicate the exact functionality of the existing code, but happy to change it.

lib/Transforms/Utils/MemorySSA.cpp
149

No.
Actually, we expect calls to return None here.

162–163

"If it does imply that, then Optional's hasValue tracking is wasted space. Wonder if there's a nice abstraction that should exist for this case, but I'm not sure."
Yes, it's a bit of waste space. We could have a traits that lets you reuse a bit in the thing you are making optional, and use that. That is how we do a lot of "use this thing, but storage is external" in LLVM.
But not sure it's worth it.

In reality, this entire class is working around a bit of api deficiency, IMHO.

We want ways to make "hashtable of memory locations", but calls don't have memory locations (or more accurately, they have multiple ones).

IE you really want to be able to say "the last time i saw this abstract memory area, it had this value".

But we only can do that for non-call instructions.
So either we have one mapping for calls, and none for non-calls, which ends up a different kind of ugly, or we have a class like this that tries to encapsulate the difference.

In practice, all of this should go away at some point, and we should come up with a clean API that allows mapping/caching memory locations to other things, without the current mess, because nobody should have to care about this :)

Even if that is really "MLocOrCall becomes the new MemoryLocation".

dberlin marked 10 inline comments as done.Mar 3 2017, 5:09 PM
dberlin added inline comments.
include/llvm/Analysis/MemoryLocation.h
71–72

I gave up and fixed it since it looks nicer that way anyway :)

dberlin updated this revision to Diff 90553.Mar 3 2017, 5:18 PM
dberlin marked an inline comment as done.
  • Update for review comments
davide accepted this revision.Apr 14 2017, 8:35 AM

Some nits inline.

include/llvm/Analysis/AliasAnalysis.h
530–544

can you use static_cast<> here instead (and if you feel motivated change the surrounding statements to do the same)?

include/llvm/Analysis/MemoryLocation.h
19–20

Unsorted.

This revision is now accepted and ready to land.Apr 14 2017, 8:35 AM
dberlin marked 2 inline comments as done.Apr 24 2017, 1:43 PM

FYI, patch should also update:
unittests/Analysis/AliasAnalysisTest.cpp:193-204