Add an additional result handle to the op. This new handle is mapped to the newly allocated buffer.
Differential Revision: https://reviews.llvm.org/D153514
let description = [{
This transform materializes an allocation for the targeted tensor value. It
replaces all original uses of the target with the newly allocated buffer,
- wrapped in a `bufferization.to_tensor` op. It returns a handle to the result
- of the `to_tensor` op.
+ wrapped in a `bufferization.to_tensor` op. It returns a handle to the newly
+ allocated buffer. Furthermore, it returns a handle to the result of the
+ `to_tensor` op.
Example:
```
#### Return modes
- This operation consumes the `target` handle and produces the `transformed`
- handle. It always succeeds.
+ This operation consumes the `target` handle and produces the `replacement`
+ and `allocated_buffer` handles. It always succeeds.
}];
let arguments = (ins Transform_AnyValue:$target,
OptionalAttr<AnyAttr>:$memory_space);
- let results = (outs Transform_AnyValue:$transformed);
+ let results = (outs Transform_AnyValue:$allocated_buffer,
+ Transform_AnyValue:$replacement);
let assemblyFormat = "$target attr-dict";
}
/// memref.tensor_store %t, %subview
/// %0 = bufferization.to_tensor %alloc restrict writable
///
-/// In addition to rewriting the IR as shown above, the result of the
-/// bufferization.to_tensor op is returned.
+/// In addition to rewriting the IR as shown above, this function returns the
+/// newly allocated buffer. Furthermore, the result of the
+/// bufferization.to_tensor op is optionally returned via `replacement`.
Value bufferizeToAllocation(RewriterBase &rewriter, tensor::PadOp padOp,
- Attribute memorySpace = {});
+ Attribute memorySpace = {},
+ Value *replacement = nullptr);
/// Materialize a buffer allocation for the given tensor value. E.g.:
///
///
/// In case `value` is a tensor.pad result, the corresponding overload is used
/// internally to produce a better bufferization.
+///
+/// In addition to rewriting the IR as shown above, this function returns the
+/// newly allocated buffer. Furthermore, the result of the
+/// bufferization.to_tensor op is optionally returned via `replacement`.
Value bufferizeToAllocation(RewriterBase &rewriter, Value value,
- Attribute memorySpace = {});
+ Attribute memorySpace = {},
+ Value *replacement = nullptr);
/// Fuse two `linalg.generic` operations that have a producer-consumer
/// relationship captured through `fusedOperand`. The method expects
transform::TransformResults &results, transform::TransformState &state) {
Attribute memorySpace =
getMemorySpace().has_value() ? getMemorySpace().value() : Attribute();
- auto transformed = llvm::to_vector(
- llvm::map_range(state.getPayloadValues(getTarget()), [&](Value v) {
- return linalg::bufferizeToAllocation(rewriter, v, memorySpace);
- }));
- results.setValues(cast<OpResult>(getTransformed()), transformed);
+ SmallVector<Value> replacements;
+ SmallVector<Value> allocatedBuffers;
+ for (Value value : state.getPayloadValues(getTarget())) {
+ Value replacement;
+ Value buffer = linalg::bufferizeToAllocation(rewriter, value, memorySpace,
+ &replacement);
+ replacements.push_back(replacement);
+ allocatedBuffers.push_back(buffer);
+ }
+ results.setValues(cast<OpResult>(getReplacement()), replacements);
+ results.setValues(cast<OpResult>(getAllocatedBuffer()), allocatedBuffers);
return DiagnosedSilenceableFailure::success();
}
void transform::BufferizeToAllocationOp::getEffects(
SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
consumesHandle(getTarget(), effects);
- producesHandle(getTransformed(), effects);
+ producesHandle(getReplacement(), effects);
+ producesHandle(getAllocatedBuffer(), effects);
modifiesPayload(effects);
}
}
Value linalg::bufferizeToAllocation(RewriterBase &rewriter, PadOp padOp,
- Attribute memorySpace) {
+ Attribute memorySpace, Value *replacement) {
OpBuilder::InsertionGuard g(rewriter);
rewriter.setInsertionPoint(padOp);
Location loc = padOp.getLoc();
Value toTensorOp = rewriter.create<bufferization::ToTensorOp>(
loc, alloc, /*restrict=*/true, /*writable=*/true);
rewriter.replaceOp(padOp, toTensorOp);
- return toTensorOp;
+
+ if (replacement)
+ *replacement = toTensorOp;
+ return alloc;
}
/// Lower tensor.from_elements to a sequence of chained tensor.insert.
}
Value linalg::bufferizeToAllocation(RewriterBase &rewriter, Value value,
- Attribute memorySpace) {
+ Attribute memorySpace, Value *replacement) {
// Call specialized overload for certain ops.
if (auto padOp = value.getDefiningOp<PadOp>())
- return bufferizeToAllocation(rewriter, padOp, memorySpace);
+ return bufferizeToAllocation(rewriter, padOp, memorySpace, replacement);
// Collect all uses.
SmallVector<OpOperand *> uses = llvm::to_vector(
[&]() { use->set(toTensorOp); });
}
- return toTensorOp;
+ if (replacement)
+ *replacement = toTensorOp;
+ return alloc;
}
namespace {
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["tensor.pad"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = transform.get_result %0[0] : (!transform.any_op) -> !transform.any_value
- %2 = transform.structured.bufferize_to_allocation %1
+ %2, %3 = transform.structured.bufferize_to_allocation %1
}
// -----
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["tensor.pad"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = transform.get_result %0[0] : (!transform.any_op) -> !transform.any_value
- %2 = transform.structured.bufferize_to_allocation %1
+ %2, %3 = transform.structured.bufferize_to_allocation %1
// Make sure that One-Shot Bufferize can bufferize the rest.
- %3 = transform.bufferization.one_shot_bufferize %arg1 : (!transform.any_op) -> !transform.any_op
+ %4 = transform.bufferization.one_shot_bufferize %arg1 : (!transform.any_op) -> !transform.any_op
}
// -----
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["tensor.extract"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = test_produce_value_handle_to_argument_of_parent_block %0, 0 : (!transform.any_op) -> !transform.any_value
- %2 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
+ %2, %3 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
}
// -----
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["tensor.extract"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = test_produce_value_handle_to_argument_of_parent_block %0, 0 : (!transform.any_op) -> !transform.any_value
- %2 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
+ %2, %3 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
// Make sure that One-Shot Bufferize can bufferize the rest.
- %3 = transform.bufferization.one_shot_bufferize %arg1 : (!transform.any_op) -> !transform.any_op
+ %4 = transform.bufferization.one_shot_bufferize %arg1 : (!transform.any_op) -> !transform.any_op
}
// -----
^bb1(%arg1: !transform.any_op):
%0 = transform.structured.match ops{["dummy.some_op"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%1 = transform.get_result %0[0] : (!transform.any_op) -> !transform.any_value
- %2 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
+ %2, %3 = transform.structured.bufferize_to_allocation %1 {memory_space = 4}
}