This is an archive of the discontinued LLVM Phabricator instance.

[MemorySSA] Iteratively check if gep's pointer operand is a guaranteed loop invariant
AcceptedPublic

Authored by StephenFan on Feb 9 2023, 5:19 AM.

Details

Reviewers
nikic
asbirlea
Summary

On the past, we just check if gep's pointer operand is a non-instruction
operand or is a alloca instruction to decide if it is guaranteed to be
a loop invariant. If the gep's pointer operand is also a gep then it would
be considered to be a non-guaranteed loop invariant. This patch makes
MemorySSA Recursively checking if gep's pointer operand is guaranteed
to be a loop invariant.

Diff Detail

Event Timeline

StephenFan created this revision.Feb 9 2023, 5:19 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 9 2023, 5:19 AM
StephenFan requested review of this revision.Feb 9 2023, 5:19 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 9 2023, 5:19 AM
asbirlea added inline comments.Feb 9 2023, 2:22 PM
llvm/lib/Analysis/MemorySSA.cpp
2642–2643

This recursion should not be unbounded, and preferably make it iterative.
A similar example: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/ValueTracking.cpp#L4568

Replace recursion as bounded iteration.

StephenFan retitled this revision from [MemorySSA] Recursively check if gep's pointer operand is a guaranteed loop invariant to [MemorySSA] Iteratively check if gep's pointer operand is a guaranteed loop invariant.

Remove TODO.

asbirlea accepted this revision.Feb 14 2023, 12:03 AM

lgtm with comments addressed.

llvm/lib/Analysis/MemorySSA.cpp
2629

The AA "look through geps" limit is 6. I don't have a strong preference on the value, I don't have any data on how frequent this will be useful..
Would be good to use a cl::opt instead of a local constant though, for easier testing.

2640

nit: Could reduce the if nesting

auto *I = dyn_cast<Instruction>(Ptr);
if (!I || isa<AllocaInst>(Ptr) || I->getParent()->isEntryBlock())
  return true;
 
if (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
  if (!GEP->hasAllConstantIndices())
    return false;
  Ptr = GEP->getPointerOperand();
}
This revision is now accepted and ready to land.Feb 14 2023, 12:03 AM

I'm curious where this came up in practice. Constant GEP based on constant GEP gets merged by InstCombine.

FWIW, we have a stripInBoundsConstantOffsets() method, which does nearly what we want here. I wonder whether it would make sense to add a new PointerStripKind for this? (I think some existing users of stripInBoundsConstantOffsets don't actually need the "inbounds" part and just end up using it because it's convenient.)

I'm curious where this came up in practice. Constant GEP based on constant GEP gets merged by InstCombine.

TBH, The test was constructed by hand. So it may not make sense in practice since as you said it always gets merged by InstCombine. But that reminds me if it makes sense to also check whether the index operands are invariant?

FWIW, we have a stripInBoundsConstantOffsets() method, which does nearly what we want here. I wonder whether it would make sense to add a new PointerStripKind for this? (I think some existing users of stripInBoundsConstantOffsets don't actually need the "inbounds" part and just end up using it because it's convenient.)

I think it makes sense. If I use the stripInBoundsConstantOffsets() here, I will not care about the inbounds flag.