-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LAA] Perform checks for no-wrap separately from getPtrStride. #126971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -855,16 +855,61 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy, | |
return Stride; | ||
} | ||
|
||
static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR, | ||
PredicatedScalarEvolution &PSE, const Loop *L); | ||
|
||
/// Check whether a pointer address cannot wrap. | ||
static bool isNoWrap(PredicatedScalarEvolution &PSE, | ||
const DenseMap<Value *, const SCEV *> &Strides, Value *Ptr, | ||
Type *AccessTy, Loop *L, bool Assume) { | ||
const SCEV *PtrScev = PSE.getSCEV(Ptr); | ||
Type *AccessTy, const Loop *L, bool Assume, | ||
std::optional<int64_t> Stride = std::nullopt) { | ||
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, Strides, Ptr); | ||
if (PSE.getSE()->isLoopInvariant(PtrScev, L)) | ||
return true; | ||
|
||
return getPtrStride(PSE, AccessTy, Ptr, L, Strides, Assume).has_value() || | ||
PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); | ||
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(PtrScev); | ||
if (!AR) { | ||
if (!Assume) | ||
return false; | ||
AR = PSE.getAsAddRec(Ptr); | ||
} | ||
|
||
// The address calculation must not wrap. Otherwise, a dependence could be | ||
// inverted. | ||
if (isNoWrapAddRec(Ptr, AR, PSE, L)) | ||
return true; | ||
|
||
// An nusw getelementptr that is an AddRec cannot wrap. If it would wrap, | ||
// the distance between the previously accessed location and the wrapped | ||
// location will be larger than half the pointer index type space. In that | ||
// case, the GEP would be poison and any memory access dependent on it would | ||
// be immediate UB when executed. | ||
if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr); | ||
GEP && GEP->hasNoUnsignedSignedWrap()) | ||
return true; | ||
|
||
if (!Stride) | ||
Stride = getStrideFromAddRec(AR, L, AccessTy, Ptr, PSE); | ||
if (Stride) { | ||
// If the null pointer is undefined, then a access sequence which would | ||
// otherwise access it can be assumed not to unsigned wrap. Note that this | ||
// assumes the object in memory is aligned to the natural alignment. | ||
unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/Ptr->getType()/AccessTy/? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think here we need the pointer type (which has the accessed address-space) vs |
||
if (!NullPointerIsDefined(L->getHeader()->getParent(), AddrSpace) && | ||
(Stride == 1 || Stride == -1)) | ||
return true; | ||
} | ||
|
||
if (Assume) { | ||
PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); | ||
LLVM_DEBUG(dbgs() << "LAA: Pointer may wrap:\n" | ||
<< "LAA: Pointer: " << *Ptr << "\n" | ||
<< "LAA: SCEV: " << *AR << "\n" | ||
<< "LAA: Added an overflow assumption\n"); | ||
return true; | ||
} | ||
|
||
return PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); | ||
} | ||
|
||
static void visitPointers(Value *StartPtr, const Loop &InnermostLoop, | ||
|
@@ -1505,36 +1550,9 @@ llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr, | |
if (!ShouldCheckWrap || !Stride) | ||
return Stride; | ||
|
||
// The address calculation must not wrap. Otherwise, a dependence could be | ||
// inverted. | ||
if (isNoWrapAddRec(Ptr, AR, PSE, Lp)) | ||
return Stride; | ||
|
||
// An nusw getelementptr that is an AddRec cannot wrap. If it would wrap, | ||
// the distance between the previously accessed location and the wrapped | ||
// location will be larger than half the pointer index type space. In that | ||
// case, the GEP would be poison and any memory access dependent on it would | ||
// be immediate UB when executed. | ||
if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr); | ||
GEP && GEP->hasNoUnsignedSignedWrap()) | ||
return Stride; | ||
|
||
// If the null pointer is undefined, then a access sequence which would | ||
// otherwise access it can be assumed not to unsigned wrap. Note that this | ||
// assumes the object in memory is aligned to the natural alignment. | ||
unsigned AddrSpace = Ty->getPointerAddressSpace(); | ||
if (!NullPointerIsDefined(Lp->getHeader()->getParent(), AddrSpace) && | ||
(Stride == 1 || Stride == -1)) | ||
if (isNoWrap(PSE, StridesMap, Ptr, AccessTy, Lp, Assume, Stride)) | ||
return Stride; | ||
|
||
if (Assume) { | ||
PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); | ||
LLVM_DEBUG(dbgs() << "LAA: Pointer may wrap:\n" | ||
<< "LAA: Pointer: " << *Ptr << "\n" | ||
<< "LAA: SCEV: " << *AR << "\n" | ||
<< "LAA: Added an overflow assumption\n"); | ||
return Stride; | ||
} | ||
LLVM_DEBUG( | ||
dbgs() << "LAA: Bad stride - Pointer may wrap in the address space " | ||
<< *Ptr << " SCEV: " << *AR << "\n"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isNoWrapAddRec has this whole dance for analyzing nusw. It seems very odd to have the unchecked form right after a call to that routine?
(Though, now I see that in the current code too?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep this just moves the existing code. I could look into revisiting/consolidating this with
isNoWrapAddRec
separately?