24#include "llvm/Support/Casting.h"
25#include "llvm/Support/DebugLog.h"
32#define DEBUG_TYPE "local-alias-analysis"
52 Value inputValue,
unsigned inputIndex,
unsigned maxDepth,
54 LDBG() <<
"collectUnderlyingAddressValues2: "
56 LDBG() <<
" with initialSuccessor " << initialSuccessor;
57 LDBG() <<
" inputValue: " << inputValue;
58 LDBG() <<
" inputIndex: " << inputIndex;
59 LDBG() <<
" maxDepth: " << maxDepth;
62 LDBG() <<
" input is empty, enqueue value";
63 output.push_back(inputValue);
66 unsigned firstInputIndex, lastInputIndex;
67 if (isa<BlockArgument>(inputs[0])) {
68 firstInputIndex = cast<BlockArgument>(inputs[0]).getArgNumber();
69 lastInputIndex = cast<BlockArgument>(inputs.back()).getArgNumber();
71 firstInputIndex = cast<OpResult>(inputs[0]).getResultNumber();
72 lastInputIndex = cast<OpResult>(inputs.back()).getResultNumber();
74 if (firstInputIndex > inputIndex || lastInputIndex < inputIndex) {
75 LDBG() <<
" !! Input index " << inputIndex <<
" out of range "
76 << firstInputIndex <<
" to " << lastInputIndex
77 <<
", adding input value to output";
78 output.push_back(inputValue);
82 branch.getPredecessorValues(initialSuccessor, inputIndex - firstInputIndex,
84 LDBG() <<
" Found " << predecessorValues.size() <<
" predecessor values";
85 for (
Value predecessorValue : predecessorValues) {
86 LDBG() <<
" Processing predecessor value: " << predecessorValue;
95 LDBG() <<
"collectUnderlyingAddressValues (OpResult): " <<
result;
96 LDBG() <<
" maxDepth: " << maxDepth;
101 if (ViewLikeOpInterface view = dyn_cast<ViewLikeOpInterface>(op)) {
102 if (
result == view.getViewDest()) {
103 LDBG() <<
" Unwrapping view to source: " << view.getViewSource();
109 if (
auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
110 LDBG() <<
" Processing region branch operation";
113 result.getResultNumber(), maxDepth, visited, output);
116 LDBG() <<
" Adding result to output: " <<
result;
125 LDBG() <<
"collectUnderlyingAddressValues (BlockArgument): " << arg;
126 LDBG() <<
" maxDepth: " << maxDepth;
135 LDBG() <<
" Processing non-entry block with "
139 auto branch = dyn_cast<BranchOpInterface>((*it)->getTerminator());
141 LDBG() <<
" Cannot analyze control flow, adding argument to output";
143 output.push_back(arg);
148 unsigned index = it.getSuccessorIndex();
149 Value operand = branch.getSuccessorOperands(
index)[argNumber];
151 LDBG() <<
" No operand found for argument, adding to output";
153 output.push_back(arg);
156 LDBG() <<
" Processing operand from predecessor: " << operand;
165 if (
auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
166 LDBG() <<
" Processing region branch operation for entry block";
176 if (successor.getSuccessor() == region) {
177 LDBG() <<
" Found matching region successor: " << successor;
179 regionSuccessor = successor;
185 <<
" No matching region successor found, adding argument to output";
186 output.push_back(arg);
190 branch, regionSuccessor, arg, argNumber, maxDepth, visited, output);
194 <<
" Cannot reason about underlying address, adding argument to output";
196 output.push_back(arg);
203 LDBG() <<
"collectUnderlyingAddressValues: " << value;
204 LDBG() <<
" maxDepth: " << maxDepth;
207 if (!visited.insert(value).second) {
208 LDBG() <<
" Value already visited, skipping";
212 LDBG() <<
" Max depth reached, adding value to output";
213 output.push_back(value);
219 LDBG() <<
" Processing as BlockArgument";
222 LDBG() <<
" Processing as OpResult";
230 LDBG() <<
"collectUnderlyingAddressValues: " << value;
234 LDBG() <<
" Collected " << output.size() <<
" underlying values";
249 std::optional<MemoryEffects::EffectInstance> &effect,
251 LDBG() <<
"getAllocEffectFor: " << value;
257 LDBG() <<
" BlockArgument, parent op: "
260 op = cast<OpResult>(value).getOwner();
261 LDBG() <<
" OpResult, owner op: "
265 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
267 LDBG() <<
" No memory effect interface found";
273 LDBG() <<
" No allocation effect found on value";
277 LDBG() <<
" Found allocation effect";
282 if (llvm::isa<SideEffects::AutomaticAllocationScopeResource>(
283 effect->getResource())) {
284 allocScopeOp = op->getParentWithTrait<OpTrait::AutomaticAllocationScope>();
286 LDBG() <<
" Automatic allocation scope found: "
287 << OpWithFlags(allocScopeOp, OpPrintingFlags().skipRegions());
289 LDBG() <<
" Automatic allocation scope found: null";
298 allocScopeOp = op->getParentOfType<FunctionOpInterface>();
300 LDBG() <<
" Function scope found: "
303 LDBG() <<
" Function scope found: null";
316 unsigned argNumber = cast<OpResult>(value).getResultNumber();
322 assert(
lhs !=
rhs &&
"lhs and rhs must be different");
335 if (lhsOp && lhsOp == rhsOp)
343 LDBG() <<
"aliasImpl: " <<
lhs <<
" vs " <<
rhs;
346 LDBG() <<
" Same value, must alias";
350 Operation *lhsAllocScope =
nullptr, *rhsAllocScope =
nullptr;
351 std::optional<MemoryEffects::EffectInstance> lhsAlloc, rhsAlloc;
356 LDBG() <<
" lhs is constant";
361 LDBG() <<
" rhs is also constant, may alias";
369 LDBG() <<
" rhs has alloc effect: " << rhsHasAlloc;
374 LDBG() <<
" rhs is constant";
379 LDBG() <<
" lhs has alloc effect: " << lhsHasAlloc;
390 LDBG() <<
" lhs has alloc effect: " << lhsHasAlloc;
391 LDBG() <<
" rhs has alloc effect: " << rhsHasAlloc;
393 if (lhsHasAlloc == rhsHasAlloc) {
396 LDBG() <<
" Both have same alloc status: "
397 << (lhsHasAlloc ?
"NoAlias" :
"MayAlias");
405 LDBG() <<
" Swapping lhs and rhs to put alloc effect on lhs";
408 lhsAllocScope = rhsAllocScope;
414 LDBG() <<
" Checking allocation scope: "
419 Operation *rhsParentOp =
rhs.getParentRegion()->getParentOp();
421 LDBG() <<
" rhs parent is ancestor of alloc scope, no alias";
424 if (rhsParentOp == lhsAllocScope) {
426 if (rhsArg &&
rhs.getParentBlock()->isEntryBlock()) {
427 LDBG() <<
" rhs is entry block arg of alloc scope, no alias";
435 LDBG() <<
" Cannot reason about relationship, may alias";
441 LDBG() <<
"alias: " <<
lhs <<
" vs " <<
rhs;
444 LDBG() <<
" Same value, must alias";
453 LDBG() <<
" lhs underlying values: " << lhsValues.size();
454 LDBG() <<
" rhs underlying values: " << rhsValues.size();
458 if (lhsValues.empty() || rhsValues.empty()) {
459 LDBG() <<
" Failed to collect underlying values, may alias";
464 std::optional<AliasResult>
result;
465 for (
Value lhsVal : lhsValues) {
466 for (
Value rhsVal : rhsValues) {
467 LDBG() <<
" Checking underlying values: " << lhsVal <<
" vs " << rhsVal;
469 LDBG() <<
" Result: "
478 LDBG() <<
" Final result: "
479 << (
result->isMust() ?
"MustAlias"
480 :
result->isNo() ?
"NoAlias"
491 <<
" on location " << location;
495 LDBG() <<
" Operation has recursive memory effects, returning ModAndRef";
505 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
507 LDBG() <<
" No memory effect interface, returning ModAndRef";
514 interface.getEffects(effects);
515 LDBG() <<
" Found " << effects.size() <<
" memory effects";
519 if (isa<MemoryEffects::Allocate, MemoryEffects::Free>(effect.getEffect())) {
520 LDBG() <<
" Skipping alloc/free effect";
527 if (
Value effectValue = effect.getValue()) {
528 LDBG() <<
" Checking alias between effect value " << effectValue
529 <<
" and location " << location;
530 aliasResult =
alias(effectValue, location);
531 LDBG() <<
" Alias result: "
532 << (aliasResult.
isMust() ?
"MustAlias"
533 : aliasResult.
isNo() ?
"NoAlias"
536 LDBG() <<
" No effect value, assuming MayAlias";
540 if (aliasResult.
isNo()) {
541 LDBG() <<
" No alias, ignoring effect";
546 if (isa<MemoryEffects::Read>(effect.getEffect())) {
547 LDBG() <<
" Adding Ref to result";
550 assert(isa<MemoryEffects::Write>(effect.getEffect()));
551 LDBG() <<
" Adding Mod to result";
554 if (
result.isModAndRef()) {
555 LDBG() <<
" Result is now ModAndRef, breaking";
560 LDBG() <<
" Final ModRef result: "
561 << (
result.isModAndRef() ?
"ModAndRef"
static std::optional< AliasResult > checkDistinctObjects(Value lhs, Value rhs)
static LogicalResult getAllocEffectFor(Value value, std::optional< MemoryEffects::EffectInstance > &effect, Operation *&allocScopeOp)
Given a value, try to get an allocation effect attached to it.
static void collectUnderlyingAddressValues(Value value, unsigned maxDepth, DenseSet< Value > &visited, SmallVectorImpl< Value > &output)
Given a value, collect all of the underlying values being addressed.
static constexpr unsigned maxUnderlyingValueSearchDepth
The maximum depth that will be searched when trying to find an underlying value.
static void collectUnderlyingAddressValues2(RegionBranchOpInterface branch, RegionSuccessor initialSuccessor, Value inputValue, unsigned inputIndex, unsigned maxDepth, DenseSet< Value > &visited, SmallVectorImpl< Value > &output)
Given a RegionBranchOpInterface operation (branch), a ValueinputValue which is an input for the provi...
static Value getDistinctObjectsOperand(Operation *op, Value value)
static Operation * isDistinctObjectsOp(Operation *op)
The possible results of an alias query.
bool isMust() const
Returns if this result is a must alias.
bool isNo() const
Returns if this result indicates no possibility of aliasing.
@ MustAlias
The two locations precisely alias each other.
@ MayAlias
The two locations may or may not alias.
@ NoAlias
The two locations do not alias at all.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
unsigned getArgNumber() const
Returns the number of this argument.
Block * getOwner() const
Returns the block that owns this argument.
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
pred_iterator pred_begin()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
ModRefResult getModRef(Operation *op, Value location)
Return the modify-reference behavior of op on location.
virtual AliasResult aliasImpl(Value lhs, Value rhs)
Given the two values, return their aliasing behavior.
AliasResult alias(Value lhs, Value rhs)
Given two values, return their aliasing behavior.
The possible results of whether a memory access modifies or references a memory location.
static ModRefResult getRef()
Return a new result that indicates that the memory access may reference the value stored in memory.
static ModRefResult getNoModRef()
Return a new result that indicates that the memory access neither references nor modifies the value s...
static ModRefResult getModAndRef()
Return a new result that indicates that the memory access may reference and may modify the value stor...
static ModRefResult getMod()
Return a new result that indicates that the memory access may modify the value stored in memory.
Set of flags used to control the behavior of the various IR print methods (e.g.
This is a value defined by a result of an operation.
This trai indicates that pointer-like objects (such as memrefs) returned from this operation will nev...
This trait indicates that the memory effects of an operation includes the effects of operations neste...
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
result_range getResults()
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
static constexpr RegionBranchPoint parent()
Returns an instance of RegionBranchPoint representing the parent operation.
This class represents a successor of a region.
ValueRange getSuccessorInputs() const
Return the inputs to the successor that are remapped by the exit values of the current region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Operation * getParentOp()
Return the parent operation this region is attached to.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
SideEffects::EffectInstance< Effect > EffectInstance
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
The following effect indicates that the operation allocates from some resource.