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;
60 ValueRange inputs = branch.getSuccessorInputs(initialSuccessor);
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 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";
174 if (successor.getSuccessor() == region) {
175 LDBG() <<
" Found matching region successor: " << successor;
177 branch, successor, arg, argNumber, maxDepth, visited, output);
180 LDBG() <<
" No matching region successor found, adding argument to output";
181 output.push_back(arg);
186 <<
" Cannot reason about underlying address, adding argument to output";
188 output.push_back(arg);
195 LDBG() <<
"collectUnderlyingAddressValues: " << value;
196 LDBG() <<
" maxDepth: " << maxDepth;
199 if (!visited.insert(value).second) {
200 LDBG() <<
" Value already visited, skipping";
204 LDBG() <<
" Max depth reached, adding value to output";
205 output.push_back(value);
211 LDBG() <<
" Processing as BlockArgument";
214 LDBG() <<
" Processing as OpResult";
222 LDBG() <<
"collectUnderlyingAddressValues: " << value;
226 LDBG() <<
" Collected " << output.size() <<
" underlying values";
241 std::optional<MemoryEffects::EffectInstance> &effect,
243 LDBG() <<
"getAllocEffectFor: " << value;
249 LDBG() <<
" BlockArgument, parent op: "
252 op = cast<OpResult>(value).getOwner();
253 LDBG() <<
" OpResult, owner op: "
257 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
259 LDBG() <<
" No memory effect interface found";
265 LDBG() <<
" No allocation effect found on value";
269 LDBG() <<
" Found allocation effect";
274 if (llvm::isa<SideEffects::AutomaticAllocationScopeResource>(
275 effect->getResource())) {
276 allocScopeOp = op->getParentWithTrait<OpTrait::AutomaticAllocationScope>();
278 LDBG() <<
" Automatic allocation scope found: "
279 << OpWithFlags(allocScopeOp, OpPrintingFlags().skipRegions());
281 LDBG() <<
" Automatic allocation scope found: null";
290 allocScopeOp = op->getParentOfType<FunctionOpInterface>();
292 LDBG() <<
" Function scope found: "
295 LDBG() <<
" Function scope found: null";
308 unsigned argNumber = cast<OpResult>(value).getResultNumber();
314 assert(
lhs !=
rhs &&
"lhs and rhs must be different");
327 if (lhsOp && lhsOp == rhsOp)
335 LDBG() <<
"aliasImpl: " <<
lhs <<
" vs " <<
rhs;
338 LDBG() <<
" Same value, must alias";
342 Operation *lhsAllocScope =
nullptr, *rhsAllocScope =
nullptr;
343 std::optional<MemoryEffects::EffectInstance> lhsAlloc, rhsAlloc;
348 LDBG() <<
" lhs is constant";
353 LDBG() <<
" rhs is also constant, may alias";
361 LDBG() <<
" rhs has alloc effect: " << rhsHasAlloc;
366 LDBG() <<
" rhs is constant";
371 LDBG() <<
" lhs has alloc effect: " << lhsHasAlloc;
382 LDBG() <<
" lhs has alloc effect: " << lhsHasAlloc;
383 LDBG() <<
" rhs has alloc effect: " << rhsHasAlloc;
385 if (lhsHasAlloc == rhsHasAlloc) {
388 LDBG() <<
" Both have same alloc status: "
389 << (lhsHasAlloc ?
"NoAlias" :
"MayAlias");
397 LDBG() <<
" Swapping lhs and rhs to put alloc effect on lhs";
400 lhsAllocScope = rhsAllocScope;
406 LDBG() <<
" Checking allocation scope: "
411 Operation *rhsParentOp =
rhs.getParentRegion()->getParentOp();
413 LDBG() <<
" rhs parent is ancestor of alloc scope, no alias";
416 if (rhsParentOp == lhsAllocScope) {
418 if (rhsArg &&
rhs.getParentBlock()->isEntryBlock()) {
419 LDBG() <<
" rhs is entry block arg of alloc scope, no alias";
427 LDBG() <<
" Cannot reason about relationship, may alias";
433 LDBG() <<
"alias: " <<
lhs <<
" vs " <<
rhs;
436 LDBG() <<
" Same value, must alias";
445 LDBG() <<
" lhs underlying values: " << lhsValues.size();
446 LDBG() <<
" rhs underlying values: " << rhsValues.size();
450 if (lhsValues.empty() || rhsValues.empty()) {
451 LDBG() <<
" Failed to collect underlying values, may alias";
456 std::optional<AliasResult>
result;
457 for (
Value lhsVal : lhsValues) {
458 for (
Value rhsVal : rhsValues) {
459 LDBG() <<
" Checking underlying values: " << lhsVal <<
" vs " << rhsVal;
461 LDBG() <<
" Result: "
470 LDBG() <<
" Final result: "
471 << (
result->isMust() ?
"MustAlias"
472 :
result->isNo() ?
"NoAlias"
483 <<
" on location " << location;
487 LDBG() <<
" Operation has recursive memory effects, returning ModAndRef";
497 MemoryEffectOpInterface
interface = dyn_cast<MemoryEffectOpInterface>(op);
499 LDBG() <<
" No memory effect interface, returning ModAndRef";
506 interface.getEffects(effects);
507 LDBG() <<
" Found " << effects.size() <<
" memory effects";
511 if (isa<MemoryEffects::Allocate, MemoryEffects::Free>(effect.getEffect())) {
512 LDBG() <<
" Skipping alloc/free effect";
519 if (
Value effectValue = effect.getValue()) {
520 LDBG() <<
" Checking alias between effect value " << effectValue
521 <<
" and location " << location;
522 aliasResult =
alias(effectValue, location);
523 LDBG() <<
" Alias result: "
524 << (aliasResult.
isMust() ?
"MustAlias"
525 : aliasResult.
isNo() ?
"NoAlias"
528 LDBG() <<
" No effect value, assuming MayAlias";
532 if (aliasResult.
isNo()) {
533 LDBG() <<
" No alias, ignoring effect";
538 if (isa<MemoryEffects::Read>(effect.getEffect())) {
539 LDBG() <<
" Adding Ref to result";
542 assert(isa<MemoryEffects::Write>(effect.getEffect()));
543 LDBG() <<
" Adding Mod to result";
546 if (
result.isModAndRef()) {
547 LDBG() <<
" Result is now ModAndRef, breaking";
552 LDBG() <<
" Final ModRef result: "
553 << (
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...
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.
static RegionSuccessor parent()
Initialize a successor that branches after/out of the parent operation.
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.