`alloc_op`. Currently supported are "memref.alloc" and "memref.alloca". In
case of a "memref.alloca", the buffer is not deallocated.
+ If `bufferize_destination_only` is set, only the destination operands of the
+ op are bufferized to a new memory allocation, but not the op itself.
+
#### Return modes
This operation consumes the `target` handle and produces the
DefaultValuedAttr<StrAttr, "\"memref.tensor_store\"">:
$memcpy_op,
DefaultValuedAttr<StrAttr, "\"memref.alloc\"">:
- $alloc_op);
+ $alloc_op,
+ UnitAttr:$bufferize_destination_only);
let hasVerifier = 1;
let results = (outs Transform_AnyValue:$allocated_buffer,
Transform_AnyOpType:$new_ops);
let assemblyFormat = "$target attr-dict `:` type($target)";
-
+
let builders = [
OpBuilder<(ins "Value":$target, "Attribute":$memorySpace)>,
OpBuilder<(ins "Value":$target, "int64_t":$memorySpace)>
Value linalg::bufferizeToAllocation(
RewriterBase &rewriter, const linalg::BufferizeToAllocationOptions &options,
PadOp padOp, Attribute memorySpace, Operation *insertionPoint) {
+ // tensor.pad does not have a destination operand.
+ assert(!options.bufferizeDestinationOnly && "invalid options");
+
OpBuilder::InsertionGuard g(rewriter);
rewriter.setInsertionPoint(insertionPoint ? insertionPoint : padOp);
Location loc = padOp.getLoc();
rewriter, options, maskOp.getMaskableOp(), memorySpace,
/*insertionPoint=*/insertionPoint ? insertionPoint : maskOp);
+ if (options.bufferizeDestinationOnly)
+ return alloc;
+
// Bufferize terminator.
rewriter.setInsertionPoint(yieldOp);
if (failed(cast<bufferization::BufferizableOpInterface>(yieldOp).bufferize(
BufferizationOptions bufferizationOptions;
AnalysisState state(bufferizationOptions);
+#ifndef NDEBUG
+ // Ops with nested tensor ops are not supported yet. At the moment, this
+ // function just bufferizes the given op itself, but not its body.
+ op->walk([&](Operation *nestedOp) {
+ if (op == nestedOp)
+ return;
+ if (llvm::any_of(nestedOp->getOperands(),
+ [](Value v) { return v.getType().isa<TensorType>(); }))
+ llvm_unreachable("ops with nested tensor ops are not supported yet");
+ if (llvm::any_of(nestedOp->getResults(),
+ [](Value v) { return v.getType().isa<TensorType>(); }))
+ llvm_unreachable("ops with nested tensor ops are not supported yet");
+ });
+#endif // NDEBUG
+
// Gather tensor results.
SmallVector<OpResult> tensorResults;
for (OpResult result : op->getResults()) {
createMemcpy(rewriter, op->getLoc(), operand->get(), alloc, options);
}
rewriter.updateRootInPlace(op, [&]() {
- operand->set(rewriter.create<ToTensorOp>(op->getLoc(), alloc));
+ auto toTensorOp = rewriter.create<ToTensorOp>(op->getLoc(), alloc);
+ operand->set(toTensorOp);
+ if (options.bufferizeDestinationOnly) {
+ rewriter.updateRootInPlace(toTensorOp, [&]() {
+ toTensorOp.setRestrict(true);
+ toTensorOp.setWritable(true);
+ });
+ }
});
}
+ if (options.bufferizeDestinationOnly)
+ return allocs.front();
+
// Bufferize the op.
rewriter.setInsertionPoint(op);
if (failed(bufferizableOp.bufferize(rewriter, bufferizationOptions)))
%0 = transform.structured.match ops{["vector.mask"]} in %arg1 : (!transform.any_op) -> !transform.any_op
%2, %new = transform.structured.bufferize_to_allocation %0 {memory_space = 4} : !transform.any_op
}
+
+// -----
+
+// CHECK-LABEL: func @tensor_insert_destination(
+// CHECK-SAME: %[[t:.*]]: tensor<?x10xindex>
+// CHECK: %[[alloc:.*]] = memref.alloc(%{{.*}}) : memref<?x10xindex, 4>
+// CHECK: memref.tensor_store %[[t]], %[[alloc]]
+// CHECK: %[[t2:.*]] = bufferization.to_tensor %[[alloc]] restrict writable
+// CHECK: %[[inserted:.*]] = tensor.insert %{{.*}} into %[[t2]]
+// CHECK: memref.dealloc %[[alloc]]
+// CHECK: return %[[inserted]]
+func.func @tensor_insert_destination(%t: tensor<?x10xindex>, %idx: index, %v: index) -> tensor<?x10xindex> {
+ %r = tensor.insert %v into %t[%idx, %idx] : tensor<?x10xindex>
+ return %r : tensor<?x10xindex>
+}
+
+transform.sequence failures(propagate) {
+^bb1(%arg1: !transform.any_op):
+ %0 = transform.structured.match ops{["tensor.insert"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+ %2, %new = transform.structured.bufferize_to_allocation %0 {memory_space = 4, bufferize_destination_only} : !transform.any_op
+}