123dec4a3SJohannes Reifferscheid //======- BufferViewFlowAnalysis.cpp - Buffer alias analysis -*- C++ -*-======//
223dec4a3SJohannes Reifferscheid //
323dec4a3SJohannes Reifferscheid // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
423dec4a3SJohannes Reifferscheid // See https://llvm.org/LICENSE.txt for license information.
523dec4a3SJohannes Reifferscheid // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
623dec4a3SJohannes Reifferscheid //
723dec4a3SJohannes Reifferscheid //===----------------------------------------------------------------------===//
823dec4a3SJohannes Reifferscheid
923dec4a3SJohannes Reifferscheid #include "mlir/Dialect/Bufferization/Transforms/BufferViewFlowAnalysis.h"
1023dec4a3SJohannes Reifferscheid
11a45e58afSMatthias Springer #include "mlir/Dialect/Bufferization/IR/BufferViewFlowOpInterface.h"
12a45e58afSMatthias Springer #include "mlir/Interfaces/CallInterfaces.h"
1323dec4a3SJohannes Reifferscheid #include "mlir/Interfaces/ControlFlowInterfaces.h"
14a45e58afSMatthias Springer #include "mlir/Interfaces/FunctionInterfaces.h"
1523dec4a3SJohannes Reifferscheid #include "mlir/Interfaces/ViewLikeInterface.h"
1623dec4a3SJohannes Reifferscheid #include "llvm/ADT/SetOperations.h"
17e6edc1bdSUday Bondhugula #include "llvm/ADT/SetVector.h"
1823dec4a3SJohannes Reifferscheid
1923dec4a3SJohannes Reifferscheid using namespace mlir;
20a45e58afSMatthias Springer using namespace mlir::bufferization;
2123dec4a3SJohannes Reifferscheid
22*dbfc38edSMatthias Springer //===----------------------------------------------------------------------===//
23*dbfc38edSMatthias Springer // BufferViewFlowAnalysis
24*dbfc38edSMatthias Springer //===----------------------------------------------------------------------===//
25*dbfc38edSMatthias Springer
2623dec4a3SJohannes Reifferscheid /// Constructs a new alias analysis using the op provided.
BufferViewFlowAnalysis(Operation * op)2723dec4a3SJohannes Reifferscheid BufferViewFlowAnalysis::BufferViewFlowAnalysis(Operation *op) { build(op); }
2823dec4a3SJohannes Reifferscheid
29*dbfc38edSMatthias Springer static BufferViewFlowAnalysis::ValueSetT
resolveValues(const BufferViewFlowAnalysis::ValueMapT & map,Value value)30*dbfc38edSMatthias Springer resolveValues(const BufferViewFlowAnalysis::ValueMapT &map, Value value) {
31*dbfc38edSMatthias Springer BufferViewFlowAnalysis::ValueSetT result;
3223dec4a3SJohannes Reifferscheid SmallVector<Value, 8> queue;
33*dbfc38edSMatthias Springer queue.push_back(value);
3423dec4a3SJohannes Reifferscheid while (!queue.empty()) {
3523dec4a3SJohannes Reifferscheid Value currentValue = queue.pop_back_val();
3623dec4a3SJohannes Reifferscheid if (result.insert(currentValue).second) {
37*dbfc38edSMatthias Springer auto it = map.find(currentValue);
38*dbfc38edSMatthias Springer if (it != map.end()) {
3923dec4a3SJohannes Reifferscheid for (Value aliasValue : it->second)
4023dec4a3SJohannes Reifferscheid queue.push_back(aliasValue);
4123dec4a3SJohannes Reifferscheid }
4223dec4a3SJohannes Reifferscheid }
4323dec4a3SJohannes Reifferscheid }
4423dec4a3SJohannes Reifferscheid return result;
4523dec4a3SJohannes Reifferscheid }
4623dec4a3SJohannes Reifferscheid
47*dbfc38edSMatthias Springer /// Find all immediate and indirect dependent buffers this value could
48*dbfc38edSMatthias Springer /// potentially have. Note that the resulting set will also contain the value
49*dbfc38edSMatthias Springer /// provided as it is a dependent alias of itself.
50*dbfc38edSMatthias Springer BufferViewFlowAnalysis::ValueSetT
resolve(Value rootValue) const51*dbfc38edSMatthias Springer BufferViewFlowAnalysis::resolve(Value rootValue) const {
52*dbfc38edSMatthias Springer return resolveValues(dependencies, rootValue);
53*dbfc38edSMatthias Springer }
54*dbfc38edSMatthias Springer
55*dbfc38edSMatthias Springer BufferViewFlowAnalysis::ValueSetT
resolveReverse(Value rootValue) const56*dbfc38edSMatthias Springer BufferViewFlowAnalysis::resolveReverse(Value rootValue) const {
57*dbfc38edSMatthias Springer return resolveValues(reverseDependencies, rootValue);
58*dbfc38edSMatthias Springer }
59*dbfc38edSMatthias Springer
6023dec4a3SJohannes Reifferscheid /// Removes the given values from all alias sets.
remove(const SetVector<Value> & aliasValues)61e6edc1bdSUday Bondhugula void BufferViewFlowAnalysis::remove(const SetVector<Value> &aliasValues) {
6223dec4a3SJohannes Reifferscheid for (auto &entry : dependencies)
6323dec4a3SJohannes Reifferscheid llvm::set_subtract(entry.second, aliasValues);
6423dec4a3SJohannes Reifferscheid }
6523dec4a3SJohannes Reifferscheid
rename(Value from,Value to)66b9982b20SMartin Erhart void BufferViewFlowAnalysis::rename(Value from, Value to) {
67b9982b20SMartin Erhart dependencies[to] = dependencies[from];
68b9982b20SMartin Erhart dependencies.erase(from);
69b9982b20SMartin Erhart
700ba868dbSJaved Absar for (auto &[_, value] : dependencies) {
71b9982b20SMartin Erhart if (value.contains(from)) {
72b9982b20SMartin Erhart value.insert(to);
73b9982b20SMartin Erhart value.erase(from);
74b9982b20SMartin Erhart }
75b9982b20SMartin Erhart }
76b9982b20SMartin Erhart }
77b9982b20SMartin Erhart
7823dec4a3SJohannes Reifferscheid /// This function constructs a mapping from values to its immediate
7923dec4a3SJohannes Reifferscheid /// dependencies. It iterates over all blocks, gets their predecessors,
8023dec4a3SJohannes Reifferscheid /// determines the values that will be passed to the corresponding block
8123dec4a3SJohannes Reifferscheid /// arguments and inserts them into the underlying map. Furthermore, it wires
8223dec4a3SJohannes Reifferscheid /// successor regions and branch-like return operations from nested regions.
build(Operation * op)8323dec4a3SJohannes Reifferscheid void BufferViewFlowAnalysis::build(Operation *op) {
8423dec4a3SJohannes Reifferscheid // Registers all dependencies of the given values.
8523dec4a3SJohannes Reifferscheid auto registerDependencies = [&](ValueRange values, ValueRange dependencies) {
86*dbfc38edSMatthias Springer for (auto [value, dep] : llvm::zip_equal(values, dependencies)) {
8723dec4a3SJohannes Reifferscheid this->dependencies[value].insert(dep);
88*dbfc38edSMatthias Springer this->reverseDependencies[dep].insert(value);
89*dbfc38edSMatthias Springer }
9023dec4a3SJohannes Reifferscheid };
9123dec4a3SJohannes Reifferscheid
92a45e58afSMatthias Springer // Mark all buffer results and buffer region entry block arguments of the
93a45e58afSMatthias Springer // given op as terminals.
94a45e58afSMatthias Springer auto populateTerminalValues = [&](Operation *op) {
95a45e58afSMatthias Springer for (Value v : op->getResults())
96a45e58afSMatthias Springer if (isa<BaseMemRefType>(v.getType()))
97a45e58afSMatthias Springer this->terminals.insert(v);
98a45e58afSMatthias Springer for (Region &r : op->getRegions())
99a45e58afSMatthias Springer for (BlockArgument v : r.getArguments())
100a45e58afSMatthias Springer if (isa<BaseMemRefType>(v.getType()))
101a45e58afSMatthias Springer this->terminals.insert(v);
102a45e58afSMatthias Springer };
103a45e58afSMatthias Springer
10438bef476SMatthias Springer op->walk([&](Operation *op) {
105a45e58afSMatthias Springer // Query BufferViewFlowOpInterface. If the op does not implement that
106a45e58afSMatthias Springer // interface, try to infer the dependencies from other interfaces that the
107a45e58afSMatthias Springer // op may implement.
108a45e58afSMatthias Springer if (auto bufferViewFlowOp = dyn_cast<BufferViewFlowOpInterface>(op)) {
109a45e58afSMatthias Springer bufferViewFlowOp.populateDependencies(registerDependencies);
110a45e58afSMatthias Springer for (Value v : op->getResults())
111a45e58afSMatthias Springer if (isa<BaseMemRefType>(v.getType()) &&
112a45e58afSMatthias Springer bufferViewFlowOp.mayBeTerminalBuffer(v))
113a45e58afSMatthias Springer this->terminals.insert(v);
114a45e58afSMatthias Springer for (Region &r : op->getRegions())
115a45e58afSMatthias Springer for (BlockArgument v : r.getArguments())
116a45e58afSMatthias Springer if (isa<BaseMemRefType>(v.getType()) &&
117a45e58afSMatthias Springer bufferViewFlowOp.mayBeTerminalBuffer(v))
118a45e58afSMatthias Springer this->terminals.insert(v);
119a45e58afSMatthias Springer return WalkResult::advance();
120a45e58afSMatthias Springer }
12138bef476SMatthias Springer
12223dec4a3SJohannes Reifferscheid // Add additional dependencies created by view changes to the alias list.
12338bef476SMatthias Springer if (auto viewInterface = dyn_cast<ViewLikeOpInterface>(op)) {
124a45e58afSMatthias Springer registerDependencies(viewInterface.getViewSource(),
12523dec4a3SJohannes Reifferscheid viewInterface->getResult(0));
12638bef476SMatthias Springer return WalkResult::advance();
12738bef476SMatthias Springer }
12823dec4a3SJohannes Reifferscheid
12938bef476SMatthias Springer if (auto branchInterface = dyn_cast<BranchOpInterface>(op)) {
13023dec4a3SJohannes Reifferscheid // Query all branch interfaces to link block argument dependencies.
13123dec4a3SJohannes Reifferscheid Block *parentBlock = branchInterface->getBlock();
13223dec4a3SJohannes Reifferscheid for (auto it = parentBlock->succ_begin(), e = parentBlock->succ_end();
13323dec4a3SJohannes Reifferscheid it != e; ++it) {
13423dec4a3SJohannes Reifferscheid // Query the branch op interface to get the successor operands.
13523dec4a3SJohannes Reifferscheid auto successorOperands =
13623dec4a3SJohannes Reifferscheid branchInterface.getSuccessorOperands(it.getIndex());
13723dec4a3SJohannes Reifferscheid // Build the actual mapping of values to their immediate dependencies.
13823dec4a3SJohannes Reifferscheid registerDependencies(successorOperands.getForwardedOperands(),
13923dec4a3SJohannes Reifferscheid (*it)->getArguments().drop_front(
14023dec4a3SJohannes Reifferscheid successorOperands.getProducedOperandCount()));
14123dec4a3SJohannes Reifferscheid }
14238bef476SMatthias Springer return WalkResult::advance();
14338bef476SMatthias Springer }
14423dec4a3SJohannes Reifferscheid
14538bef476SMatthias Springer if (auto regionInterface = dyn_cast<RegionBranchOpInterface>(op)) {
14623dec4a3SJohannes Reifferscheid // Query the RegionBranchOpInterface to find potential successor regions.
14723dec4a3SJohannes Reifferscheid // Extract all entry regions and wire all initial entry successor inputs.
14823dec4a3SJohannes Reifferscheid SmallVector<RegionSuccessor, 2> entrySuccessors;
1494dd744acSMarkus Böck regionInterface.getSuccessorRegions(/*point=*/RegionBranchPoint::parent(),
1501a36588eSKazu Hirata entrySuccessors);
15123dec4a3SJohannes Reifferscheid for (RegionSuccessor &entrySuccessor : entrySuccessors) {
15223dec4a3SJohannes Reifferscheid // Wire the entry region's successor arguments with the initial
15323dec4a3SJohannes Reifferscheid // successor inputs.
15423dec4a3SJohannes Reifferscheid registerDependencies(
1554dd744acSMarkus Böck regionInterface.getEntrySuccessorOperands(entrySuccessor),
15623dec4a3SJohannes Reifferscheid entrySuccessor.getSuccessorInputs());
15723dec4a3SJohannes Reifferscheid }
15823dec4a3SJohannes Reifferscheid
15923dec4a3SJohannes Reifferscheid // Wire flow between regions and from region exits.
16023dec4a3SJohannes Reifferscheid for (Region ®ion : regionInterface->getRegions()) {
16123dec4a3SJohannes Reifferscheid // Iterate over all successor region entries that are reachable from the
16223dec4a3SJohannes Reifferscheid // current region.
16323dec4a3SJohannes Reifferscheid SmallVector<RegionSuccessor, 2> successorRegions;
1644dd744acSMarkus Böck regionInterface.getSuccessorRegions(region, successorRegions);
16523dec4a3SJohannes Reifferscheid for (RegionSuccessor &successorRegion : successorRegions) {
16623dec4a3SJohannes Reifferscheid // Iterate over all immediate terminator operations and wire the
16723dec4a3SJohannes Reifferscheid // successor inputs with the successor operands of each terminator.
16810ae8ae8SMarkus Böck for (Block &block : region)
16910ae8ae8SMarkus Böck if (auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(
17010ae8ae8SMarkus Böck block.getTerminator()))
1714dd744acSMarkus Böck registerDependencies(
1724dd744acSMarkus Böck terminator.getSuccessorOperands(successorRegion),
17323dec4a3SJohannes Reifferscheid successorRegion.getSuccessorInputs());
17423dec4a3SJohannes Reifferscheid }
17523dec4a3SJohannes Reifferscheid }
17623dec4a3SJohannes Reifferscheid
17738bef476SMatthias Springer return WalkResult::advance();
17838bef476SMatthias Springer }
17938bef476SMatthias Springer
180a45e58afSMatthias Springer // Region terminators are handled together with RegionBranchOpInterface.
181a45e58afSMatthias Springer if (isa<RegionBranchTerminatorOpInterface>(op))
182a45e58afSMatthias Springer return WalkResult::advance();
183a45e58afSMatthias Springer
184a45e58afSMatthias Springer if (isa<CallOpInterface>(op)) {
185a45e58afSMatthias Springer // This is an intra-function analysis. We have no information about other
186a45e58afSMatthias Springer // functions. Conservatively assume that each operand may alias with each
187a45e58afSMatthias Springer // result. Also mark the results are terminals because the function could
188a45e58afSMatthias Springer // return newly allocated buffers.
189a45e58afSMatthias Springer populateTerminalValues(op);
190a45e58afSMatthias Springer for (Value operand : op->getOperands())
191a45e58afSMatthias Springer for (Value result : op->getResults())
19238bef476SMatthias Springer registerDependencies({operand}, {result});
193a45e58afSMatthias Springer return WalkResult::advance();
19438bef476SMatthias Springer }
195a45e58afSMatthias Springer
196a45e58afSMatthias Springer // We have no information about unknown ops.
197a45e58afSMatthias Springer populateTerminalValues(op);
198a45e58afSMatthias Springer
19938bef476SMatthias Springer return WalkResult::advance();
20023dec4a3SJohannes Reifferscheid });
20123dec4a3SJohannes Reifferscheid }
202a45e58afSMatthias Springer
mayBeTerminalBuffer(Value value) const203a45e58afSMatthias Springer bool BufferViewFlowAnalysis::mayBeTerminalBuffer(Value value) const {
204a45e58afSMatthias Springer assert(isa<BaseMemRefType>(value.getType()) && "expected memref");
205a45e58afSMatthias Springer return terminals.contains(value);
206a45e58afSMatthias Springer }
207*dbfc38edSMatthias Springer
208*dbfc38edSMatthias Springer //===----------------------------------------------------------------------===//
209*dbfc38edSMatthias Springer // BufferOriginAnalysis
210*dbfc38edSMatthias Springer //===----------------------------------------------------------------------===//
211*dbfc38edSMatthias Springer
212*dbfc38edSMatthias Springer /// Return "true" if the given value is the result of a memory allocation.
hasAllocateSideEffect(Value v)213*dbfc38edSMatthias Springer static bool hasAllocateSideEffect(Value v) {
214*dbfc38edSMatthias Springer Operation *op = v.getDefiningOp();
215*dbfc38edSMatthias Springer if (!op)
216*dbfc38edSMatthias Springer return false;
217*dbfc38edSMatthias Springer return hasEffect<MemoryEffects::Allocate>(op, v);
218*dbfc38edSMatthias Springer }
219*dbfc38edSMatthias Springer
220*dbfc38edSMatthias Springer /// Return "true" if the given value is a function block argument.
isFunctionArgument(Value v)221*dbfc38edSMatthias Springer static bool isFunctionArgument(Value v) {
222*dbfc38edSMatthias Springer auto bbArg = dyn_cast<BlockArgument>(v);
223*dbfc38edSMatthias Springer if (!bbArg)
224*dbfc38edSMatthias Springer return false;
225*dbfc38edSMatthias Springer Block *b = bbArg.getOwner();
226*dbfc38edSMatthias Springer auto funcOp = dyn_cast<FunctionOpInterface>(b->getParentOp());
227*dbfc38edSMatthias Springer if (!funcOp)
228*dbfc38edSMatthias Springer return false;
229*dbfc38edSMatthias Springer return bbArg.getOwner() == &funcOp.getFunctionBody().front();
230*dbfc38edSMatthias Springer }
231*dbfc38edSMatthias Springer
232*dbfc38edSMatthias Springer /// Given a memref value, return the "base" value by skipping over all
233*dbfc38edSMatthias Springer /// ViewLikeOpInterface ops (if any) in the reverse use-def chain.
getViewBase(Value value)234*dbfc38edSMatthias Springer static Value getViewBase(Value value) {
235*dbfc38edSMatthias Springer while (auto viewLikeOp = value.getDefiningOp<ViewLikeOpInterface>())
236*dbfc38edSMatthias Springer value = viewLikeOp.getViewSource();
237*dbfc38edSMatthias Springer return value;
238*dbfc38edSMatthias Springer }
239*dbfc38edSMatthias Springer
BufferOriginAnalysis(Operation * op)240*dbfc38edSMatthias Springer BufferOriginAnalysis::BufferOriginAnalysis(Operation *op) : analysis(op) {}
241*dbfc38edSMatthias Springer
isSameAllocation(Value v1,Value v2)242*dbfc38edSMatthias Springer std::optional<bool> BufferOriginAnalysis::isSameAllocation(Value v1, Value v2) {
243*dbfc38edSMatthias Springer assert(isa<BaseMemRefType>(v1.getType()) && "expected buffer");
244*dbfc38edSMatthias Springer assert(isa<BaseMemRefType>(v2.getType()) && "expected buffer");
245*dbfc38edSMatthias Springer
246*dbfc38edSMatthias Springer // Skip over all view-like ops.
247*dbfc38edSMatthias Springer v1 = getViewBase(v1);
248*dbfc38edSMatthias Springer v2 = getViewBase(v2);
249*dbfc38edSMatthias Springer
250*dbfc38edSMatthias Springer // Fast path: If both buffers are the same SSA value, we can be sure that
251*dbfc38edSMatthias Springer // they originate from the same allocation.
252*dbfc38edSMatthias Springer if (v1 == v2)
253*dbfc38edSMatthias Springer return true;
254*dbfc38edSMatthias Springer
255*dbfc38edSMatthias Springer // Compute the SSA values from which the buffers `v1` and `v2` originate.
256*dbfc38edSMatthias Springer SmallPtrSet<Value, 16> origin1 = analysis.resolveReverse(v1);
257*dbfc38edSMatthias Springer SmallPtrSet<Value, 16> origin2 = analysis.resolveReverse(v2);
258*dbfc38edSMatthias Springer
259*dbfc38edSMatthias Springer // Originating buffers are "terminal" if they could not be traced back any
260*dbfc38edSMatthias Springer // further by the `BufferViewFlowAnalysis`. Examples of terminal buffers:
261*dbfc38edSMatthias Springer // - function block arguments
262*dbfc38edSMatthias Springer // - values defined by allocation ops such as "memref.alloc"
263*dbfc38edSMatthias Springer // - values defined by ops that are unknown to the buffer view flow analysis
264*dbfc38edSMatthias Springer // - values that are marked as "terminal" in the `BufferViewFlowOpInterface`
265*dbfc38edSMatthias Springer SmallPtrSet<Value, 16> terminal1, terminal2;
266*dbfc38edSMatthias Springer
267*dbfc38edSMatthias Springer // While gathering terminal buffers, keep track of whether all terminal
268*dbfc38edSMatthias Springer // buffers are newly allocated buffer or function entry arguments.
269*dbfc38edSMatthias Springer bool allAllocs1 = true, allAllocs2 = true;
270*dbfc38edSMatthias Springer bool allAllocsOrFuncEntryArgs1 = true, allAllocsOrFuncEntryArgs2 = true;
271*dbfc38edSMatthias Springer
272*dbfc38edSMatthias Springer // Helper function that gathers terminal buffers among `origin`.
273*dbfc38edSMatthias Springer auto gatherTerminalBuffers = [this](const SmallPtrSet<Value, 16> &origin,
274*dbfc38edSMatthias Springer SmallPtrSet<Value, 16> &terminal,
275*dbfc38edSMatthias Springer bool &allAllocs,
276*dbfc38edSMatthias Springer bool &allAllocsOrFuncEntryArgs) {
277*dbfc38edSMatthias Springer for (Value v : origin) {
278*dbfc38edSMatthias Springer if (isa<BaseMemRefType>(v.getType()) && analysis.mayBeTerminalBuffer(v)) {
279*dbfc38edSMatthias Springer terminal.insert(v);
280*dbfc38edSMatthias Springer allAllocs &= hasAllocateSideEffect(v);
281*dbfc38edSMatthias Springer allAllocsOrFuncEntryArgs &=
282*dbfc38edSMatthias Springer isFunctionArgument(v) || hasAllocateSideEffect(v);
283*dbfc38edSMatthias Springer }
284*dbfc38edSMatthias Springer }
285*dbfc38edSMatthias Springer assert(!terminal.empty() && "expected non-empty terminal set");
286*dbfc38edSMatthias Springer };
287*dbfc38edSMatthias Springer
288*dbfc38edSMatthias Springer // Gather terminal buffers for `v1` and `v2`.
289*dbfc38edSMatthias Springer gatherTerminalBuffers(origin1, terminal1, allAllocs1,
290*dbfc38edSMatthias Springer allAllocsOrFuncEntryArgs1);
291*dbfc38edSMatthias Springer gatherTerminalBuffers(origin2, terminal2, allAllocs2,
292*dbfc38edSMatthias Springer allAllocsOrFuncEntryArgs2);
293*dbfc38edSMatthias Springer
294*dbfc38edSMatthias Springer // If both `v1` and `v2` have a single matching terminal buffer, they are
295*dbfc38edSMatthias Springer // guaranteed to originate from the same buffer allocation.
296*dbfc38edSMatthias Springer if (llvm::hasSingleElement(terminal1) && llvm::hasSingleElement(terminal2) &&
297*dbfc38edSMatthias Springer *terminal1.begin() == *terminal2.begin())
298*dbfc38edSMatthias Springer return true;
299*dbfc38edSMatthias Springer
300*dbfc38edSMatthias Springer // At least one of the two values has multiple terminals.
301*dbfc38edSMatthias Springer
302*dbfc38edSMatthias Springer // Check if there is overlap between the terminal buffers of `v1` and `v2`.
303*dbfc38edSMatthias Springer bool distinctTerminalSets = true;
304*dbfc38edSMatthias Springer for (Value v : terminal1)
305*dbfc38edSMatthias Springer distinctTerminalSets &= !terminal2.contains(v);
306*dbfc38edSMatthias Springer // If there is overlap between the terminal buffers of `v1` and `v2`, we
307*dbfc38edSMatthias Springer // cannot make an accurate decision without further analysis.
308*dbfc38edSMatthias Springer if (!distinctTerminalSets)
309*dbfc38edSMatthias Springer return std::nullopt;
310*dbfc38edSMatthias Springer
311*dbfc38edSMatthias Springer // If `v1` originates from only allocs, and `v2` is guaranteed to originate
312*dbfc38edSMatthias Springer // from different allocations (that is guaranteed if `v2` originates from
313*dbfc38edSMatthias Springer // only distinct allocs or function entry arguments), we can be sure that
314*dbfc38edSMatthias Springer // `v1` and `v2` originate from different allocations. The same argument can
315*dbfc38edSMatthias Springer // be made when swapping `v1` and `v2`.
316*dbfc38edSMatthias Springer bool isolatedAlloc1 = allAllocs1 && (allAllocs2 || allAllocsOrFuncEntryArgs2);
317*dbfc38edSMatthias Springer bool isolatedAlloc2 = (allAllocs1 || allAllocsOrFuncEntryArgs1) && allAllocs2;
318*dbfc38edSMatthias Springer if (isolatedAlloc1 || isolatedAlloc2)
319*dbfc38edSMatthias Springer return false;
320*dbfc38edSMatthias Springer
321*dbfc38edSMatthias Springer // Otherwise: We do not know whether `v1` and `v2` originate from the same
322*dbfc38edSMatthias Springer // allocation or not.
323*dbfc38edSMatthias Springer // TODO: Function arguments are currently handled conservatively. We assume
324*dbfc38edSMatthias Springer // that they could be the same allocation.
325*dbfc38edSMatthias Springer // TODO: Terminals other than allocations and function arguments are
326*dbfc38edSMatthias Springer // currently handled conservatively. We assume that they could be the same
327*dbfc38edSMatthias Springer // allocation. E.g., we currently return "nullopt" for values that originate
328*dbfc38edSMatthias Springer // from different "memref.get_global" ops (with different symbols).
329*dbfc38edSMatthias Springer return std::nullopt;
330*dbfc38edSMatthias Springer }
331