This is an archive of the discontinued LLVM Phabricator instance.

[mlir][Linalg] Add ReduceOp to Linalg structured ops.
ClosedPublic

Authored by akuegel on Sep 27 2022, 5:11 AM.

Details

Summary

This will allow to model (variadic) reductions with this special op instead of
using GenericOp.

RFC: https://discourse.llvm.org/t/rfc-primitive-ops-add-mapop-reductionop-transposeop-broadcastop-to-linalg/64184

Diff Detail

Event Timeline

akuegel created this revision.Sep 27 2022, 5:11 AM
akuegel requested review of this revision.Sep 27 2022, 5:11 AM

Thanks @akuegel for pushing in this direction!

I added a first round of comments.

Upon deeper inspection, I find that none of the tests exercise mixing ? and shape, I'd drop it from this PR for now and we can introduce later if needed (I suspect this would trigger discussions).

mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
266

getIteratorTypes ?

270

getOutputs?

mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
1190

getIteratorTypes?

1208

I'd just start from getMultiDimIdentityMap and apply AffineMap dropResult(unsigned pos) for all getDimensions.

Bonus points: impl AffineMap dropResults(ArrayRef<unsigned> pos)

1245

do we want to just ignore stuff that is not what we expect ?

1306

you seem to want to allow the mixing .. plz see my message below.

1314

This allows mixing static and dynamic shapes, are you sure this is what you want?

If so, this needs to be well-documented in the op semantics.
It will be surprising if someone mixes 4 and ? and at runtime ? != 4 => this should be clearly spelled out as UB.

If this is not the behavior you want, just do a.getShape() == b.getShape() ?

Looking back at the RFC, we didn't discuss allowing implicit conversions to/from ?, could you comment on the tradeoffs?

1323

same comment

1337

can we use some Tablegen "confined" spec here and avoid reinventing?

1342

feels like a generally useful Tablegen-level property to add (can be left for later).

1375
if (getBody()->getNumArguments() != this->getNumOperands())
  return emitOpError() << "mismatching number of operands and block arguments";
1384
// Note: zip iterates until the min length.
for (auto [input, bbArg] :: llvm::zip(getInputs(), block->getArguments())) {
  if (input.getType().cast<ShapedType>().getElementType() != bbArg.getType())
    return ...
}
1398

Same

for (auto [..., bbArg]
pifon2a added inline comments.Sep 27 2022, 6:42 AM
mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
1314

That's because we never discussed variadic reductions in the RFC. HLO allows having just "compatible" shapes among inputs and among outputs, but it is definitely not clear if it's needed.

akuegel updated this revision to Diff 463503.Sep 28 2022, 4:50 AM
akuegel marked 8 inline comments as done.

Address review comments.

akuegel added inline comments.Sep 28 2022, 4:50 AM
mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
270

Done, but this requires changing the DestinationStyleOpInterface. Please let me know whether I should move that change to a separate patch. Changing the name of this interface method would also require updates to users outside MLIR, e.g. tHLO in Tensorflow.

mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
1208

I have added a dropResults method, however to make it easily usable for my case, I needed to use ArrayRef<int64_t>. To make both methods consistent, I also changed dropResult() to take int64_t. But maybe unsigned types are preferred here, and I should instead cast my int64_t ArrayRef?

1245

Good point, I guess it makes sense to return a failure. Done.

1306

Yes, not really necessary. I have removed this method.

1314

Lets get rid of this. I think we don't need to allow mismatch of dynamic and static dimensions.

1337

I guess you mean specifying dimensions as a ConfinedAttr?

I tried the following:

class IndexInBounds<int upperBound>
    : AttrConstraint<CPred<"llvm::all_of($_self.cast<::mlir::DenseI64ArrayAttr>"
                           "().asArrayRef(), [](int64_t dim) { return dim >= 0 "
                           "&& dim < " # upperBound # "; })">,
                     "should be in the range [0, " # upperBound # "]">;

ConfinedAttr<DenseI64ArrayAttr, [IndexInBounds<2>]>:$dimensions

But in fact I cannot use a constant upper bound. How can I pass a dynamic upper bound (the input rank) to IndexInBounds? Is it even possible? And if it is not possible, should I just verify that each value is >= 0 and keep the other verification code inside the verify method?

1342

So here I can see how it can be done as AttrConstraint. If I understand correctly, you would prefer if such a constraint is available for reuse. Where would be a good place for it in the code base?

akuegel added inline comments.Sep 29 2022, 5:21 AM
mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
270
nicolasvasilache accepted this revision.Sep 29 2022, 5:33 AM
nicolasvasilache added a subscriber: Mogball.

Nice!

Minor comments (and maybe a bug)

mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
270

thanks for putting this in a separate patch!

mlir/include/mlir/IR/AffineMap.h
254

++

mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
1208

Generally we should avoid unsigned as much as possible (see e.g. https://www.youtube.com/watch?v=Puio5dly9N8), there are a bunch of older APIs based on unsigned that will need to be cleaned up but avoiding to propagate that mistake is better, this is great as is.

1337

Had the same issue in https://reviews.llvm.org/D130348 actually..

At the time, @Mogball wrote: This can be achieved with a derived attribute that uses the value of an optional attribute or some derived value
I wasn't able to immediately turn that into something actionnable; if you see a way to please go ahead otherwise it's fine with me to leave as a future cleanup.

1342

I would think something in OpBase.td would make sense to implement the "sorted" constraint.

1377

wrong input/output mixing and you are getting lucky with the current tests :) ?

This revision is now accepted and ready to land.Sep 29 2022, 5:33 AM
akuegel updated this revision to Diff 463874.Sep 29 2022, 6:39 AM
akuegel marked 3 inline comments as done.

Fix copy/paste bug in verify.

mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
1337

I also don't understand what is meant with derived attribute.
So I will leave this as a future cleanup.

1342

Ok, I will prepare a separate patch for that.

1377

Good catch! I have adjusted the test for mismatched outputs a bit so that it would catch this bug.

akuegel closed this revision.Sep 30 2022, 1:02 AM