Make snegate / unegate overflow handling consistent with other builtins. (#4744)

Make `int.snegate` ignore the signedness of its operand and
unconditionally check for signed overflow like all the other `int.s*`
builtins do. Fix the prelude implementation of unary `-` for `Core.UInt`
to use `int.unegate` instead of `int.snegate`.

Fix the test for unsigned negate to actually test negating unsigned
integers, and add some tests that unary `-` also works.
This commit is contained in:
Richard Smith
2024-12-26 22:07:47 +00:00
committed by GitHub
parent 724fc7623e
commit 7d8d59cb7e
4 changed files with 469 additions and 276 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ impl forall [N:! IntLiteral()] UInt(N) as Mul {
}
impl forall [N:! IntLiteral()] UInt(N) as Negate {
fn Op[self: Self]() -> Self = "int.snegate";
fn Op[self: Self]() -> Self = "int.unegate";
}
impl forall [N:! IntLiteral()] UInt(N) as Sub {
+1 -1
View File
@@ -783,7 +783,7 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
switch (builtin_kind) {
case SemIR::BuiltinFunctionKind::IntSNegate:
if (is_signed && op_val.isMinSignedValue()) {
if (op_val.isMinSignedValue()) {
CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error,
"integer overflow in negation of {0}", TypedInt);
context.emitter().Emit(loc, CompileTimeIntegerNegateOverflow,
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -93,8 +93,8 @@ fn div_u16(a: u16, b: u16) -> u16 { return a / b; }
// CHECK:STDOUT:
// CHECK:STDOUT: define i32 @_Cneg_u32.Main(i32 %a) !dbg !33 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %int.snegate = sub i32 0, %a, !dbg !34
// CHECK:STDOUT: ret i32 %int.snegate, !dbg !35
// CHECK:STDOUT: %int.unegate = sub i32 0, %a, !dbg !34
// CHECK:STDOUT: ret i32 %int.unegate, !dbg !35
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define i32 @_Csub_i32.Main(i32 %a, i32 %b) !dbg !36 {