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
117ceffae1SRiver Riddle #include "mlir/IR/FunctionInterfaces.h"
12b9c876bdSRiver Riddle #include "mlir/IR/Matchers.h"
13b9c876bdSRiver Riddle #include "mlir/Interfaces/ControlFlowInterfaces.h"
14b9c876bdSRiver Riddle #include "mlir/Interfaces/SideEffectInterfaces.h"
15b9c876bdSRiver Riddle #include "mlir/Interfaces/ViewLikeInterface.h"
16b9c876bdSRiver Riddle
17b9c876bdSRiver Riddle using namespace mlir;
18b9c876bdSRiver Riddle
19b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
20b9c876bdSRiver Riddle // Underlying Address Computation
21b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
22b9c876bdSRiver Riddle
23b9c876bdSRiver Riddle /// The maximum depth that will be searched when trying to find an underlying
24b9c876bdSRiver Riddle /// value.
25b9c876bdSRiver Riddle static constexpr unsigned maxUnderlyingValueSearchDepth = 10;
26b9c876bdSRiver Riddle
27b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
28b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value, unsigned maxDepth,
29b9c876bdSRiver Riddle DenseSet<Value> &visited,
30b9c876bdSRiver Riddle SmallVectorImpl<Value> &output);
31b9c876bdSRiver Riddle
32b9c876bdSRiver Riddle /// Given a successor (`region`) of a RegionBranchOpInterface, collect all of
33b9c876bdSRiver Riddle /// the underlying values being addressed by one of the successor inputs. If the
34b9c876bdSRiver Riddle /// provided `region` is null, as per `RegionBranchOpInterface` this represents
35b9c876bdSRiver Riddle /// the parent operation.
collectUnderlyingAddressValues(RegionBranchOpInterface branch,Region * region,Value inputValue,unsigned inputIndex,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)36b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(RegionBranchOpInterface branch,
37b9c876bdSRiver Riddle Region *region, Value inputValue,
38b9c876bdSRiver Riddle unsigned inputIndex,
39b9c876bdSRiver Riddle unsigned maxDepth,
40b9c876bdSRiver Riddle DenseSet<Value> &visited,
41b9c876bdSRiver Riddle SmallVectorImpl<Value> &output) {
42b9c876bdSRiver Riddle // Given the index of a region of the branch (`predIndex`), or None to
43b9c876bdSRiver Riddle // represent the parent operation, try to return the index into the outputs of
44b9c876bdSRiver Riddle // this region predecessor that correspond to the input values of `region`. If
45b9c876bdSRiver Riddle // an index could not be found, None is returned instead.
46b9c876bdSRiver Riddle auto getOperandIndexIfPred =
47b9c876bdSRiver Riddle [&](Optional<unsigned> predIndex) -> Optional<unsigned> {
48b9c876bdSRiver Riddle SmallVector<RegionSuccessor, 2> successors;
49b9c876bdSRiver Riddle branch.getSuccessorRegions(predIndex, successors);
50b9c876bdSRiver Riddle for (RegionSuccessor &successor : successors) {
51b9c876bdSRiver Riddle if (successor.getSuccessor() != region)
52b9c876bdSRiver Riddle continue;
53b9c876bdSRiver Riddle // Check that the successor inputs map to the given input value.
54b9c876bdSRiver Riddle ValueRange inputs = successor.getSuccessorInputs();
55b9c876bdSRiver Riddle if (inputs.empty()) {
56b9c876bdSRiver Riddle output.push_back(inputValue);
57b9c876bdSRiver Riddle break;
58b9c876bdSRiver Riddle }
59b9c876bdSRiver Riddle unsigned firstInputIndex, lastInputIndex;
60b9c876bdSRiver Riddle if (region) {
61b9c876bdSRiver Riddle firstInputIndex = inputs[0].cast<BlockArgument>().getArgNumber();
62b9c876bdSRiver Riddle lastInputIndex = inputs.back().cast<BlockArgument>().getArgNumber();
63b9c876bdSRiver Riddle } else {
64b9c876bdSRiver Riddle firstInputIndex = inputs[0].cast<OpResult>().getResultNumber();
65b9c876bdSRiver Riddle lastInputIndex = inputs.back().cast<OpResult>().getResultNumber();
66b9c876bdSRiver Riddle }
67b9c876bdSRiver Riddle if (firstInputIndex > inputIndex || lastInputIndex < inputIndex) {
68b9c876bdSRiver Riddle output.push_back(inputValue);
69b9c876bdSRiver Riddle break;
70b9c876bdSRiver Riddle }
71b9c876bdSRiver Riddle return inputIndex - firstInputIndex;
72b9c876bdSRiver Riddle }
73b9c876bdSRiver Riddle return llvm::None;
74b9c876bdSRiver Riddle };
75b9c876bdSRiver Riddle
76b9c876bdSRiver Riddle // Check branches from the parent operation.
7704253320SMarcel Koester Optional<unsigned> regionIndex;
78b9c876bdSRiver Riddle if (region) {
7904253320SMarcel Koester // Determine the actual region number from the passed region.
8004253320SMarcel Koester regionIndex = region->getRegionNumber();
81*537f2208SMogball }
82b9c876bdSRiver Riddle if (Optional<unsigned> operandIndex =
83b9c876bdSRiver Riddle getOperandIndexIfPred(/*predIndex=*/llvm::None)) {
84b9c876bdSRiver Riddle collectUnderlyingAddressValues(
85*537f2208SMogball branch.getSuccessorEntryOperands(regionIndex)[*operandIndex], maxDepth,
86*537f2208SMogball visited, output);
87b9c876bdSRiver Riddle }
88b9c876bdSRiver Riddle // Check branches from each child region.
89b9c876bdSRiver Riddle Operation *op = branch.getOperation();
90b9c876bdSRiver Riddle for (int i = 0, e = op->getNumRegions(); i != e; ++i) {
91b9c876bdSRiver Riddle if (Optional<unsigned> operandIndex = getOperandIndexIfPred(i)) {
92b9c876bdSRiver Riddle for (Block &block : op->getRegion(i)) {
93b9c876bdSRiver Riddle Operation *term = block.getTerminator();
9404253320SMarcel Koester // Try to determine possible region-branch successor operands for the
9504253320SMarcel Koester // current region.
9604253320SMarcel Koester auto successorOperands =
9704253320SMarcel Koester getRegionBranchSuccessorOperands(term, regionIndex);
9804253320SMarcel Koester if (successorOperands) {
9904253320SMarcel Koester collectUnderlyingAddressValues((*successorOperands)[*operandIndex],
100b9c876bdSRiver Riddle maxDepth, visited, output);
101b9c876bdSRiver Riddle } else if (term->getNumSuccessors()) {
102b9c876bdSRiver Riddle // Otherwise, if this terminator may exit the region we can't make
103b9c876bdSRiver Riddle // any assumptions about which values get passed.
104b9c876bdSRiver Riddle output.push_back(inputValue);
105b9c876bdSRiver Riddle return;
106b9c876bdSRiver Riddle }
107b9c876bdSRiver Riddle }
108b9c876bdSRiver Riddle }
109b9c876bdSRiver Riddle }
110b9c876bdSRiver Riddle }
111b9c876bdSRiver Riddle
112b9c876bdSRiver Riddle /// Given a result, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(OpResult result,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)113b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(OpResult result, unsigned maxDepth,
114b9c876bdSRiver Riddle DenseSet<Value> &visited,
115b9c876bdSRiver Riddle SmallVectorImpl<Value> &output) {
116b9c876bdSRiver Riddle Operation *op = result.getOwner();
117b9c876bdSRiver Riddle
118b9c876bdSRiver Riddle // If this is a view, unwrap to the source.
119b9c876bdSRiver Riddle if (ViewLikeOpInterface view = dyn_cast<ViewLikeOpInterface>(op))
120b9c876bdSRiver Riddle return collectUnderlyingAddressValues(view.getViewSource(), maxDepth,
121b9c876bdSRiver Riddle visited, output);
122b9c876bdSRiver Riddle // Check to see if we can reason about the control flow of this op.
123b9c876bdSRiver Riddle if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
124b9c876bdSRiver Riddle return collectUnderlyingAddressValues(branch, /*region=*/nullptr, result,
125b9c876bdSRiver Riddle result.getResultNumber(), maxDepth,
126b9c876bdSRiver Riddle visited, output);
127b9c876bdSRiver Riddle }
128b9c876bdSRiver Riddle
129b9c876bdSRiver Riddle output.push_back(result);
130b9c876bdSRiver Riddle }
131b9c876bdSRiver Riddle
132b9c876bdSRiver Riddle /// Given a block argument, collect all of the underlying values being
133b9c876bdSRiver Riddle /// addressed.
collectUnderlyingAddressValues(BlockArgument arg,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)134b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(BlockArgument arg, unsigned maxDepth,
135b9c876bdSRiver Riddle DenseSet<Value> &visited,
136b9c876bdSRiver Riddle SmallVectorImpl<Value> &output) {
137b9c876bdSRiver Riddle Block *block = arg.getOwner();
138b9c876bdSRiver Riddle unsigned argNumber = arg.getArgNumber();
139b9c876bdSRiver Riddle
140b9c876bdSRiver Riddle // Handle the case of a non-entry block.
141b9c876bdSRiver Riddle if (!block->isEntryBlock()) {
142b9c876bdSRiver Riddle for (auto it = block->pred_begin(), e = block->pred_end(); it != e; ++it) {
143b9c876bdSRiver Riddle auto branch = dyn_cast<BranchOpInterface>((*it)->getTerminator());
144b9c876bdSRiver Riddle if (!branch) {
145b9c876bdSRiver Riddle // We can't analyze the control flow, so bail out early.
146b9c876bdSRiver Riddle output.push_back(arg);
147b9c876bdSRiver Riddle return;
148b9c876bdSRiver Riddle }
149b9c876bdSRiver Riddle
150b9c876bdSRiver Riddle // Try to get the operand passed for this argument.
151b9c876bdSRiver Riddle unsigned index = it.getSuccessorIndex();
1520c789db5SMarkus Böck Value operand = branch.getSuccessorOperands(index)[argNumber];
1530c789db5SMarkus Böck if (!operand) {
154b9c876bdSRiver Riddle // We can't analyze the control flow, so bail out early.
155b9c876bdSRiver Riddle output.push_back(arg);
156b9c876bdSRiver Riddle return;
157b9c876bdSRiver Riddle }
1580c789db5SMarkus Böck collectUnderlyingAddressValues(operand, maxDepth, visited, output);
159b9c876bdSRiver Riddle }
160b9c876bdSRiver Riddle return;
161b9c876bdSRiver Riddle }
162b9c876bdSRiver Riddle
163b9c876bdSRiver Riddle // Otherwise, check to see if we can reason about the control flow of this op.
164b9c876bdSRiver Riddle Region *region = block->getParent();
165b9c876bdSRiver Riddle Operation *op = region->getParentOp();
166b9c876bdSRiver Riddle if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {
167b9c876bdSRiver Riddle return collectUnderlyingAddressValues(branch, region, arg, argNumber,
168b9c876bdSRiver Riddle maxDepth, visited, output);
169b9c876bdSRiver Riddle }
170b9c876bdSRiver Riddle
171b9c876bdSRiver Riddle // We can't reason about the underlying address of this argument.
172b9c876bdSRiver Riddle output.push_back(arg);
173b9c876bdSRiver Riddle }
174b9c876bdSRiver Riddle
175b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(Value value,unsigned maxDepth,DenseSet<Value> & visited,SmallVectorImpl<Value> & output)176b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value, unsigned maxDepth,
177b9c876bdSRiver Riddle DenseSet<Value> &visited,
178b9c876bdSRiver Riddle SmallVectorImpl<Value> &output) {
179b9c876bdSRiver Riddle // Check that we don't infinitely recurse.
180b9c876bdSRiver Riddle if (!visited.insert(value).second)
181b9c876bdSRiver Riddle return;
182b9c876bdSRiver Riddle if (maxDepth == 0) {
183b9c876bdSRiver Riddle output.push_back(value);
184b9c876bdSRiver Riddle return;
185b9c876bdSRiver Riddle }
186b9c876bdSRiver Riddle --maxDepth;
187b9c876bdSRiver Riddle
188b9c876bdSRiver Riddle if (BlockArgument arg = value.dyn_cast<BlockArgument>())
189b9c876bdSRiver Riddle return collectUnderlyingAddressValues(arg, maxDepth, visited, output);
190b9c876bdSRiver Riddle collectUnderlyingAddressValues(value.cast<OpResult>(), maxDepth, visited,
191b9c876bdSRiver Riddle output);
192b9c876bdSRiver Riddle }
193b9c876bdSRiver Riddle
194b9c876bdSRiver Riddle /// Given a value, collect all of the underlying values being addressed.
collectUnderlyingAddressValues(Value value,SmallVectorImpl<Value> & output)195b9c876bdSRiver Riddle static void collectUnderlyingAddressValues(Value value,
196b9c876bdSRiver Riddle SmallVectorImpl<Value> &output) {
197b9c876bdSRiver Riddle DenseSet<Value> visited;
198b9c876bdSRiver Riddle collectUnderlyingAddressValues(value, maxUnderlyingValueSearchDepth, visited,
199b9c876bdSRiver Riddle output);
200b9c876bdSRiver Riddle }
201b9c876bdSRiver Riddle
202b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
203d47dd110SRiver Riddle // LocalAliasAnalysis: alias
204b9c876bdSRiver Riddle //===----------------------------------------------------------------------===//
205b9c876bdSRiver Riddle
206b9c876bdSRiver Riddle /// Given a value, try to get an allocation effect attached to it. If
207b9c876bdSRiver Riddle /// successful, `allocEffect` is populated with the effect. If an effect was
208b9c876bdSRiver Riddle /// found, `allocScopeOp` is also specified if a parent operation of `value`
209b9c876bdSRiver Riddle /// could be identified that bounds the scope of the allocated value; i.e. if
210b9c876bdSRiver Riddle /// non-null it specifies the parent operation that the allocation does not
211b9c876bdSRiver Riddle /// escape. If no scope is found, `allocScopeOp` is set to nullptr.
212b9c876bdSRiver Riddle static LogicalResult
getAllocEffectFor(Value value,Optional<MemoryEffects::EffectInstance> & effect,Operation * & allocScopeOp)213b9c876bdSRiver Riddle getAllocEffectFor(Value value, Optional<MemoryEffects::EffectInstance> &effect,
214b9c876bdSRiver Riddle Operation *&allocScopeOp) {
215b9c876bdSRiver Riddle // Try to get a memory effect interface for the parent operation.
216b9c876bdSRiver Riddle Operation *op;
217b9c876bdSRiver Riddle if (BlockArgument arg = value.dyn_cast<BlockArgument>())
218b9c876bdSRiver Riddle op = arg.getOwner()->getParentOp();
219b9c876bdSRiver Riddle else
220b9c876bdSRiver Riddle op = value.cast<OpResult>().getOwner();
221b9c876bdSRiver Riddle MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
222b9c876bdSRiver Riddle if (!interface)
223b9c876bdSRiver Riddle return failure();
224b9c876bdSRiver Riddle
225b9c876bdSRiver Riddle // Try to find an allocation effect on the resource.
226b9c876bdSRiver Riddle if (!(effect = interface.getEffectOnValue<MemoryEffects::Allocate>(value)))
227b9c876bdSRiver Riddle return failure();
228b9c876bdSRiver Riddle
229b9c876bdSRiver Riddle // If we found an allocation effect, try to find a scope for the allocation.
230b9c876bdSRiver Riddle // If the resource of this allocation is automatically scoped, find the parent
231b9c876bdSRiver Riddle // operation that bounds the allocation scope.
232b9c876bdSRiver Riddle if (llvm::isa<SideEffects::AutomaticAllocationScopeResource>(
233b9c876bdSRiver Riddle effect->getResource())) {
234b9c876bdSRiver Riddle allocScopeOp = op->getParentWithTrait<OpTrait::AutomaticAllocationScope>();
235b9c876bdSRiver Riddle return success();
236b9c876bdSRiver Riddle }
237b9c876bdSRiver Riddle
238b9c876bdSRiver Riddle // TODO: Here we could look at the users to see if the resource is either
239b9c876bdSRiver Riddle // freed on all paths within the region, or is just not captured by anything.
24091e0cb65SButygin // For now assume allocation scope to the function scope (we don't care if
24191e0cb65SButygin // pointer escape outside function).
2427ceffae1SRiver Riddle allocScopeOp = op->getParentOfType<FunctionOpInterface>();
243b9c876bdSRiver Riddle return success();
244b9c876bdSRiver Riddle }
245b9c876bdSRiver Riddle
246b9c876bdSRiver Riddle /// Given the two values, return their aliasing behavior.
aliasImpl(Value lhs,Value rhs)247b9c876bdSRiver Riddle static AliasResult aliasImpl(Value lhs, Value rhs) {
248b9c876bdSRiver Riddle if (lhs == rhs)
249b9c876bdSRiver Riddle return AliasResult::MustAlias;
250b9c876bdSRiver Riddle Operation *lhsAllocScope = nullptr, *rhsAllocScope = nullptr;
251b9c876bdSRiver Riddle Optional<MemoryEffects::EffectInstance> lhsAlloc, rhsAlloc;
252b9c876bdSRiver Riddle
253b9c876bdSRiver Riddle // Handle the case where lhs is a constant.
254b9c876bdSRiver Riddle Attribute lhsAttr, rhsAttr;
255b9c876bdSRiver Riddle if (matchPattern(lhs, m_Constant(&lhsAttr))) {
256b9c876bdSRiver Riddle // TODO: This is overly conservative. Two matching constants don't
257b9c876bdSRiver Riddle // necessarily map to the same address. For example, if the two values
258b9c876bdSRiver Riddle // correspond to different symbols that both represent a definition.
259b9c876bdSRiver Riddle if (matchPattern(rhs, m_Constant(&rhsAttr)))
260b9c876bdSRiver Riddle return AliasResult::MayAlias;
261b9c876bdSRiver Riddle
262b9c876bdSRiver Riddle // Try to find an alloc effect on rhs. If an effect was found we can't
263b9c876bdSRiver Riddle // alias, otherwise we might.
264b9c876bdSRiver Riddle return succeeded(getAllocEffectFor(rhs, rhsAlloc, rhsAllocScope))
265b9c876bdSRiver Riddle ? AliasResult::NoAlias
266b9c876bdSRiver Riddle : AliasResult::MayAlias;
267b9c876bdSRiver Riddle }
268b9c876bdSRiver Riddle // Handle the case where rhs is a constant.
269b9c876bdSRiver Riddle if (matchPattern(rhs, m_Constant(&rhsAttr))) {
270b9c876bdSRiver Riddle // Try to find an alloc effect on lhs. If an effect was found we can't
271b9c876bdSRiver Riddle // alias, otherwise we might.
272b9c876bdSRiver Riddle return succeeded(getAllocEffectFor(lhs, lhsAlloc, lhsAllocScope))
273b9c876bdSRiver Riddle ? AliasResult::NoAlias
274b9c876bdSRiver Riddle : AliasResult::MayAlias;
275b9c876bdSRiver Riddle }
276b9c876bdSRiver Riddle
277b9c876bdSRiver Riddle // Otherwise, neither of the values are constant so check to see if either has
278b9c876bdSRiver Riddle // an allocation effect.
279b9c876bdSRiver Riddle bool lhsHasAlloc = succeeded(getAllocEffectFor(lhs, lhsAlloc, lhsAllocScope));
280b9c876bdSRiver Riddle bool rhsHasAlloc = succeeded(getAllocEffectFor(rhs, rhsAlloc, rhsAllocScope));
281b9c876bdSRiver Riddle if (lhsHasAlloc == rhsHasAlloc) {
282b9c876bdSRiver Riddle // If both values have an allocation effect we know they don't alias, and if
283b9c876bdSRiver Riddle // neither have an effect we can't make an assumptions.
284b9c876bdSRiver Riddle return lhsHasAlloc ? AliasResult::NoAlias : AliasResult::MayAlias;
285b9c876bdSRiver Riddle }
286b9c876bdSRiver Riddle
287b9c876bdSRiver Riddle // When we reach this point we have one value with a known allocation effect,
288b9c876bdSRiver Riddle // and one without. Move the one with the effect to the lhs to make the next
289b9c876bdSRiver Riddle // checks simpler.
290b9c876bdSRiver Riddle if (rhsHasAlloc) {
291b9c876bdSRiver Riddle std::swap(lhs, rhs);
292b9c876bdSRiver Riddle lhsAlloc = rhsAlloc;
293b9c876bdSRiver Riddle lhsAllocScope = rhsAllocScope;
294b9c876bdSRiver Riddle }
295b9c876bdSRiver Riddle
296b9c876bdSRiver Riddle // If the effect has a scoped allocation region, check to see if the
297b9c876bdSRiver Riddle // non-effect value is defined above that scope.
298b9c876bdSRiver Riddle if (lhsAllocScope) {
299b9c876bdSRiver Riddle // If the parent operation of rhs is an ancestor of the allocation scope, or
300b9c876bdSRiver Riddle // if rhs is an entry block argument of the allocation scope we know the two
301b9c876bdSRiver Riddle // values can't alias.
302b9c876bdSRiver Riddle Operation *rhsParentOp = rhs.getParentRegion()->getParentOp();
303b9c876bdSRiver Riddle if (rhsParentOp->isProperAncestor(lhsAllocScope))
304b9c876bdSRiver Riddle return AliasResult::NoAlias;
305b9c876bdSRiver Riddle if (rhsParentOp == lhsAllocScope) {
306b9c876bdSRiver Riddle BlockArgument rhsArg = rhs.dyn_cast<BlockArgument>();
307b9c876bdSRiver Riddle if (rhsArg && rhs.getParentBlock()->isEntryBlock())
308b9c876bdSRiver Riddle return AliasResult::NoAlias;
309b9c876bdSRiver Riddle }
310b9c876bdSRiver Riddle }
311b9c876bdSRiver Riddle
312b9c876bdSRiver Riddle // If we couldn't reason about the relationship between the two values,
313b9c876bdSRiver Riddle // conservatively assume they might alias.
314b9c876bdSRiver Riddle return AliasResult::MayAlias;
315b9c876bdSRiver Riddle }
316b9c876bdSRiver Riddle
317b9c876bdSRiver Riddle /// Given the two values, return their aliasing behavior.
alias(Value lhs,Value rhs)318b9c876bdSRiver Riddle AliasResult LocalAliasAnalysis::alias(Value lhs, Value rhs) {
319b9c876bdSRiver Riddle if (lhs == rhs)
320b9c876bdSRiver Riddle return AliasResult::MustAlias;
321b9c876bdSRiver Riddle
322b9c876bdSRiver Riddle // Get the underlying values being addressed.
323b9c876bdSRiver Riddle SmallVector<Value, 8> lhsValues, rhsValues;
324b9c876bdSRiver Riddle collectUnderlyingAddressValues(lhs, lhsValues);
325b9c876bdSRiver Riddle collectUnderlyingAddressValues(rhs, rhsValues);
326b9c876bdSRiver Riddle
327b9c876bdSRiver Riddle // If we failed to collect for either of the values somehow, conservatively
328b9c876bdSRiver Riddle // assume they may alias.
329b9c876bdSRiver Riddle if (lhsValues.empty() || rhsValues.empty())
330b9c876bdSRiver Riddle return AliasResult::MayAlias;
331b9c876bdSRiver Riddle
332b9c876bdSRiver Riddle // Check the alias results against each of the underlying values.
333b9c876bdSRiver Riddle Optional<AliasResult> result;
334b9c876bdSRiver Riddle for (Value lhsVal : lhsValues) {
335b9c876bdSRiver Riddle for (Value rhsVal : rhsValues) {
336b9c876bdSRiver Riddle AliasResult nextResult = aliasImpl(lhsVal, rhsVal);
337b9c876bdSRiver Riddle result = result ? result->merge(nextResult) : nextResult;
338b9c876bdSRiver Riddle }
339b9c876bdSRiver Riddle }
340b9c876bdSRiver Riddle
341b9c876bdSRiver Riddle // We should always have a valid result here.
342b9c876bdSRiver Riddle return *result;
343b9c876bdSRiver Riddle }
344d47dd110SRiver Riddle
345d47dd110SRiver Riddle //===----------------------------------------------------------------------===//
346d47dd110SRiver Riddle // LocalAliasAnalysis: getModRef
347d47dd110SRiver Riddle //===----------------------------------------------------------------------===//
348d47dd110SRiver Riddle
getModRef(Operation * op,Value location)349d47dd110SRiver Riddle ModRefResult LocalAliasAnalysis::getModRef(Operation *op, Value location) {
350d47dd110SRiver Riddle // Check to see if this operation relies on nested side effects.
351d47dd110SRiver Riddle if (op->hasTrait<OpTrait::HasRecursiveSideEffects>()) {
352d47dd110SRiver Riddle // TODO: To check recursive operations we need to check all of the nested
353d47dd110SRiver Riddle // operations, which can result in a quadratic number of queries. We should
354d47dd110SRiver Riddle // introduce some caching of some kind to help alleviate this, especially as
355d47dd110SRiver Riddle // this caching could be used in other areas of the codebase (e.g. when
356d47dd110SRiver Riddle // checking `wouldOpBeTriviallyDead`).
357d47dd110SRiver Riddle return ModRefResult::getModAndRef();
358d47dd110SRiver Riddle }
359d47dd110SRiver Riddle
360d47dd110SRiver Riddle // Otherwise, check to see if this operation has a memory effect interface.
361d47dd110SRiver Riddle MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
362d47dd110SRiver Riddle if (!interface)
363d47dd110SRiver Riddle return ModRefResult::getModAndRef();
364d47dd110SRiver Riddle
365d47dd110SRiver Riddle // Build a ModRefResult by merging the behavior of the effects of this
366d47dd110SRiver Riddle // operation.
367d47dd110SRiver Riddle SmallVector<MemoryEffects::EffectInstance> effects;
368d47dd110SRiver Riddle interface.getEffects(effects);
369d47dd110SRiver Riddle
370d47dd110SRiver Riddle ModRefResult result = ModRefResult::getNoModRef();
371d47dd110SRiver Riddle for (const MemoryEffects::EffectInstance &effect : effects) {
372d47dd110SRiver Riddle if (isa<MemoryEffects::Allocate, MemoryEffects::Free>(effect.getEffect()))
373d47dd110SRiver Riddle continue;
374d47dd110SRiver Riddle
375d47dd110SRiver Riddle // Check for an alias between the effect and our memory location.
376d47dd110SRiver Riddle // TODO: Add support for checking an alias with a symbol reference.
377d47dd110SRiver Riddle AliasResult aliasResult = AliasResult::MayAlias;
378d47dd110SRiver Riddle if (Value effectValue = effect.getValue())
379d47dd110SRiver Riddle aliasResult = alias(effectValue, location);
380d47dd110SRiver Riddle
381d47dd110SRiver Riddle // If we don't alias, ignore this effect.
382d47dd110SRiver Riddle if (aliasResult.isNo())
383d47dd110SRiver Riddle continue;
384d47dd110SRiver Riddle
385d47dd110SRiver Riddle // Merge in the corresponding mod or ref for this effect.
386d47dd110SRiver Riddle if (isa<MemoryEffects::Read>(effect.getEffect())) {
387d47dd110SRiver Riddle result = result.merge(ModRefResult::getRef());
388d47dd110SRiver Riddle } else {
389d47dd110SRiver Riddle assert(isa<MemoryEffects::Write>(effect.getEffect()));
390d47dd110SRiver Riddle result = result.merge(ModRefResult::getMod());
391d47dd110SRiver Riddle }
392d47dd110SRiver Riddle if (result.isModAndRef())
393d47dd110SRiver Riddle break;
394d47dd110SRiver Riddle }
395d47dd110SRiver Riddle return result;
396d47dd110SRiver Riddle }
397