[RFC] Integer overflow flags support in `arith` dialect

I would like to add nsw/nuw (NoSisgnedWrap/NoUnsignedWrap) flags to some arith ops.

Motivation

Common backends (LLVM, SPIR-V) have wrap/overflow flags support but middle-level arith dialect doesn’t, which makes it difficult to plumb this info from high-level language sematics.
Also, those flags are useful to do optimizations on arith dialect level.
One immediate candidate is relaxing Integer Range Analysis with presence of such flags llvm-project/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp at 5930725c891b60f5fb94058c6c08a55a2e03d83e · llvm/llvm-project · GitHub

Implementation details

Initially, I will update the following ops:

  • arith.addi
  • arith.subi
  • arith.muli

Later, we may think in extending it to other ops or dialects (e.g. index)

I will add IntegerOverflowFlags bitenum and attr to arith dialect, which will be carbon copy of exisitng LLVM dialect IntegerOverflowFlags enum. Default sematics will remain the same (wraparound).
We can potentially reuse same enum and attr between dialects, but I don’t want to add dependency between arith and LLVM (float fastmath flags are implemented in the same way).

Existing canonicalizations/transformations which are not aware of those flags may drop those flags arbitrarily. We will update them gradually as needed, as dropping these flags will only lead to missing optimizations and not to correctness issues.

Lowering

For LLVM those flags will be directly lowered to nsw/nuw flags
For SPIR-V they will be lowered to NoSignedWrap/NoUnsignedWrap op decorations.

If some backend doesn’t support such flags it can safely ignore them and assume default (wraparound) sematics.

7 Likes

Thanks for writing this up @Hardcode84, the proposal makes sense to me.

Should we also allow these on vector/gpu reduction ops, like we do with fast math flags? In the SPIR-V lowering path, we would need these to avoid UB when emitting some integer dot product ops like spirv.SDotAccSat.

This makes sense, but:

  • I would prefer to keep initial PR small, so it should be done in follow up PRs
  • We will end up with reduction ops having both float fastmath and integer overflow flags, should we split them into separate int/float versions?

Yeah making this incremental makes sense for me but I would like to make sure we can get to the full solution eventually. As for reduction ops and flags, I wouldn’t mind having different enum values for int/float reductions so that they map 1:1 to arith ops – I think it’ll be just a bit more code but simpler logic (no need to branch on the value type) and easier to look up the semantics. But that’s probably a separate discussion.

Sorry, I wasn’t clear, reduce ops like vector.reduction support both int and float types, so they will have both sets of flags attached as 2 different args. Is this ok, or do we want to split reduction ops into separate int/float versions?

I’d think we allow both attributes (fast math and overflow, as defined in arith) in the assembly format and then add check in the verifier that the op doesn’t mix fp/int types with int/fp attributes.

1 Like

Hi, @Hardcode84, you can look at my half-baked implementation here: yi-wu-arm/llvm-project at yi_dev_NSW_NUW_arith_dialect (github.com). I got quite lost when check flags for canonicalization. I don’t think that I will complete it, so feel free to go.

1 Like

Here is initial PR [mlir][arith] Add overflow flags support to arith ops by Hardcode84 · Pull Request #77211 · llvm/llvm-project · GitHub

I took some code from your impl, but made canonicalizations to just drop flags. It’s quite annoying to deal with tablegen rewrites and I’ll update them in separate PR.

Also, had to include LLVM translation code in this PR, as existing patterns will crash when unexpected attributes are encountered.

Just a suggestion for the overall execution strategy: could you start a tracking issue on github with all the planned integer overflow tasks? This should be a lightweight mechanism to track the progress and keep track of all the related PRs

That makes sense, but I don’t have very detailed plan at the moment besides

  • Add flags
  • llvm lowering
  • spir-v lowering
  • canonicalizations
  • integer range analysis

I’d put exactly this as a tasklist in an issue :slight_smile:

1 Like

I will merge initial PR tomorrow

Merged, I’ll work on basic SPIR-V lowering next. If anyone wants to work on anything else from the list, ping this thread or github issue

SPIR-V conversion

Ok, first patch broke python bindings in a bad way (see comment [mlir][arith] Add overflow flags support to arith ops by Hardcode84 · Pull Request #77211 · llvm/llvm-project · GitHub). I will revert both and reland them soon, I hope.

relanded [mlir][arith] Add overflow flags support to arith ops by jpienaar · Pull Request #78376 · llvm/llvm-project · GitHub, thanks @jpienaar

I think we can support the integer overflow flags for complex dialect as we do (still on-doing) to support the fastmath flag in converting to arith and LLVM dialect. It allows us to keep the overflow flags semantics from the complex dialect to the lower dialect in the same manner. What do you think about it? If it makes sense, I’ll try to work on that.

2 Likes

Yeah, that’s makes sense, thanks.

Hello.
I’d like to ask you a question.

  • Add flags
  • llvm lowering
  • spir-v lowering
  • canonicalizations
  • integer range analysis

There is a task for canonicalization in the above list. Does it include not only fixing missing flags in canonicalization but also adding more flags to operations?
I’m working on Flang and it’s found that some nsw flags on arith.addi can help optimization. I’m roughly thinking of implementing the feature adding nsw flags in canonicalizer, but I’m not sure this conforms to the design of arith dialect considering the following discussion.