This is an archive of the discontinued LLVM Phabricator instance.

[mlir][complex] Canonicalize complex.mul with 1 and 0
ClosedPublic

Authored by Lewuathe on Jun 22 2023, 8:43 PM.

Details

Summary

We can fold the complex.mul if the right value is obvious 1 or 0.

Diff Detail

Event Timeline

Lewuathe created this revision.Jun 22 2023, 8:43 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 22 2023, 8:43 PM
Lewuathe requested review of this revision.Jun 22 2023, 8:43 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 22 2023, 8:43 PM

Does complex allow for special fp values like NaN, +/- Inf, or -0? I remember this being the case for complex in C. If yes, is the '* 0' fold valid when the non-constant values are NaN/Inf/-0/etc.?

mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
256
257–259

nit: I would prefer to see the exact types spelled out here, it's not immediately obvious what each .getValue(); returns.

As @kuhar mentioned, multiplying by zero isn't necessarily zero, unless the appropriate fastmath flags are set. (LLVM won't simplify multiplication scalar values by zero unless the nnan and nsz flags are set.)

I would think the "right" thing to do here is add fastmath flags to the complex dialect operations and make the fold conditional.

@kuhar @jfurtek Thank you for the comment. I found a related discussion here for the arithmetic dialect. (you are already leading the one, @jfurtek)

https://discourse.llvm.org/t/rfc-fastmath-flags-support-in-mlir-arith-dialect/6049

I think we can add similar flag as the arith dialect right?

IIRC mul_one case should not be affected by the fast math flag this time. Can I separate mul_zero from the patch so that we can work on after supporting fast math flag?

kuhar added a comment.Jun 24 2023, 9:19 AM

@kuhar @jfurtek Thank you for the comment. I found a related discussion here for the arithmetic dialect. (you are already leading the one, @jfurtek)

IIRC mul_one case should not be affected by the fast math flag this time. Can I separate mul_zero from the patch so that we can work on after supporting fast math flag?

Limiting the scope SGTM. We should make sure to add test cases with those special fp values to show that these folds handle them as intended, provided they won't be matched against directly in the fold.

Lewuathe updated this revision to Diff 534435.Jun 25 2023, 11:53 PM

Add test cases for multiple floating point precisions.

kuhar added inline comments.Jun 26 2023, 10:37 AM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
261–262

nit: we don't need llvm:: with casts, I believe it started appearing in the code base because it was easier to migrate from member casts this way

264–265

Consider adding an early exit if (real != APFloat(...)) return {}; to simplify the switch below

Lewuathe updated this revision to Diff 534779.Jun 26 2023, 4:16 PM

Post review follow-up

Lewuathe marked 4 inline comments as done.Jun 26 2023, 4:17 PM
kuhar added inline comments.Jun 26 2023, 5:13 PM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
257–259

The type of arrayAttr is not obvious to me based on the RHS. Could we spell it out instead of using auto?

264–265

Not done

Lewuathe added inline comments.Jun 26 2023, 7:15 PM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

@kuhar Sorry, I might have missed what you meant. Which part should we do early exit for this case?

To do if (real != APFloat(...)) type of check, we need to check the size in bits first (64 bit real will always fail to check real != APFloat(1.0f) but it should be caught in the case of 32 bit. )

kuhar added inline comments.Jun 26 2023, 11:26 PM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

I was thinking of something like:

if (!imag.isZero()) return {};
if (real != APFloat(1.0)) return {};

if (!llvm::is_contained({32, 64}, real.getSizeInBits(real.getSemantics())) return {};

return getLhs();
kuhar added inline comments.Jun 26 2023, 11:31 PM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

Gah, I'm sorry, I missed the 1.0 vs. 1.0f distinction.

In this case I think we can use the m_OneFloat matcher: https://mlir.llvm.org/doxygen/namespacemlir.html#af0495d84f34cf3238a7741fa6974a485

Lewuathe added inline comments.Jun 27 2023, 12:36 AM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

Thank you. Let me try!

Lewuathe added inline comments.Jun 27 2023, 11:50 PM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

Apparently, m_OneFloat (or any other matcher) does not work with APFloat derived from the attribute. It's only working with the value type.

https://discord.com/channels/636084430946959380/642426447167881246/1123498353129426994

Lewuathe updated this revision to Diff 535254.Jun 28 2023, 12:03 AM

Early exit for non-zero imaginary part.

Lewuathe marked 3 inline comments as done and an inline comment as not done.Jun 28 2023, 12:03 AM
Lewuathe marked an inline comment as done.
Lewuathe added inline comments.
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

I changed to exit earlier in the case of non-zero imaginary part instead.

kuhar added inline comments.Jun 28 2023, 12:10 AM
mlir/lib/Dialect/Complex/IR/ComplexOps.cpp
264–265

In this case, should we use the same implementation as they do to support any bitwidth?

inline detail::constant_float_predicate_matcher m_OneFloat() {
  return {[](const APFloat &value) {
    return APFloat(value.getSemantics(), 1) == value;
  }};
}
Lewuathe updated this revision to Diff 535258.Jun 28 2023, 12:15 AM

Support any bitwidth (f16, f80 and f128)

kuhar accepted this revision.Jun 28 2023, 12:19 AM

LGTM, thanks for the fixes!

This revision is now accepted and ready to land.Jun 28 2023, 12:19 AM
Lewuathe marked an inline comment as done.Jun 28 2023, 12:20 AM
This revision was automatically updated to reflect the committed changes.