xref: /llvm-project/mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1b9c876bdSRiver Riddle //===- LocalAliasAnalysis.cpp - Local stateless alias Analysis for MLIR ---===//
2b9c876bdSRiver Riddle //
3b9c876bdSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b9c876bdSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5b9c876bdSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b9c876bdSRiver Riddle //
7b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
8b9c876bdSRiver Riddle 
9b9c876bdSRiver Riddle #include "mlir/Analysis/AliasAnalysis/LocalAliasAnalysis.h"
10b9c876bdSRiver Riddle 
11*a2e69c57SMehdi Amini #include "mlir/Analysis/AliasAnalysis.h"
12*a2e69c57SMehdi Amini #include "mlir/IR/Attributes.h"
13*a2e69c57SMehdi Amini #include "mlir/IR/Block.h"
14b9c876bdSRiver Riddle #include "mlir/IR/Matchers.h"
15*a2e69c57SMehdi Amini #include "mlir/IR/OpDefinition.h"
16*a2e69c57SMehdi Amini #include "mlir/IR/Operation.h"
17*a2e69c57SMehdi Amini #include "mlir/IR/Region.h"
18*a2e69c57SMehdi Amini #include "mlir/IR/Value.h"
19*a2e69c57SMehdi Amini #include "mlir/IR/ValueRange.h"
20b9c876bdSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h"
2134a35a8bSMartin Erhart #include "mlir/Interfaces/FunctionInterfaces.h"
22b9c876bdSRiver Riddle #include "mlir/Interfaces/SideEffectInterfaces.h"
23b9c876bdSRiver Riddle #include "mlir/Interfaces/ViewLikeInterface.h"
24*a2e69c57SMehdi Amini #include "mlir/Support/LLVM.h"
25*a2e69c57SMehdi Amini #include "llvm/Support/Casting.h"
26*a2e69c57SMehdi Amini #include <cassert>
27100c3867SKazu Hirata #include <optional>
28*a2e69c57SMehdi Amini #include <utility>
29b9c876bdSRiver Riddle 
30b9c876bdSRiver Riddle using namespace mlir;
31b9c876bdSRiver Riddle 
32b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
33b9c876bdSRiver Riddle // Underlying Address Computation
34b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
35b9c876bdSRiver Riddle 
36b9c876bdSRiver Riddle /// The maximum depth that will be searched when trying to find an underlying
37b9c876bdSRiver Riddle /// value.
38b9c876bdSRiver Riddle static constexpr unsigned maxUnderlyingValueSearchDepth = 10;
39b9c876bdSRiver Riddle 
40b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
41b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value, unsigned maxDepth,
42b9c876bdSRiver Riddle                                            DenseSet<Value> &visited,
43b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output);
44b9c876bdSRiver Riddle 
45b9c876bdSRiver Riddle /// Given a successor (`region`) of a RegionBranchOpInterface, collect all of
46b9c876bdSRiver Riddle /// the underlying values being addressed by one of the successor inputs. If the
47b9c876bdSRiver Riddle /// provided `region` is null, as per `RegionBranchOpInterface` this represents
48b9c876bdSRiver Riddle /// the parent operation.
collectUnderlyingAddressValues(RegionBranchOpInterface branch,Region * region,Value inputValue,unsigned inputIndex,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)49b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(RegionBranchOpInterface branch,
50b9c876bdSRiver Riddle                                            Region *region, Value inputValue,
51b9c876bdSRiver Riddle                                            unsigned inputIndex,
52b9c876bdSRiver Riddle                                            unsigned maxDepth,
53b9c876bdSRiver Riddle                                            DenseSet<Value> &visited,
54b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output) {
55192d9dd7SKazu Hirata   // Given the index of a region of the branch (`predIndex`), or std::nullopt to
56b9c876bdSRiver Riddle   // represent the parent operation, try to return the index into the outputs of
57b9c876bdSRiver Riddle   // this region predecessor that correspond to the input values of `region`. If
58192d9dd7SKazu Hirata   // an index could not be found, std::nullopt is returned instead.
59b9c876bdSRiver Riddle   auto getOperandIndexIfPred =
604dd744acSMarkus Böck       [&](RegionBranchPoint pred) -> std::optional<unsigned> {
61b9c876bdSRiver Riddle     SmallVector<RegionSuccessor, 2> successors;
624dd744acSMarkus Böck     branch.getSuccessorRegions(pred, successors);
63b9c876bdSRiver Riddle     for (RegionSuccessor &successor : successors) {
64b9c876bdSRiver Riddle       if (successor.getSuccessor() != region)
65b9c876bdSRiver Riddle         continue;
66b9c876bdSRiver Riddle       // Check that the successor inputs map to the given input value.
67b9c876bdSRiver Riddle       ValueRange inputs = successor.getSuccessorInputs();
68b9c876bdSRiver Riddle       if (inputs.empty()) {
69b9c876bdSRiver Riddle         output.push_back(inputValue);
70b9c876bdSRiver Riddle         break;
71b9c876bdSRiver Riddle       }
72b9c876bdSRiver Riddle       unsigned firstInputIndex, lastInputIndex;
73b9c876bdSRiver Riddle       if (region) {
745550c821STres Popp         firstInputIndex = cast<BlockArgument>(inputs[0]).getArgNumber();
755550c821STres Popp         lastInputIndex = cast<BlockArgument>(inputs.back()).getArgNumber();
76b9c876bdSRiver Riddle       } else {
775550c821STres Popp         firstInputIndex = cast<OpResult>(inputs[0]).getResultNumber();
785550c821STres Popp         lastInputIndex = cast<OpResult>(inputs.back()).getResultNumber();
79b9c876bdSRiver Riddle       }
80b9c876bdSRiver Riddle       if (firstInputIndex > inputIndex || lastInputIndex < inputIndex) {
81b9c876bdSRiver Riddle         output.push_back(inputValue);
82b9c876bdSRiver Riddle         break;
83b9c876bdSRiver Riddle       }
84b9c876bdSRiver Riddle       return inputIndex - firstInputIndex;
85b9c876bdSRiver Riddle     }
861a36588eSKazu Hirata     return std::nullopt;
87b9c876bdSRiver Riddle   };
88b9c876bdSRiver Riddle 
89b9c876bdSRiver Riddle   // Check branches from the parent operation.
904dd744acSMarkus Böck   auto branchPoint = RegionBranchPoint::parent();
914dd744acSMarkus Böck   if (region)
924dd744acSMarkus Böck     branchPoint = region;
934dd744acSMarkus Böck 
9422426110SRamkumar Ramachandra   if (std::optional<unsigned> operandIndex =
954dd744acSMarkus Böck           getOperandIndexIfPred(/*predIndex=*/RegionBranchPoint::parent())) {
96b9c876bdSRiver Riddle     collectUnderlyingAddressValues(
974dd744acSMarkus Böck         branch.getEntrySuccessorOperands(branchPoint)[*operandIndex], maxDepth,
98537f2208SMogball         visited, output);
99b9c876bdSRiver Riddle   }
100b9c876bdSRiver Riddle   // Check branches from each child region.
101b9c876bdSRiver Riddle   Operation *op = branch.getOperation();
1024dd744acSMarkus Böck   for (Region &region : op->getRegions()) {
1034dd744acSMarkus Böck     if (std::optional<unsigned> operandIndex = getOperandIndexIfPred(region)) {
1044dd744acSMarkus Böck       for (Block &block : region) {
10504253320SMarcel Koester         // Try to determine possible region-branch successor operands for the
10604253320SMarcel Koester         // current region.
10710ae8ae8SMarkus Böck         if (auto term = dyn_cast<RegionBranchTerminatorOpInterface>(
10810ae8ae8SMarkus Böck                 block.getTerminator())) {
10910ae8ae8SMarkus Böck           collectUnderlyingAddressValues(
1104dd744acSMarkus Böck               term.getSuccessorOperands(branchPoint)[*operandIndex], maxDepth,
11110ae8ae8SMarkus Böck               visited, output);
11210ae8ae8SMarkus Böck         } else if (block.getNumSuccessors()) {
113b9c876bdSRiver Riddle           // Otherwise, if this terminator may exit the region we can't make
114b9c876bdSRiver Riddle           // any assumptions about which values get passed.
115b9c876bdSRiver Riddle           output.push_back(inputValue);
116b9c876bdSRiver Riddle           return;
117b9c876bdSRiver Riddle         }
118b9c876bdSRiver Riddle       }
119b9c876bdSRiver Riddle     }
120b9c876bdSRiver Riddle   }
121b9c876bdSRiver Riddle }
122b9c876bdSRiver Riddle 
123b9c876bdSRiver Riddle /// Given a result, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(OpResult result,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)124b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(OpResult result, unsigned maxDepth,
125b9c876bdSRiver Riddle                                            DenseSet<Value> &visited,
126b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output) {
127b9c876bdSRiver Riddle   Operation *op = result.getOwner();
128b9c876bdSRiver Riddle 
129b9c876bdSRiver Riddle   // If this is a view, unwrap to the source.
130b9c876bdSRiver Riddle   if (ViewLikeOpInterface view = dyn_cast<ViewLikeOpInterface>(op))
131b9c876bdSRiver Riddle     return collectUnderlyingAddressValues(view.getViewSource(), maxDepth,
132b9c876bdSRiver Riddle                                           visited, output);
133b9c876bdSRiver Riddle   // Check to see if we can reason about the control flow of this op.
134b9c876bdSRiver Riddle   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
135b9c876bdSRiver Riddle     return collectUnderlyingAddressValues(branch, /*region=*/nullptr, result,
136b9c876bdSRiver Riddle                                           result.getResultNumber(), maxDepth,
137b9c876bdSRiver Riddle                                           visited, output);
138b9c876bdSRiver Riddle   }
139b9c876bdSRiver Riddle 
140b9c876bdSRiver Riddle   output.push_back(result);
141b9c876bdSRiver Riddle }
142b9c876bdSRiver Riddle 
143b9c876bdSRiver Riddle /// Given a block argument, collect all of the underlying values being
144b9c876bdSRiver Riddle /// addressed.
collectUnderlyingAddressValues(BlockArgument arg,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)145b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(BlockArgument arg, unsigned maxDepth,
146b9c876bdSRiver Riddle                                            DenseSet<Value> &visited,
147b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output) {
148b9c876bdSRiver Riddle   Block *block = arg.getOwner();
149b9c876bdSRiver Riddle   unsigned argNumber = arg.getArgNumber();
150b9c876bdSRiver Riddle 
151b9c876bdSRiver Riddle   // Handle the case of a non-entry block.
152b9c876bdSRiver Riddle   if (!block->isEntryBlock()) {
153b9c876bdSRiver Riddle     for (auto it = block->pred_begin(), e = block->pred_end(); it != e; ++it) {
154b9c876bdSRiver Riddle       auto branch = dyn_cast<BranchOpInterface>((*it)->getTerminator());
155b9c876bdSRiver Riddle       if (!branch) {
156b9c876bdSRiver Riddle         // We can't analyze the control flow, so bail out early.
157b9c876bdSRiver Riddle         output.push_back(arg);
158b9c876bdSRiver Riddle         return;
159b9c876bdSRiver Riddle       }
160b9c876bdSRiver Riddle 
161b9c876bdSRiver Riddle       // Try to get the operand passed for this argument.
162b9c876bdSRiver Riddle       unsigned index = it.getSuccessorIndex();
1630c789db5SMarkus Böck       Value operand = branch.getSuccessorOperands(index)[argNumber];
1640c789db5SMarkus Böck       if (!operand) {
165b9c876bdSRiver Riddle         // We can't analyze the control flow, so bail out early.
166b9c876bdSRiver Riddle         output.push_back(arg);
167b9c876bdSRiver Riddle         return;
168b9c876bdSRiver Riddle       }
1690c789db5SMarkus Böck       collectUnderlyingAddressValues(operand, maxDepth, visited, output);
170b9c876bdSRiver Riddle     }
171b9c876bdSRiver Riddle     return;
172b9c876bdSRiver Riddle   }
173b9c876bdSRiver Riddle 
174b9c876bdSRiver Riddle   // Otherwise, check to see if we can reason about the control flow of this op.
175b9c876bdSRiver Riddle   Region *region = block->getParent();
176b9c876bdSRiver Riddle   Operation *op = region->getParentOp();
177b9c876bdSRiver Riddle   if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
178b9c876bdSRiver Riddle     return collectUnderlyingAddressValues(branch, region, arg, argNumber,
179b9c876bdSRiver Riddle                                           maxDepth, visited, output);
180b9c876bdSRiver Riddle   }
181b9c876bdSRiver Riddle 
182b9c876bdSRiver Riddle   // We can't reason about the underlying address of this argument.
183b9c876bdSRiver Riddle   output.push_back(arg);
184b9c876bdSRiver Riddle }
185b9c876bdSRiver Riddle 
186b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(Value value,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)187b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value, unsigned maxDepth,
188b9c876bdSRiver Riddle                                            DenseSet<Value> &visited,
189b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output) {
190b9c876bdSRiver Riddle   // Check that we don't infinitely recurse.
191b9c876bdSRiver Riddle   if (!visited.insert(value).second)
192b9c876bdSRiver Riddle     return;
193b9c876bdSRiver Riddle   if (maxDepth == 0) {
194b9c876bdSRiver Riddle     output.push_back(value);
195b9c876bdSRiver Riddle     return;
196b9c876bdSRiver Riddle   }
197b9c876bdSRiver Riddle   --maxDepth;
198b9c876bdSRiver Riddle 
1995550c821STres Popp   if (BlockArgument arg = dyn_cast<BlockArgument>(value))
200b9c876bdSRiver Riddle     return collectUnderlyingAddressValues(arg, maxDepth, visited, output);
2015550c821STres Popp   collectUnderlyingAddressValues(cast<OpResult>(value), maxDepth, visited,
202b9c876bdSRiver Riddle                                  output);
203b9c876bdSRiver Riddle }
204b9c876bdSRiver Riddle 
205b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(Value value,SmallVectorImpl<Value> & output)206b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value,
207b9c876bdSRiver Riddle                                            SmallVectorImpl<Value> &output) {
208b9c876bdSRiver Riddle   DenseSet<Value> visited;
209b9c876bdSRiver Riddle   collectUnderlyingAddressValues(value, maxUnderlyingValueSearchDepth, visited,
210b9c876bdSRiver Riddle                                  output);
211b9c876bdSRiver Riddle }
212b9c876bdSRiver Riddle 
213b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
214d47dd110SRiver Riddle // LocalAliasAnalysis: alias
215b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
216b9c876bdSRiver Riddle 
217b9c876bdSRiver Riddle /// Given a value, try to get an allocation effect attached to it. If
218b9c876bdSRiver Riddle /// successful, `allocEffect` is populated with the effect. If an effect was
219b9c876bdSRiver Riddle /// found, `allocScopeOp` is also specified if a parent operation of `value`
220b9c876bdSRiver Riddle /// could be identified that bounds the scope of the allocated value; i.e. if
221b9c876bdSRiver Riddle /// non-null it specifies the parent operation that the allocation does not
222b9c876bdSRiver Riddle /// escape. If no scope is found, `allocScopeOp` is set to nullptr.
223b9c876bdSRiver Riddle static LogicalResult
getAllocEffectFor(Value value,std::optional<MemoryEffects::EffectInstance> & effect,Operation * & allocScopeOp)22422426110SRamkumar Ramachandra getAllocEffectFor(Value value,
22522426110SRamkumar Ramachandra                   std::optional<MemoryEffects::EffectInstance> &effect,
226b9c876bdSRiver Riddle                   Operation *&allocScopeOp) {
227b9c876bdSRiver Riddle   // Try to get a memory effect interface for the parent operation.
228b9c876bdSRiver Riddle   Operation *op;
2295550c821STres Popp   if (BlockArgument arg = dyn_cast<BlockArgument>(value))
230b9c876bdSRiver Riddle     op = arg.getOwner()->getParentOp();
231b9c876bdSRiver Riddle   else
2325550c821STres Popp     op = cast<OpResult>(value).getOwner();
233b9c876bdSRiver Riddle   MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
234b9c876bdSRiver Riddle   if (!interface)
235b9c876bdSRiver Riddle     return failure();
236b9c876bdSRiver Riddle 
237b9c876bdSRiver Riddle   // Try to find an allocation effect on the resource.
238b9c876bdSRiver Riddle   if (!(effect = interface.getEffectOnValue<MemoryEffects::Allocate>(value)))
239b9c876bdSRiver Riddle     return failure();
240b9c876bdSRiver Riddle 
241b9c876bdSRiver Riddle   // If we found an allocation effect, try to find a scope for the allocation.
242b9c876bdSRiver Riddle   // If the resource of this allocation is automatically scoped, find the parent
243b9c876bdSRiver Riddle   // operation that bounds the allocation scope.
244b9c876bdSRiver Riddle   if (llvm::isa<SideEffects::AutomaticAllocationScopeResource>(
245b9c876bdSRiver Riddle           effect->getResource())) {
246b9c876bdSRiver Riddle     allocScopeOp = op->getParentWithTrait<OpTrait::AutomaticAllocationScope>();
247b9c876bdSRiver Riddle     return success();
248b9c876bdSRiver Riddle   }
249b9c876bdSRiver Riddle 
250b9c876bdSRiver Riddle   // TODO: Here we could look at the users to see if the resource is either
251b9c876bdSRiver Riddle   // freed on all paths within the region, or is just not captured by anything.
25291e0cb65SButygin   // For now assume allocation scope to the function scope (we don't care if
25391e0cb65SButygin   // pointer escape outside function).
2547ceffae1SRiver Riddle   allocScopeOp = op->getParentOfType<FunctionOpInterface>();
255b9c876bdSRiver Riddle   return success();
256b9c876bdSRiver Riddle }
257b9c876bdSRiver Riddle 
258b9c876bdSRiver Riddle /// Given the two values, return their aliasing behavior.
aliasImpl(Value lhs,Value rhs)259d42cb024SIvan Butygin AliasResult LocalAliasAnalysis::aliasImpl(Value lhs, Value rhs) {
260b9c876bdSRiver Riddle   if (lhs == rhs)
261b9c876bdSRiver Riddle     return AliasResult::MustAlias;
262b9c876bdSRiver Riddle   Operation *lhsAllocScope = nullptr, *rhsAllocScope = nullptr;
26322426110SRamkumar Ramachandra   std::optional<MemoryEffects::EffectInstance> lhsAlloc, rhsAlloc;
264b9c876bdSRiver Riddle 
265b9c876bdSRiver Riddle   // Handle the case where lhs is a constant.
266b9c876bdSRiver Riddle   Attribute lhsAttr, rhsAttr;
267b9c876bdSRiver Riddle   if (matchPattern(lhs, m_Constant(&lhsAttr))) {
268b9c876bdSRiver Riddle     // TODO: This is overly conservative. Two matching constants don't
269b9c876bdSRiver Riddle     // necessarily map to the same address. For example, if the two values
270b9c876bdSRiver Riddle     // correspond to different symbols that both represent a definition.
271b9c876bdSRiver Riddle     if (matchPattern(rhs, m_Constant(&rhsAttr)))
272b9c876bdSRiver Riddle       return AliasResult::MayAlias;
273b9c876bdSRiver Riddle 
274b9c876bdSRiver Riddle     // Try to find an alloc effect on rhs. If an effect was found we can't
275b9c876bdSRiver Riddle     // alias, otherwise we might.
276b9c876bdSRiver Riddle     return succeeded(getAllocEffectFor(rhs, rhsAlloc, rhsAllocScope))
277b9c876bdSRiver Riddle                ? AliasResult::NoAlias
278b9c876bdSRiver Riddle                : AliasResult::MayAlias;
279b9c876bdSRiver Riddle   }
280b9c876bdSRiver Riddle   // Handle the case where rhs is a constant.
281b9c876bdSRiver Riddle   if (matchPattern(rhs, m_Constant(&rhsAttr))) {
282b9c876bdSRiver Riddle     // Try to find an alloc effect on lhs. If an effect was found we can't
283b9c876bdSRiver Riddle     // alias, otherwise we might.
284b9c876bdSRiver Riddle     return succeeded(getAllocEffectFor(lhs, lhsAlloc, lhsAllocScope))
285b9c876bdSRiver Riddle                ? AliasResult::NoAlias
286b9c876bdSRiver Riddle                : AliasResult::MayAlias;
287b9c876bdSRiver Riddle   }
288b9c876bdSRiver Riddle 
289b9c876bdSRiver Riddle   // Otherwise, neither of the values are constant so check to see if either has
290b9c876bdSRiver Riddle   // an allocation effect.
291b9c876bdSRiver Riddle   bool lhsHasAlloc = succeeded(getAllocEffectFor(lhs, lhsAlloc, lhsAllocScope));
292b9c876bdSRiver Riddle   bool rhsHasAlloc = succeeded(getAllocEffectFor(rhs, rhsAlloc, rhsAllocScope));
293b9c876bdSRiver Riddle   if (lhsHasAlloc == rhsHasAlloc) {
294b9c876bdSRiver Riddle     // If both values have an allocation effect we know they don't alias, and if
295b9c876bdSRiver Riddle     // neither have an effect we can't make an assumptions.
296b9c876bdSRiver Riddle     return lhsHasAlloc ? AliasResult::NoAlias : AliasResult::MayAlias;
297b9c876bdSRiver Riddle   }
298b9c876bdSRiver Riddle 
299b9c876bdSRiver Riddle   // When we reach this point we have one value with a known allocation effect,
300b9c876bdSRiver Riddle   // and one without. Move the one with the effect to the lhs to make the next
301b9c876bdSRiver Riddle   // checks simpler.
302b9c876bdSRiver Riddle   if (rhsHasAlloc) {
303b9c876bdSRiver Riddle     std::swap(lhs, rhs);
304b9c876bdSRiver Riddle     lhsAlloc = rhsAlloc;
305b9c876bdSRiver Riddle     lhsAllocScope = rhsAllocScope;
306b9c876bdSRiver Riddle   }
307b9c876bdSRiver Riddle 
308b9c876bdSRiver Riddle   // If the effect has a scoped allocation region, check to see if the
309b9c876bdSRiver Riddle   // non-effect value is defined above that scope.
310b9c876bdSRiver Riddle   if (lhsAllocScope) {
311b9c876bdSRiver Riddle     // If the parent operation of rhs is an ancestor of the allocation scope, or
312b9c876bdSRiver Riddle     // if rhs is an entry block argument of the allocation scope we know the two
313b9c876bdSRiver Riddle     // values can't alias.
314b9c876bdSRiver Riddle     Operation *rhsParentOp = rhs.getParentRegion()->getParentOp();
315b9c876bdSRiver Riddle     if (rhsParentOp->isProperAncestor(lhsAllocScope))
316b9c876bdSRiver Riddle       return AliasResult::NoAlias;
317b9c876bdSRiver Riddle     if (rhsParentOp == lhsAllocScope) {
3185550c821STres Popp       BlockArgument rhsArg = dyn_cast<BlockArgument>(rhs);
319b9c876bdSRiver Riddle       if (rhsArg && rhs.getParentBlock()->isEntryBlock())
320b9c876bdSRiver Riddle         return AliasResult::NoAlias;
321b9c876bdSRiver Riddle     }
322b9c876bdSRiver Riddle   }
323b9c876bdSRiver Riddle 
324b9c876bdSRiver Riddle   // If we couldn't reason about the relationship between the two values,
325b9c876bdSRiver Riddle   // conservatively assume they might alias.
326b9c876bdSRiver Riddle   return AliasResult::MayAlias;
327b9c876bdSRiver Riddle }
328b9c876bdSRiver Riddle 
329b9c876bdSRiver Riddle /// Given the two values, return their aliasing behavior.
alias(Value lhs,Value rhs)330b9c876bdSRiver Riddle AliasResult LocalAliasAnalysis::alias(Value lhs, Value rhs) {
331b9c876bdSRiver Riddle   if (lhs == rhs)
332b9c876bdSRiver Riddle     return AliasResult::MustAlias;
333b9c876bdSRiver Riddle 
334b9c876bdSRiver Riddle   // Get the underlying values being addressed.
335b9c876bdSRiver Riddle   SmallVector<Value, 8> lhsValues, rhsValues;
336b9c876bdSRiver Riddle   collectUnderlyingAddressValues(lhs, lhsValues);
337b9c876bdSRiver Riddle   collectUnderlyingAddressValues(rhs, rhsValues);
338b9c876bdSRiver Riddle 
339b9c876bdSRiver Riddle   // If we failed to collect for either of the values somehow, conservatively
340b9c876bdSRiver Riddle   // assume they may alias.
341b9c876bdSRiver Riddle   if (lhsValues.empty() || rhsValues.empty())
342b9c876bdSRiver Riddle     return AliasResult::MayAlias;
343b9c876bdSRiver Riddle 
344b9c876bdSRiver Riddle   // Check the alias results against each of the underlying values.
345100c3867SKazu Hirata   std::optional<AliasResult> result;
346b9c876bdSRiver Riddle   for (Value lhsVal : lhsValues) {
347b9c876bdSRiver Riddle     for (Value rhsVal : rhsValues) {
348b9c876bdSRiver Riddle       AliasResult nextResult = aliasImpl(lhsVal, rhsVal);
349b9c876bdSRiver Riddle       result = result ? result->merge(nextResult) : nextResult;
350b9c876bdSRiver Riddle     }
351b9c876bdSRiver Riddle   }
352b9c876bdSRiver Riddle 
353b9c876bdSRiver Riddle   // We should always have a valid result here.
354b9c876bdSRiver Riddle   return *result;
355b9c876bdSRiver Riddle }
356d47dd110SRiver Riddle 
357d47dd110SRiver Riddle //===----------------------------------------------------------------------===//
358d47dd110SRiver Riddle // LocalAliasAnalysis: getModRef
359d47dd110SRiver Riddle //===----------------------------------------------------------------------===//
360d47dd110SRiver Riddle 
getModRef(Operation * op,Value location)361d47dd110SRiver Riddle ModRefResult LocalAliasAnalysis::getModRef(Operation *op, Value location) {
362d47dd110SRiver Riddle   // Check to see if this operation relies on nested side effects.
36386771d0bSSanjoy Das   if (op->hasTrait<OpTrait::HasRecursiveMemoryEffects>()) {
364d47dd110SRiver Riddle     // TODO: To check recursive operations we need to check all of the nested
365d47dd110SRiver Riddle     // operations, which can result in a quadratic number of queries. We should
366d47dd110SRiver Riddle     // introduce some caching of some kind to help alleviate this, especially as
367d47dd110SRiver Riddle     // this caching could be used in other areas of the codebase (e.g. when
368d47dd110SRiver Riddle     // checking `wouldOpBeTriviallyDead`).
369d47dd110SRiver Riddle     return ModRefResult::getModAndRef();
370d47dd110SRiver Riddle   }
371d47dd110SRiver Riddle 
372d47dd110SRiver Riddle   // Otherwise, check to see if this operation has a memory effect interface.
373d47dd110SRiver Riddle   MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
374d47dd110SRiver Riddle   if (!interface)
375d47dd110SRiver Riddle     return ModRefResult::getModAndRef();
376d47dd110SRiver Riddle 
377d47dd110SRiver Riddle   // Build a ModRefResult by merging the behavior of the effects of this
378d47dd110SRiver Riddle   // operation.
379d47dd110SRiver Riddle   SmallVector<MemoryEffects::EffectInstance> effects;
380d47dd110SRiver Riddle   interface.getEffects(effects);
381d47dd110SRiver Riddle 
382d47dd110SRiver Riddle   ModRefResult result = ModRefResult::getNoModRef();
383d47dd110SRiver Riddle   for (const MemoryEffects::EffectInstance &effect : effects) {
384d47dd110SRiver Riddle     if (isa<MemoryEffects::Allocate, MemoryEffects::Free>(effect.getEffect()))
385d47dd110SRiver Riddle       continue;
386d47dd110SRiver Riddle 
387d47dd110SRiver Riddle     // Check for an alias between the effect and our memory location.
388d47dd110SRiver Riddle     // TODO: Add support for checking an alias with a symbol reference.
389d47dd110SRiver Riddle     AliasResult aliasResult = AliasResult::MayAlias;
390d47dd110SRiver Riddle     if (Value effectValue = effect.getValue())
391d47dd110SRiver Riddle       aliasResult = alias(effectValue, location);
392d47dd110SRiver Riddle 
393d47dd110SRiver Riddle     // If we don't alias, ignore this effect.
394d47dd110SRiver Riddle     if (aliasResult.isNo())
395d47dd110SRiver Riddle       continue;
396d47dd110SRiver Riddle 
397d47dd110SRiver Riddle     // Merge in the corresponding mod or ref for this effect.
398d47dd110SRiver Riddle     if (isa<MemoryEffects::Read>(effect.getEffect())) {
399d47dd110SRiver Riddle       result = result.merge(ModRefResult::getRef());
400d47dd110SRiver Riddle     } else {
401d47dd110SRiver Riddle       assert(isa<MemoryEffects::Write>(effect.getEffect()));
402d47dd110SRiver Riddle       result = result.merge(ModRefResult::getMod());
403d47dd110SRiver Riddle     }
404d47dd110SRiver Riddle     if (result.isModAndRef())
405d47dd110SRiver Riddle       break;
406d47dd110SRiver Riddle   }
407d47dd110SRiver Riddle   return result;
408d47dd110SRiver Riddle }
409