Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Mostly LGTM. Also I have a question about how best to handle patterns for named linalg ops going forward.
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | Can we forward the new pack op destination to the fill op if the result is a tensor.empty (same as we're doing for generic elementwise in D149250)? This should be fine because the padding value and fill value are the same. | |
492 | Once padding is supported (with some toggle option) in propagation through generics, would it be better to let the linalg.fill building happen via a callback specified in BubbleUpPackOpThroughFillOpPattern? Then we can reuse the pattern for generic ops for any linalg op which could help consolidate code at the expense of extra analysis in certain cases like this. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
481 | nit, I would write: SmallVector<Value> operands = {fillOp.getDpsInitOperand(0)->get(), packOpDest}; | |
486 | nit: operands.append(packOp.getInnerTiles().begin(), packOp.getInnerTiles().end()); | |
mlir/test/Dialect/Linalg/data-layout-propagation.mlir | ||
836 | Do we plan to fold the pack into the fill op in another PR? I would avoid the packing and make the fill operation work directly on the packed layout. Do you have some use cases where you want to preserve the packing? If so, we could do this folding in populateSimplifyTensorPack. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | I think we can drop the pack op directly after I read chelini's comment. I can't think a case that we'd like to preserve the new pack op because it's only used by the new fill op. What do you think? | |
492 | Propagation with padding value is tricky, esp. for generic ops. The fill op case is fairly simple, so I'd like to scope it to the pattern at this moment. | |
mlir/test/Dialect/Linalg/data-layout-propagation.mlir | ||
836 | Sounds really good to me, maybe we can do it in this PR.. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | That's probably fine too, although I think they work out to be essentially the same thing whenever the fill is on an empty tensor (with an extra floating pack that can get DCE'd). Correct me if I'm wrong about that though. My only concern was if the fill op destination was a non-empty tensor for whatever reason and we would then want to maintain the use-def chain similar to bubbling up through pure elementwise (as noted in D149250, given that fill is just a specific kind of pure elementwise). The difference is that filling a tensor is only sensible on an empty tensor then? Basically I don't see why a named op gets to be propagated differently than an equivalent generic (without padding). At a minimum I would expect us to be using the LinalgFillOpInterface for this then. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 |
It looks fine to me because all the things in tensors world are destructive. Filling on whatever tensors (maybe except bufferization.alloc_tensor op) should create a new tensor with filled value. The pass is intended to be applied at tensor graph level, which is at a higher level than bufferization. So I think it is fine. The generic op version of the fill op is very rare to me.. I agree that it could be a case, but we don't have to expose it at this moment. I have an idea for supporting padding cases in limit cases, and it could cover the case.
I was not aware of the interface. I studied it, and found that we can't use it here. The property is having a scalar value operand and one output operand. The computation body can be different, e.g., we could define FillExpOp using the interface which fills the arith.exp(scalar) into the output operand. In the context, we'll need different check between padding value and filled value. This interface is only used by linalg.fill op now, I think we can scope it to linalg.fill at this moment. If we really have other needs, it should be easy to extend. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | I'm open to keep the pack chain; fold them away only if the dest tensor is a tensor.empty op. There could be other use cases that I haven't seen before. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | I see, this is fine then and I didn't intend to block. I just figured named linalg ops should try to be as close as possible to the generic patterns (the only difference being the pack chain in this case), but agreed that it would be strange usage of a fill op that I haven't seen either. I can go either way on keeping the pack chain because the pattern looks cleaner without it. Thanks for the discussion! |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | I'm happy that we have the nice discussion! (I planned to wait for a day just in case if others would like to review it. No worry at all!) |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 |
Thanks for all these discussions! In D149250, I attempted to avoid packing an 'init' operand if the 'init' is already a tensor.empty. In this case, empty carries only the shape; we can update it with the packed version. I start wondering if the into keyword in tensor.pack is confusing. Internally there was some discussion about it because people think we are writing into the destination tensor. Let's discuss this offline in a call! | |
mlir/test/Dialect/Linalg/data-layout-propagation.mlir | ||
836 | Why do we want to pass %dest as arg for the fill, seems a bit wired a tensor level. I would create a tensor.empty inside the func. | |
852 | same here. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 |
Agreed, that has confused me as well; also happy to discuss in a call! |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
491–492 | agree, into is a confusing term. We can maybe use ins and outs because it's intended to capture the shape information. happy to discuss it! | |
mlir/test/Dialect/Linalg/data-layout-propagation.mlir | ||
836 | It is not a big concern to me because sometimes a function can be inlined into a program. My intention was to create a minimal test for the pass. We can do this for static cases, but not dynamic shapes. We'll have to tie the dim sizes to something. Passing it as an argument is simplest way I've found. Let's do it for static shapes, and leave the dynamic case as what it is.. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
453 | I had the impression that @qcolombet had written something like this ~1 month ago ? Signaling in case there is a dedup that needs to happen here. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
453 | We definitely talked about it, but no I didn't land anything on that. |
mlir/lib/Dialect/Linalg/Transforms/DataLayoutPropagation.cpp | ||
---|---|---|
453 | I think what you have in mind @nicolasvasilache is pad + fill: https://github.com/openxla/iree/blob/ef2bb52317eed3b90618a6c16616ae14e33b7803/compiler/src/iree/compiler/Codegen/Common/TransformExtensions/CommonExtensions.cpp#L254 |
I had the impression that @qcolombet had written something like this ~1 month ago ?
Signaling in case there is a dedup that needs to happen here.