Skip to content

Commit a02ad6c

Browse files
[mlir][bufferization] Generalize getAliasingOpResults to getAliasingValues
This revision is needed to support bufferization of `cf.br`/`cf.cond_br`. It will also be useful for better analysis of loop ops. This revision generalizes `getAliasingOpResults` to `getAliasingValues`. An OpOperand can now not only alias with OpResults but also with BlockArguments. In the case of `cf.br` (will be added in a later revision): a `cf.br` operand will alias with the corresponding argument of the destination block. If an op does not implement the `BufferizableOpInterface`, the analysis in conservative. It previously assumed that an OpOperand may alias with each OpResult. It now assumes that an OpOperand may alias with each OpResult and each BlockArgument of the entry block. Differential Revision: https://reviews.llvm.org/D157957
1 parent fdbc944 commit a02ad6c

File tree

16 files changed

+354
-286
lines changed

16 files changed

+354
-286
lines changed

mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,13 @@ struct AliasingOpOperand {
4949
bool isDefinite;
5050
};
5151

52-
/// A maybe aliasing OpResult. If `isDefinite` is `true`, the OpResult is
53-
/// guaranteed to alias at runtime.
54-
struct AliasingOpResult {
55-
AliasingOpResult(OpResult opResult, BufferRelation relation,
56-
bool isDefinite = true)
57-
: opResult(opResult), relation(relation), isDefinite(isDefinite) {}
52+
/// A maybe aliasing Value. If `isDefinite` is `true`, the Value is guaranteed
53+
/// to alias at runtime.
54+
struct AliasingValue {
55+
AliasingValue(Value value, BufferRelation relation, bool isDefinite = true)
56+
: value(value), relation(relation), isDefinite(isDefinite) {}
5857

59-
OpResult opResult;
58+
Value value;
6059
BufferRelation relation;
6160
bool isDefinite;
6261
};
@@ -90,12 +89,12 @@ template <typename T> class AliasList {
9089
};
9190

9291
/// A list of possible aliasing OpOperands. This list models the runtime
93-
/// aliasing relationship for an OpResult.
92+
/// aliasing relationship for a Value.
9493
using AliasingOpOperandList = AliasList<AliasingOpOperand>;
9594

96-
/// A list of possible aliasing OpResults. This list models the runtime
97-
/// aliasing relationship for an OpOperand.
98-
using AliasingOpResultList = AliasList<AliasingOpResult>;
95+
/// A list of possible aliasing Values. This list models the runtime aliasing
96+
/// relationship for an OpOperand.
97+
using AliasingValueList = AliasList<AliasingValue>;
9998

10099
class OpFilter {
101100
public:
@@ -418,15 +417,14 @@ struct TraversalConfig {
418417
/// tensor values.
419418
class AnalysisState {
420419
public:
421-
/// Determine which OpOperand* will alias with `result` if the op is
420+
/// Determine which OpOperand* will alias with `value` if the op is
422421
/// bufferized in place. Return all tensor OpOperand* if the op is not
423422
/// bufferizable.
424-
AliasingOpOperandList getAliasingOpOperands(OpResult result) const;
423+
AliasingOpOperandList getAliasingOpOperands(Value value) const;
425424

426-
/// Determine which OpResult will alias with `opOperand` if the op is
427-
/// bufferized in place. Return all tensor OpResults if the op is not
428-
/// bufferizable.
429-
AliasingOpResultList getAliasingOpResults(OpOperand &opOperand) const;
425+
/// Determine which Value will alias with `opOperand` if the op is bufferized
426+
/// in place. Return all tensor Values if the op is not bufferizable.
427+
AliasingValueList getAliasingValues(OpOperand &opOperand) const;
430428

431429
/// Return true if `opOperand` bufferizes to a memory read. Return `true` if
432430
/// the op is not bufferizable.
@@ -685,7 +683,7 @@ namespace detail {
685683
/// This is the default implementation of
686684
/// BufferizableOpInterface::getAliasingOpOperands. Should not be called from
687685
/// other places.
688-
AliasingOpOperandList defaultGetAliasingOpOperands(OpResult opResult,
686+
AliasingOpOperandList defaultGetAliasingOpOperands(Value value,
689687
const AnalysisState &state);
690688

691689
/// This is the default implementation of
@@ -709,11 +707,11 @@ bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp,
709707

710708
/// This is the default implementation of getAliasingOpOperands in case the
711709
/// defining op does not implement the BufferizableOpInterface.
712-
AliasingOpOperandList unknownGetAliasingOpOperands(OpResult opResult);
710+
AliasingOpOperandList unknownGetAliasingOpOperands(Value value);
713711

714-
/// This is the default implementation of getAliasingOpResults in case the
715-
/// owner op does not implement the BufferizableOpInterface.
716-
AliasingOpResultList unknownGetAliasingOpResults(OpOperand &opOperand);
712+
/// This is the default implementation of getAliasingValues in case the owner
713+
/// op does not implement the BufferizableOpInterface.
714+
AliasingValueList unknownGetAliasingValues(OpOperand &opOperand);
717715
} // namespace detail
718716

719717
} // namespace bufferization

mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
1818

1919
Note: All "bufferizesTo*" and "getAliasing*" interface methods must be
2020
implemented conservatively. If it is not statically known whether an
21-
OpOperand/OpResult bufferizes in a certain way (e.g., to a memory write),
21+
OpOperand/Value bufferizes in a certain way (e.g., to a memory write),
2222
the worst case must be assumed (e.g., that it does). Similarly,
2323
"getAliasing*" interface methods may always return additional OpOperands or
24-
OpResults, but must not miss an OpOperand or OpResult that could potentially
24+
Values, but must not miss an OpOperand or Value that could potentially
2525
alias at runtime.
2626
}];
2727
let cppNamespace = "::mlir::bufferization";
2828
let methods = [
2929
InterfaceMethod<
3030
/*desc=*/[{
31-
Return `true` if the given OpResult may bufferize to a new buffer
32-
allocation. If it is statically unknown if the given OpResult
31+
Return `true` if the given Value may bufferize to a new buffer
32+
allocation. If it is statically unknown that the given Value
3333
bufferizes to a buffer allocation, `true` should be returned.
3434
}],
3535
/*retType=*/"bool",
3636
/*methodName=*/"bufferizesToAllocation",
37-
/*args=*/(ins "::mlir::OpResult":$opResult),
37+
/*args=*/(ins "::mlir::Value":$value),
3838
/*methodBody=*/"",
3939
/*defaultImplementation=*/"return false;"
4040
>,
@@ -68,10 +68,9 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
6868
tensor type.
6969

7070
This method will never be called on OpOperands that do not have an
71-
aliasing OpResult. Intuitively, it does not make sense for an
72-
OpOperand to bufferize to a memory write without returning an aliasing
73-
tensor, because the write would have no visible effect outside of the
74-
op.
71+
aliasing Value. Intuitively, it does not make sense for an OpOperand
72+
to bufferize to a memory write without returning an aliasing tensor,
73+
because the write would have no visible effect outside of the op.
7574

7675
Note: It is always safe to consider an OpOperand as a memory write,
7776
even if it does actually not write; however, this can introduce
@@ -87,7 +86,7 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
8786
/*defaultImplementation=*/[{
8887
// Does not have to be implemented for ops without tensor OpOperands.
8988
// Does not have to be implemented for OpOperands that do not have an
90-
// aliasing OpResult.
89+
// aliasing Value.
9190
llvm_unreachable("bufferizesToMemoryWrite not implemented");
9291
}]
9392
>,
@@ -221,21 +220,21 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
221220
>,
222221
InterfaceMethod<
223222
/*desc=*/[{
224-
Return the OpResults that may alias with a given OpOperand when
223+
Return the Values that may alias with a given OpOperand when
225224
bufferized in-place. This method will never be called on OpOperands
226225
that do not have a tensor type.
227226

228-
This method can return multiple OpResults, indicating that a given
227+
This method can return multiple Values, indicating that a given
229228
OpOperand may at runtime alias with any (or multiple) of the returned
230-
OpResults.
229+
Values.
231230

232231
Each alias is specified with a degree of certainty:
233232

234233
* MAYBE (`isDefinite = false`): At runtime, buffer(opOperand) may
235-
alias with the specified OpResult.
234+
alias with the specified Value.
236235
* DEFINITE (`isDefinite = true`, default): At runtime,
237236
buffer(opOperand) is guaranteed to alias the buffer of the specified
238-
OpResult. This is a stronger property than MAYBE and allows for more
237+
Value. This is a stronger property than MAYBE and allows for more
239238
precise analyses. DEFINITE properties should be used when possible.
240239

241240
Furthermore, each alias is specified with a buffer relation:
@@ -245,69 +244,69 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
245244
* `BufferRelation::Unknown`: There is no further information apart
246245
from the fact that both buffers alias.
247246

248-
False positives are allowed in the list of OpResults, but they can
247+
False positives are allowed in the list of Values, but they can
249248
adversely affect the accuracy of the anlysis. On the contrary,
250249
omitting potential aliases is incorrect.
251250

252251
One possible (conservative) implementation of this interface method,
253-
that is always safe, is to return all tensor OpResults with
252+
that is always safe, is to return all tensor Values with
254253
BufferRelation::Unknown and MAYBE.
255254

256255
Examples:
257256

258257
```
259-
// aliasingOpResults(%t) = DEFINITE {Equivalent %r}
258+
// aliasingValues(%t) = DEFINITE {Equivalent %r}
260259
%r = tensor.insert_slice %f into %t : tensor<10xf32>
261260

262-
// aliasingOpResults(%t) = DEFINITE {Unknown %r}
261+
// aliasingValues(%t) = DEFINITE {Unknown %r}
263262
// Note: "Buffer is subset of buffer" relationship are not yet
264263
// supported, so "Unknown" is the best we can do for now.
265264
%r = tensor.extract_slice %t[0]][5][1]
266265
: tensor<10xf32> to tensor<5xf32>
267266

268-
// aliasingOpResults(%t1) = MAYBE {Equivalent %r}
269-
// aliasingOpResults(%t2) = MAYBE {Equivalent %r}
267+
// aliasingValues(%t1) = MAYBE {Equivalent %r}
268+
// aliasingValues(%t2) = MAYBE {Equivalent %r}
270269
%r = arith.select %c, %t1, %t2 : tensor<10xf32>
271270

272271
// A hypothetical op that bufferizes to rolling a dice and based on
273272
// the result to either return buffer(%t) or a newly allocated copy
274273
// thereof.
275-
// aliasingOpResults(%t) = MAYBE {Equivalent %r}
274+
// aliasingValues(%t) = MAYBE {Equivalent %r}
276275
%r = "dummy.alias_or_copy(%t) : (tensor<10xf32>) -> (tensor<10xf32>)"
277276
```
278277
}],
279-
/*retType=*/"::mlir::bufferization::AliasingOpResultList",
280-
/*methodName=*/"getAliasingOpResults",
278+
/*retType=*/"::mlir::bufferization::AliasingValueList",
279+
/*methodName=*/"getAliasingValues",
281280
/*args=*/(ins "::mlir::OpOperand &":$opOperand,
282281
"const ::mlir::bufferization::AnalysisState &":$state),
283282
/*methodBody=*/"",
284283
/*defaultImplementation=*/[{
285284
// Does not have to be implemented for ops without tensor OpOperands.
286285
assert(::llvm::isa<::mlir::TensorType>(opOperand.get().getType()) &&
287286
"expected OpOperand with tensor type");
288-
llvm_unreachable("getAliasingOpResults not implemented");
287+
llvm_unreachable("getAliasingValues not implemented");
289288
}]
290289
>,
291290
InterfaceMethod<
292291
/*desc=*/[{
293-
Return the OpOperands that alias with a given OpResult when
294-
bufferized in-place. This method will never be called on OpResults
295-
that do not have a tensor type.
292+
Return the OpOperands that alias with a given Value when bufferized
293+
in-place. This method will never be called on Values that do not
294+
have a tensor type.
296295

297-
By default, this method is the inverse of `getAliasingOpResults`. Ops
296+
By default, this method is the inverse of `getAliasingValues`. Ops
298297
with a region that yield values may want to override this method to
299298
return the OpOperands that are yielded by the terminator.
300299

301300
This method can return multiple OpOperands, indicating that a given
302-
OpResult may at runtime alias with any (or multiple) of the returned
301+
Value may at runtime alias with any (or multiple) of the returned
303302
OpOperands.
304303

305304
This property is specified with a degree of certainty:
306305

307-
* MAYBE (`isDefinite = false`): At runtime, buffer(opResult) may
308-
alias with the specified OpOperand.
306+
* MAYBE (`isDefinite = false`): At runtime, buffer(value) may alias
307+
with the specified OpOperand.
309308
* DEFINITE (`isDefinite = true`, default): At runtime,
310-
buffer(opResult) is guaranteed to alias the buffer of the specified
309+
buffer(value) is guaranteed to alias the buffer of the specified
311310
OpOperand. This is a stronger property than MAYBE and allows for
312311
more precise analyses. DEFINITE properties should be used when
313312
possible.
@@ -350,14 +349,14 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
350349
}],
351350
/*retType=*/"::mlir::bufferization::AliasingOpOperandList",
352351
/*methodName=*/"getAliasingOpOperands",
353-
/*args=*/(ins "::mlir::OpResult":$opResult,
352+
/*args=*/(ins "::mlir::Value":$value,
354353
"const ::mlir::bufferization::AnalysisState &":$state),
355354
/*methodBody=*/"",
356355
/*defaultImplementation=*/[{
357-
assert(::llvm::isa<::mlir::TensorType>(opResult.getType()) &&
358-
"expected OpResult with tensor type");
356+
assert(isa<::mlir::TensorType>(value.getType()) &&
357+
"expected tensor type");
359358
return ::mlir::bufferization::detail::defaultGetAliasingOpOperands(
360-
opResult, state);
359+
value, state);
361360
}]
362361
>,
363362
InterfaceMethod<
@@ -568,7 +567,7 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
568567
::llvm::cast<::mlir::bufferization::BufferizableOpInterface>(getOperation());
569568
return !bufferizableOp.bufferizesToMemoryRead(opOperand, state)
570569
&& !bufferizableOp.bufferizesToMemoryWrite(opOperand, state)
571-
&& bufferizableOp.getAliasingOpResults(opOperand, state)
570+
&& bufferizableOp.getAliasingValues(opOperand, state)
572571
.getNumAliases() != 0;
573572
}
574573
}];

mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ def Bufferization_AllocTensorOp : Bufferization_Op<"alloc_tensor",
9595
bool resultBufferizesToMemoryWrite(OpResult opResult,
9696
const AnalysisState &state);
9797

98-
bool bufferizesToAllocation(OpResult opResult) { return true; }
98+
bool bufferizesToAllocation(Value value) { return true; }
9999

100100
bool bufferizesToMemoryRead(OpOperand &opOperand,
101101
const AnalysisState &state);
102102

103103
bool bufferizesToMemoryWrite(OpOperand &opOperand,
104104
const AnalysisState &state);
105105

106-
AliasingOpResultList getAliasingOpResults(
106+
AliasingValueList getAliasingValues(
107107
OpOperand &opOperand, const AnalysisState &state);
108108

109109
FailureOr<BaseMemRefType> getBufferType(
@@ -237,7 +237,7 @@ def Bufferization_CopyTensorOp : Bufferization_Op<"copy_tensor",
237237
bool bufferizesToMemoryWrite(OpOperand &opOperand,
238238
const AnalysisState &state);
239239

240-
AliasingOpResultList getAliasingOpResults(
240+
AliasingValueList getAliasingValues(
241241
OpOperand &opOperand, const AnalysisState &state);
242242

243243
RankedTensorType getType() {
@@ -295,7 +295,7 @@ def Bufferization_DeallocTensorOp : Bufferization_Op<"dealloc_tensor",
295295
return false;
296296
}
297297

298-
AliasingOpResultList getAliasingOpResults(
298+
AliasingValueList getAliasingValues(
299299
OpOperand &opOperand, const AnalysisState &state) const {
300300
return {};
301301
}
@@ -459,7 +459,7 @@ def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref", [
459459
return !getReadOnly();
460460
}
461461

462-
AliasingOpResultList getAliasingOpResults(
462+
AliasingValueList getAliasingValues(
463463
OpOperand &opOperand, const AnalysisState &state) const {
464464
return {};
465465
}

mlir/include/mlir/Dialect/Bufferization/IR/DstBufferizableOpInterfaceImpl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ struct DstBufferizableOpInterfaceExternalModel
3636
return dstOp.isDpsInit(&opOperand);
3737
}
3838

39-
AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
40-
const AnalysisState &state) const {
39+
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
40+
const AnalysisState &state) const {
4141
// Output operands alias with their respective tied OpResults.
4242
auto dstOp = cast<DestinationStyleOpInterface>(op);
4343
if (dstOp.isDpsInit(&opOperand))

mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ struct IndexCastOpInterface
7676
return false;
7777
}
7878

79-
AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
80-
const AnalysisState &state) const {
79+
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
80+
const AnalysisState &state) const {
8181
return {{op->getResult(0), BufferRelation::Equivalent}};
8282
}
8383

@@ -123,8 +123,8 @@ struct SelectOpInterface
123123
return false;
124124
}
125125

126-
AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
127-
const AnalysisState &state) const {
126+
AliasingValueList getAliasingValues(Operation *op, OpOperand &opOperand,
127+
const AnalysisState &state) const {
128128
return {{op->getOpResult(0) /*result*/, BufferRelation::Equivalent,
129129
/*isDefinite=*/false}};
130130
}

0 commit comments

Comments
 (0)