This is an archive of the discontinued LLVM Phabricator instance.

[AliasAnalysis] Introduce getModRefInfoMask() as a generalization of pointsToConstantMemory().
ClosedPublic

Authored by pcwalton on Oct 24 2022, 8:51 PM.

Details

Summary

The pointsToConstantMemory() method returns true only if the memory pointed to
by the memory location is globally invariant. However, the LLVM memory model
also has the semantic notion of *locally-invariant*: memory that is known to be
invariant for the life of the SSA value representing that pointer. The most
common example of this is a pointer argument that is marked readonly noalias,
which the Rust compiler frequently emits.

It'd be desirable for LLVM to treat locally-invariant memory the same way as
globally-invariant memory when it's safe to do so. This patch implements that,
by introducing the concept of a *ModRefInfo mask*. A ModRefInfo mask is a bound
on the Mod/Ref behavior of an instruction that writes to a memory location,
based on the knowledge that the memory is globally-constant memory (in which
case the mask is NoModRef) or locally-constant memory (in which case the mask
is Ref). ModRefInfo values for an instruction can be combined with the
ModRefInfo mask by simply using the & operator. Where appropriate, this patch
has modified uses of pointsToConstantMemory() to instead examine the mask.

The most notable optimization change I noticed with this patch is that now
redundant loads from readonly noalias pointers can be eliminated across calls,
even when the pointer is captured. Internally, before this patch,
AliasAnalysis was assigning Ref to reads from constant memory; now AA can
assign NoModRef, which is a tighter bound.

Diff Detail

Event Timeline

pcwalton created this revision.Oct 24 2022, 8:51 PM
pcwalton updated this revision to Diff 470365.Oct 24 2022, 8:53 PM

Marking as non-draft.

pcwalton published this revision for review.Oct 24 2022, 8:54 PM
pcwalton added a reviewer: nikic.
nikic added inline comments.Oct 25 2022, 3:18 AM
llvm/lib/Analysis/AliasAnalysis.cpp
567

Should use getModRefInfoMask() here as well.

586

And here.

605

And here.

llvm/lib/Analysis/BasicAliasAnalysis.cpp
810

Rather than making this a separate method, this should replace pointsToConstantMemory() instead, at least as far as AA providers are concerned. (At the top-level interface, we can keep pointsToConstantMemory() as a thin wrapper like getModRefInfoMask() == NoModRef.)

The problem with your current implementation is that it does not handle cases where there are multiple underlying objects (or a single one that requires looking through phis) which all ultimately end in noalias readonly memory.

llvm/lib/Transforms/IPO/FunctionAttrs.cpp
149

This should be something like MR &= AAR.getModRefInfoMask(Loc, /*IgnoreLocal*/true), after merging with pointsToConstantMemory().

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
136

This one is non-trivial and could use a test.

llvm/test/Analysis/BasicAA/pr18573.ll
11 ↗(On Diff #470365)

Did you mean to drop the readonly rather than the noalias here?

llvm/test/Analysis/BasicAA/readonly-noalias.ll
8 ↗(On Diff #470365)

This test already returns NoModRef prior to your changes. You need to pass ptr %p as an argument to @foo(), otherwise it can't access it due to noalias.

alex added a subscriber: alex.Oct 25 2022, 4:08 AM
Matt added a subscriber: Matt.Oct 25 2022, 11:11 AM
pcwalton added inline comments.Oct 25 2022, 5:08 PM
llvm/lib/Analysis/BasicAliasAnalysis.cpp
810

Sure, in fact that was what I originally tried to do, but I got stuck on what to do with the OrLocal parameter. How should getModRefInfoMask() deal with the case in which OrLocal is true and the memory location resolves to a local? Should it return NoModRef? Should it return Ref? Or should I split out the logic of getModRefInfoMask() and pointsToConstantMemory() into a shared helper function that both of them call into?

pcwalton added inline comments.Oct 25 2022, 5:09 PM
llvm/lib/Analysis/BasicAliasAnalysis.cpp
810

Oh never mind, I saw the IgnoreLocal part of your other comment. OK, I'll return NoModRef in that case.

pcwalton updated this revision to Diff 470893.Oct 26 2022, 12:00 PM

Merge pointsToConstantMemory() into getModRefMask().

Should be ready for review again. I'll look at the failing test cases in the meantime.

pcwalton marked 8 inline comments as done.Oct 26 2022, 12:05 PM
pcwalton updated this revision to Diff 470906.Oct 26 2022, 12:50 PM

Fix AMDGPU alias analysis.

pcwalton updated this revision to Diff 470946.Oct 26 2022, 2:56 PM

Fix AMDGPU alias analysis and new test failure.

nikic added inline comments.Oct 27 2022, 2:26 AM
llvm/include/llvm/Analysis/AliasAnalysis.h
769–770

This method should be dropped (together with the ones in AAResults::Model and AAResultBase).

llvm/lib/Analysis/AliasAnalysis.cpp
567

This should be return getModRefInfoMask(Loc, AAQI) (we may have to preserve the Ref).

586

Same here, just return the mask.

605

Same here.

llvm/lib/Analysis/BasicAliasAnalysis.cpp
839

We should probably also check for ReadNone here to be thorough, though it's likely not terribly useful in practice.

840

Result |=

llvm/test/Transforms/InstCombine/copied-from-readonly-noalias.ll
1 ↗(On Diff #470946)

Use update_test_checks.py here.

3 ↗(On Diff #470946)

The -aa-pipeline and 2>&1 are not necessary here.

17 ↗(On Diff #470946)

I'd replace readnone -> readonly here, I think that would be a bit clearer (wouldn't be able to read the argument otherwise anyway...)

llvm/test/Transforms/LoopVectorize/interleaved-accesses.ll
583 ↗(On Diff #470946)

Can you please commit these fixes for readonly in tests ahead of time?

pcwalton updated this revision to Diff 471381.Oct 27 2022, 8:02 PM

Updated to address review comments.

pcwalton marked 9 inline comments as done.Oct 27 2022, 8:03 PM
pcwalton added inline comments.
llvm/test/Transforms/LoopVectorize/interleaved-accesses.ll
583 ↗(On Diff #470946)

You mean as a separate Phabricator diff? Sure, I can do that.

nikic added a comment.Oct 28 2022, 5:36 AM

This looks basically good to me. I'd suggest precommitting the test changes with baseline checks, and then rebasing this patch.

llvm/docs/AliasAnalysis.rst
166

This doesn't line up with the implementation anymore. (Feel free to just delete this section entirely.)

llvm/lib/Analysis/BasicAliasAnalysis.cpp
809

Keeping the previous location of the function would make it a bit clearer what changed here.

llvm/test/Analysis/BasicAA/readonly-noalias.ll
1 ↗(On Diff #471381)

This test can be merged into constant-memory.ll.

13 ↗(On Diff #471381)

We should also have a negative test for the case where noalias on the argument is missing.

llvm/test/Transforms/InstCombine/copied-from-readonly-noalias.ll
1 ↗(On Diff #471381)

This test can be merged into memcpy-from-global.ll.

pcwalton updated this revision to Diff 471690.Oct 28 2022, 5:03 PM

Addressed comments. Note that D136993 contains the diff this is now based on top of.

pcwalton updated this revision to Diff 471767.Oct 29 2022, 11:28 AM

Rebased on top of updated D136993.

OK, I pushed the baseline test changes. @nikic Let me know if this looks good and I can push this.

pcwalton retitled this revision from [AliasAnalysis] Introduce getModRefMask() as a generalization of pointsToConstantMemory(). to [AliasAnalysis] Introduce getModRefInfoMask() as a generalization of pointsToConstantMemory()..Oct 29 2022, 7:11 PM
pcwalton updated this revision to Diff 471827.Oct 30 2022, 2:48 AM

Rebased. This should be ready for sign off now.

nikic added inline comments.Oct 30 2022, 7:24 AM
llvm/lib/Analysis/BasicAliasAnalysis.cpp
683

I'd prefer omitting this check here and instead keeping it in the fence implementation. We should try to move away from locations without pointers rather than pushing them deeper into the API.

llvm/lib/Analysis/ObjCARCAliasAnalysis.cpp
93

Huh, this whole function is a very complicated way to do nothing at all. The function above it as well. Not related to your patch though...

llvm/lib/Target/AMDGPU/AMDGPUAliasAnalysis.cpp
131

Same here.

140–141

Can't we drop this part of the code entirely? This should be subsumed by the generic handling in BasicAA now.

pcwalton updated this revision to Diff 471860.Oct 30 2022, 1:19 PM

Address review comments.

pcwalton marked 4 inline comments as done.Oct 30 2022, 1:19 PM
nikic accepted this revision.EditedOct 31 2022, 2:47 AM

LGTM. The patch description needs an update though, in particular the test changes are no longer part of this patch.

This revision is now accepted and ready to land.Oct 31 2022, 2:47 AM
pcwalton edited the summary of this revision. (Show Details)Oct 31 2022, 10:48 AM
pcwalton edited the summary of this revision. (Show Details)
This revision was landed with ongoing or failed builds.Oct 31 2022, 1:04 PM
This revision was automatically updated to reflect the committed changes.
xry111 added a subscriber: xry111.Mar 30 2023, 9:47 AM

We observed a crash in Thunderbird built with Rustc using LLVM 16.0.0 (happens with Rustc 1.68.x built with a system LLVM 16, and Rustc nightly 2023-03-25). See https://bugzilla.mozilla.org/show_bug.cgi?id=1824544.

Bisect suggests this change is the first bad commit.

Any pointer for diagnose?

nikic added a comment.Mar 30 2023, 9:59 AM

We observed a crash in Thunderbird built with Rustc using LLVM 16.0.0 (happens with Rustc 1.68.x built with a system LLVM 16, and Rustc nightly 2023-03-25). See https://bugzilla.mozilla.org/show_bug.cgi?id=1824544.

Bisect suggests this change is the first bad commit.

Any pointer for diagnose?

Probably the same issue as https://github.com/llvm/llvm-project/issues/58776. It needs a smaller reproducer than "build all of firefox".

We observed a crash in Thunderbird built with Rustc using LLVM 16.0.0 (happens with Rustc 1.68.x built with a system LLVM 16, and Rustc nightly 2023-03-25). See https://bugzilla.mozilla.org/show_bug.cgi?id=1824544.

Bisect suggests this change is the first bad commit.

Any pointer for diagnose?

Probably the same issue as https://github.com/llvm/llvm-project/issues/58776. It needs a smaller reproducer than "build all of firefox".

Well this is annoying. When we reported this to Mozilla guys they just believe we are building Thunderbird in a wrong way. And it seems they have no interest to use a latest Rustc/LLVM in their CI. We are not Mozilla developers so it seems we cannot review the large code base to find what's wrong...

Are there any tools (test case reducer or UBsan) may help? Or is it possible to disable this optimization via some RUSTFLAGS as a work around?