[PATCH] D78996: [MLIR][LINALG] Convert Linalg to Linalg
Alex Zinenko via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 09:06:16 PDT 2020
ftynse added a comment.
Here's a more detailed review. I am not familiar enough with the buffer assignment mechanism that was introduced, deferring that to @pifon2a
================
Comment at: mlir/include/mlir/Dialect/Linalg/Passes.h:20
namespace mlir {
+class BufferAssignmentPlacer;
class FuncOp;
----------------
These forward declarations look unnecessary in this file
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:44
+ SmallVector<Value, 2> newBuffers;
+ for (auto result : results) {
+ auto type = result.getType().cast<ShapedType>();
----------------
Please, call `.reserve` on vectors before using `push_back` in a loop
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:47
+ if (!type)
+ op.emitOpError()
+ << "tensor to buffer conversion expects ranked results";
----------------
rewriter.notifyMatchFailure
If this is an invariant of the op itself, it should be checked in the verifier and can be asserted to be correct here.
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:70
+ // Move regions from the old operation to the new one.
+ auto ®ion = linalgOp.region();
+ rewriter.inlineRegionBefore(op.region(), region, region.end());
----------------
Nit: we prefer `auto` in places where it improves readability, i.e. if the type is too long to spell out (e.g., iterators, zippers) or if it is obvious due to a `cast`. I think `Region &` would be just fine here.
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:77
+ auto type = result.getType().cast<ShapedType>();
+ entryBlock.addArgument(type.getElementType());
+ }
----------------
.addArgument (and any inplace modification) is not allowed in a conversion pattern because it's not undoable. You'll have to create a new block with `rewriter.createBlock` and move/clone the operations from the existing block.
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:86
+/// tensors to buffers.
+void populateConvertLinalgOnTensorsToBuffersPattern(
+ MLIRContext *context, BufferAssignmentPlacer *placer,
----------------
LLVM prefers declaring functions `static` to putting them in an anonymous namespace, unlike classes.
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:93-94
+ GenericOpConverter,
+ NonVoidToVoidReturnOpConverter<
+ mlir::ReturnOp, mlir::ReturnOp, linalg::CopyOp>
+ >(context, placer, converter);
----------------
Could you have `using <foo> = NonVoidToVoidReturnOpConverter<mlir::ReturnOp, mlir::ReturnOp, linalg::CopyOp>` and put just `<foo>` here to get less crazy formatting? Don't know what's the name for `<foo>` though.
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:102
+struct ConvertLinalgOnTensorsToBuffers
+ : mlir::PassWrapper<ConvertLinalgOnTensorsToBuffers,
+ OperationPass<ModuleOp>> {
----------------
Given that the pass is declaratively specified, use `ConvertLinalgOnTensorsToBuffersPassBase<ConvertLinalgOnTensorToBuffers>` instead. (also feel free to choose a shorter name for the anonymous class)
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:113
+ Optional<ConversionTarget::DynamicLegalityCallbackFn>(
+ [&](Operation *op) {
+ auto isIllegalType = [&](Type type) {
----------------
Style nit: let's put this lambda outside the function call
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:122
+ // Mark return operations illegal as long as they return values.
+ target.addDynamicallyLegalOp<mlir::ReturnOp>(
+ [](mlir::ReturnOp returnOp) { return returnOp.getNumOperands() == 0; });
----------------
This looks like it would make impossible to have simple helper functions that have no Linalg in them.
```
func @square(%arg0: f32) {
%0 = mulf %arg0, %arg0 : f32
return %0 : f32
}
func @foo(...) {
linalg.generic (...buffers...) {
%0 = call @square(...) : (f32) -> f32
linalg.yield %0 : f32
}
}
```
================
Comment at: mlir/lib/Dialect/Linalg/Transforms/TensorsToBuffers.cpp:126
+ // Mark the function operation illegal as long as an argument is tensor.
+ target.addDynamicallyLegalOp<FuncOp>([&](FuncOp funcOp) {
+ return converter.isSignatureLegal(funcOp.getType());
----------------
Similar to the above, but I might understand that we want this pass to fail if there remains any function on tensors (maybe it doesn't use linalg at all...)
================
Comment at: mlir/test/Dialect/Linalg/tensors-to-buffers.mlir:15
+// CHECK: (%[[NEW_ARG0:.*]]: [[TYPE:.*]], %[[ARG1_RESULT:.*]]: [[TYPE]], %[[ARG2_RESULT:.*]]: [[TYPE]])
+// CHECK-NEXT: %[[FIRST_ALLOC:.*]] = alloc() : [[TYPE]]
+// CHECK-NEXT: %[[SECOND_ALLOC:.*]] = alloc() : [[TYPE]]
----------------
Do we actually care about lines being strictly consecutive, or just them being ordered suffices? If the latter, drop the `-NEXT`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D78996/new/
https://reviews.llvm.org/D78996
More information about the llvm-commits
mailing list