126 const mlir::DataLayout &dataLayout) {
127 LDBG() <<
"Decomposing pointer: " << val;
129 std::optional<int64_t> offset = 0;
132 mlir::Operation *defOp = val.getDefiningOp();
134 LDBG() <<
"No defining operation, stopping";
140 if (
auto castOp = mlir::dyn_cast<cir::CastOp>(defOp)) {
141 if (castOp.isAllocaPreservingCast() ||
142 castOp.getKind() == cir::CastKind::array_to_ptrdecay) {
143 LDBG() <<
"Walking past cast operation";
144 val = castOp.getSrc();
147 LDBG() <<
"Opaque cast operation, stopping";
152 if (
auto strideOp = mlir::dyn_cast<cir::PtrStrideOp>(defOp)) {
153 LDBG() <<
"Walking past PtrStrideOp";
158 val = strideOp.getBase();
163 if (
auto memberOp = mlir::dyn_cast<cir::GetMemberOp>(defOp)) {
164 LDBG() <<
"Walking past GetMemberOp";
166 mlir::cast<cir::RecordType>(memberOp.getAddrTy().getPointee());
167 std::optional<int64_t> memberOffset;
168 if (!recordTy.isIncomplete())
170 recordTy.getElementOffset(dataLayout, memberOp.getIndex());
172 val = memberOp.getAddr();
177 if (
auto elementOp = mlir::dyn_cast<cir::GetElementOp>(defOp)) {
178 LDBG() <<
"Walking past GetElementOp";
183 val = elementOp.getBase();
191 if (
auto baseOp = mlir::dyn_cast<cir::BaseClassAddrOp>(defOp)) {
192 LDBG() <<
"Walking past BaseClassAddrOp";
193 addToOffset(offset, baseOp.getOffset().tryZExtValue());
194 val = baseOp.getSrcAddr();
202 if (
auto derivedOp = mlir::dyn_cast<cir::DerivedClassAddrOp>(defOp)) {
203 LDBG() <<
"Walking past DerivedClassAddrOp";
204 std::optional<int64_t> baseOffset = derivedOp.getOffset().tryZExtValue();
206 baseOffset = -*baseOffset;
208 val = derivedOp.getSrcAddr();
214 if (
auto realOp = mlir::dyn_cast<cir::ComplexRealPtrOp>(defOp)) {
215 LDBG() <<
"Walking past ComplexRealPtrOp";
216 val = realOp.getOperand();
219 if (
auto imagOp = mlir::dyn_cast<cir::ComplexImagPtrOp>(defOp)) {
220 LDBG() <<
"Walking past ComplexImagPtrOp";
221 auto ptrTy = mlir::cast<cir::PointerType>(imagOp.getOperand().getType());
222 auto complexTy = mlir::cast<cir::ComplexType>(ptrTy.getPointee());
225 val = imagOp.getOperand();
229 LDBG() <<
"Unhandled operation, stopping";
233 return {val, offset};
253 LDBG() <<
"Checking alias between: " << lhs <<
" and " << rhs;
256 LDBG() <<
"Trivial alias between identical values";
257 return mlir::AliasResult::MustAlias;
263 if (lhsPtr.base != rhsPtr.base) {
265 LDBG() <<
"No alias between pointers into distinct objects";
266 return mlir::AliasResult::NoAlias;
268 LDBG() <<
"Unrelated base objects, may alias";
269 return mlir::AliasResult::MayAlias;
274 if (!lhsPtr.offset || !rhsPtr.offset) {
275 LDBG() <<
"Same object at an unknown offset, may alias";
276 return mlir::AliasResult::MayAlias;
281 if (*lhsPtr.offset == *rhsPtr.offset) {
282 LDBG() <<
"Must alias at the same address within the same object";
283 return mlir::AliasResult::MustAlias;
289 std::optional<int64_t> lhsSize =
getAccessSize(lhs, dataLayout);
290 std::optional<int64_t> rhsSize =
getAccessSize(rhs, dataLayout);
291 if (!lhsSize || !rhsSize) {
292 LDBG() <<
"Same object but unknown access size, may alias";
293 return mlir::AliasResult::MayAlias;
296 auto [lhsEnd, lhsOverflow] = AddOverflow(*lhsPtr.offset, *lhsSize);
297 auto [rhsEnd, rhsOverflow] = AddOverflow(*rhsPtr.offset, *rhsSize);
298 if (lhsOverflow || rhsOverflow) {
299 LDBG() <<
"Access range overflows, may alias";
300 return mlir::AliasResult::MayAlias;
303 if (lhsEnd <= *rhsPtr.offset || rhsEnd <= *lhsPtr.offset) {
304 LDBG() <<
"No alias between disjoint ranges of the same object";
305 return mlir::AliasResult::NoAlias;
308 LDBG() <<
"Partial alias between overlapping ranges of the same object";
309 return mlir::AliasResult::PartialAlias;
313 mlir::Value location) {
314 LDBG() <<
"getModRef: "
315 << mlir::OpWithFlags(op, mlir::OpPrintingFlags().skipRegions())
316 <<
" on location " << location;
318 auto effects = mlir::dyn_cast<mlir::MemoryEffectOpInterface>(op);
320 LDBG() <<
"No memory effect interface, returning ModAndRef";
321 return mlir::ModRefResult::getModAndRef();
325 effects.getEffects(effectList);
327 auto classifyEffect = [location,
this](
328 const mlir::MemoryEffects::EffectInstance &effect) {
329 if (mlir::isa<mlir::MemoryEffects::Allocate>(effect.getEffect())) {
330 LDBG() <<
"Skipping allocate effect";
331 return mlir::ModRefResult::getNoModRef();
334 mlir::AliasResult aliasResult = mlir::AliasResult::MayAlias;
335 if (mlir::Value affectedLocation = effect.getValue()) {
336 LDBG() <<
" Checking alias between affected location "
337 << affectedLocation <<
" and query location " << location;
338 aliasResult =
alias(affectedLocation, location);
339 LDBG() <<
" Alias result: " << aliasResult;
343 if (!effect.getResource()->isAddressable()) {
344 LDBG() <<
" Effect on non-addressable resource '"
345 << effect.getResource()->getName() <<
"', skipping (NoAlias)";
346 aliasResult = mlir::AliasResult::NoAlias;
348 LDBG() <<
" No effect value, assuming MayAlias";
354 if (aliasResult.isNo()) {
355 LDBG() <<
"No alias with affected location";
356 return mlir::ModRefResult::getNoModRef();
360 if (mlir::isa<mlir::MemoryEffects::Free>(effect.getEffect())) {
361 LDBG() <<
"Skipping free effect";
362 return mlir::ModRefResult::getModAndRef();
365 if (mlir::isa<mlir::MemoryEffects::Write>(effect.getEffect())) {
366 LDBG() <<
"Write effect, adding Mod";
367 return mlir::ModRefResult::getMod();
370 if (mlir::isa<mlir::MemoryEffects::Read>(effect.getEffect())) {
371 LDBG() <<
"Read effect, adding Ref";
372 return mlir::ModRefResult::getRef();
375 LDBG() <<
"Unexpected memory effect: " << effect.getEffect();
376 return mlir::ModRefResult::getNoModRef();
379 return llvm::accumulate(llvm::map_range(effectList, classifyEffect),
380 mlir::ModRefResult::getNoModRef(),
381 [](mlir::ModRefResult lhs, mlir::ModRefResult rhs) {
382 return lhs.merge(rhs);
static void addToOffset(std::optional< int64_t > &offset, std::optional< int64_t > delta)
Add delta bytes to offset, making the offset unknown if delta is unknown or if the sum overflows.
static std::optional< int64_t > getTypeSizeInBytes(mlir::Type type, const mlir::DataLayout &dataLayout)
Return the size in bytes of type, or std::nullopt when that size isn't statically known (void,...
static std::optional< int64_t > scaleOffset(std::optional< int64_t > count, std::optional< int64_t > size)
Return count * size, or std::nullopt if either input is unknown or the product overflows.
static PointerOffset decomposePointer(mlir::Value val, const mlir::DataLayout &dataLayout)
Trace val back to the object it points into, accumulating the byte offset of val from the start of th...
static std::optional< int64_t > getAccessSize(mlir::Value ptr, const mlir::DataLayout &dataLayout)
Return the number of bytes an access through ptr touches, that is, the size of its pointee type.