llvm / clangir

A new (MLIR based) high-level IR for clang.
https://clangir.org
Other
343 stars 89 forks source link

[CIR][CodeGen][Lowering] Support Integer overflow with fwrap #539

Closed gitoleg closed 5 months ago

gitoleg commented 5 months ago

This PR fixes some cases when a program compiled with -fwrapv fails with NYI . Basically, the default behavior is no overlap:

void baz(int x, int y) {
  int z = x - y;
}

LLVM IR (no CIR enabled):

%sub = sub nsw i32 %0, %1

and with -fwrapv :

%sub = sub i32 %0, %1

We need something similar in CIR. The only way I see how to implement it is to add a couple of attributes to the BinOp to make things even with the llvm dialect.

Well, are there any other ideas?

Lancern commented 5 months ago

Since nsw and nuw only applies to integral operands, what about inventing a new operation specifically for wrapped integral arithmetic? Something like cir.binop.wrapped.

gitoleg commented 5 months ago

@Lancern

Since nsw and nuw only applies to integral operands, what about inventing a new operation specifically for wrapped integral arithmetic? Something like cir.binop.wrapped.

well, maybe .. but I would not introduce new operations for math arithmetic, at least now, if there is a chance to do the same with the existing ones.

@bcardosolopes I didn't have a chance to check carefully, but as far I understand unsigned wrap is a standard behavior in C, and only in the rare case we need to emphasize there is no wrap with nuw. So from my point of view (at least now) it's may be wrong way to infer "nuw" or "nsw" from integer type. Or even more! I took a look at original codegen tests, and it could be both nuw nsw set simultaneously!

bcardosolopes commented 5 months ago

Mistake from my review: my intention was to suggest nowrap, not wrap. Thanks for the feedback @gitoleg

well, maybe .. but I would not introduce new operations for math arithmetic, at least now, if there is a chance to do the same with the existing ones.

+1

I didn't have a chance to check carefully, but as far I understand unsigned wrap is a standard behavior in C, and only in the rare case we need to emphasize there is no wrap with nuw. So from my point of view (at least now) it's may be wrong way to infer "nuw" or "nsw" from integer type. Or even more! I took a look at original codegen tests, and it could be both nuw nsw set simultaneously!

We need testcases that cover that too.

By looking at the PR, seems like this is a TU level configuration, and emitting these flags is dependent on:

So here's one idea, perhaps we should encode that at the module level (like we for fp behavior) and LLVM lowering could then look at these module properties to pick how it should lower BinOps. How does that sound? For this to work, I'm assuming that all of these binops on both signed and unsigned in a TU will have to follow the rules, do you know if that applies?

bcardosolopes commented 5 months ago

In fact we already have those global definitions, see SignedOverflowBehaviorAttr.

gitoleg commented 5 months ago

@bcardosolopes So far I can't prove to myself that we can solve it on the module level, since there are both NUW and NSW arithmetic instructions emitted in the original codegen even without language options checked. So I'm afraid we have to do it for operations :(

We need testcases that cover that too.

Just if you are curious about, how it's possible:

unsigned test(unsigned x, unsigned y) {
  return x << y;
}

compiled with -fsanitize=unsigned-shift-base So I think we need to support this sanitizer first.


NUW - no unsigned wrap NSW - no signed wrap

gitoleg commented 5 months ago

@bcardosolopes

Now the question is - do you want me to do the same for ShiftOp (for the left one) in this PR? OR we just postpone it until we will need it? I just noticed shifts are not BinOp in cir.

bcardosolopes commented 5 months ago

Now the question is - do you want me to do the same for ShiftOp (for the left one) in this PR? OR we just postpone it until we will need it? I just noticed shifts are not BinOp in cir.

It'd be great if you can already fix the shift, so we don't need to revisit this - feel free to do it in another PR though, this one does good incremental work.

gitoleg commented 5 months ago

@bcardosolopes done!