diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 64c7376903f4..eb5e93a8f6b2 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -381,7 +381,7 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc, auto op_val = context.ints().Get(op.int_id); switch (builtin_kind) { - case SemIR::BuiltinFunctionKind::IntNegate: + case SemIR::BuiltinFunctionKind::IntSNegate: if (context.types().IsSignedInt(op.type_id) && op_val.isMinSignedValue()) { CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error, @@ -391,6 +391,9 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc, } op_val.negate(); break; + case SemIR::BuiltinFunctionKind::IntUNegate: + op_val.negate(); + break; case SemIR::BuiltinFunctionKind::IntComplement: op_val.flipAllBits(); break; @@ -412,45 +415,67 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc, const auto& lhs_val = context.ints().Get(lhs.int_id); const auto& rhs_val = context.ints().Get(rhs.int_id); - bool is_signed = context.types().IsSignedInt(lhs.type_id); + // Check for division by zero. + switch (builtin_kind) { + case SemIR::BuiltinFunctionKind::IntSDiv: + case SemIR::BuiltinFunctionKind::IntSMod: + case SemIR::BuiltinFunctionKind::IntUDiv: + case SemIR::BuiltinFunctionKind::IntUMod: + if (rhs_val.isZero()) { + DiagnoseDivisionByZero(context, loc); + return SemIR::ConstantId::Error; + } + break; + default: + break; + } + bool overflow = false; llvm::APInt result_val; llvm::StringLiteral op_str = ""; switch (builtin_kind) { // Arithmetic. - case SemIR::BuiltinFunctionKind::IntAdd: - result_val = - is_signed ? lhs_val.sadd_ov(rhs_val, overflow) : lhs_val + rhs_val; + case SemIR::BuiltinFunctionKind::IntSAdd: + result_val = lhs_val.sadd_ov(rhs_val, overflow); op_str = "+"; break; - case SemIR::BuiltinFunctionKind::IntSub: - result_val = - is_signed ? lhs_val.ssub_ov(rhs_val, overflow) : lhs_val - rhs_val; + case SemIR::BuiltinFunctionKind::IntSSub: + result_val = lhs_val.ssub_ov(rhs_val, overflow); op_str = "-"; break; - case SemIR::BuiltinFunctionKind::IntMul: - result_val = - is_signed ? lhs_val.smul_ov(rhs_val, overflow) : lhs_val * rhs_val; + case SemIR::BuiltinFunctionKind::IntSMul: + result_val = lhs_val.smul_ov(rhs_val, overflow); op_str = "*"; break; - case SemIR::BuiltinFunctionKind::IntDiv: - if (rhs_val.isZero()) { - DiagnoseDivisionByZero(context, loc); - return SemIR::ConstantId::Error; - } - result_val = is_signed ? lhs_val.sdiv_ov(rhs_val, overflow) - : lhs_val.udiv(rhs_val); + case SemIR::BuiltinFunctionKind::IntSDiv: + result_val = lhs_val.sdiv_ov(rhs_val, overflow); op_str = "/"; break; - case SemIR::BuiltinFunctionKind::IntMod: - if (rhs_val.isZero()) { - DiagnoseDivisionByZero(context, loc); - return SemIR::ConstantId::Error; - } - result_val = is_signed ? lhs_val.srem(rhs_val) : lhs_val.urem(rhs_val); + case SemIR::BuiltinFunctionKind::IntSMod: + result_val = lhs_val.srem(rhs_val); // LLVM weirdly lacks `srem_ov`, so we work it out for ourselves: // % -1 overflows because / -1 overflows. - overflow = is_signed && lhs_val.isMinSignedValue() && rhs_val.isAllOnes(); + overflow = lhs_val.isMinSignedValue() && rhs_val.isAllOnes(); + op_str = "%"; + break; + case SemIR::BuiltinFunctionKind::IntUAdd: + result_val = lhs_val + rhs_val; + op_str = "+"; + break; + case SemIR::BuiltinFunctionKind::IntUSub: + result_val = lhs_val - rhs_val; + op_str = "-"; + break; + case SemIR::BuiltinFunctionKind::IntUMul: + result_val = lhs_val * rhs_val; + op_str = "*"; + break; + case SemIR::BuiltinFunctionKind::IntUDiv: + result_val = lhs_val.udiv(rhs_val); + op_str = "/"; + break; + case SemIR::BuiltinFunctionKind::IntUMod: + result_val = lhs_val.urem(rhs_val); op_str = "%"; break; @@ -490,7 +515,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc, if (builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift) { result_val = lhs_val.shl(rhs_val); - } else if (is_signed) { + } else if (context.types().IsSignedInt(lhs.type_id)) { result_val = lhs_val.ashr(rhs_val); } else { result_val = lhs_val.lshr(rhs_val); @@ -591,7 +616,8 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, } // Unary integer -> integer operations. - case SemIR::BuiltinFunctionKind::IntNegate: + case SemIR::BuiltinFunctionKind::IntSNegate: + case SemIR::BuiltinFunctionKind::IntUNegate: case SemIR::BuiltinFunctionKind::IntComplement: { if (phase != Phase::Template) { break; @@ -600,11 +626,16 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, } // Binary integer -> integer operations. - case SemIR::BuiltinFunctionKind::IntAdd: - case SemIR::BuiltinFunctionKind::IntSub: - case SemIR::BuiltinFunctionKind::IntMul: - case SemIR::BuiltinFunctionKind::IntDiv: - case SemIR::BuiltinFunctionKind::IntMod: + case SemIR::BuiltinFunctionKind::IntSAdd: + case SemIR::BuiltinFunctionKind::IntSSub: + case SemIR::BuiltinFunctionKind::IntSMul: + case SemIR::BuiltinFunctionKind::IntSDiv: + case SemIR::BuiltinFunctionKind::IntSMod: + case SemIR::BuiltinFunctionKind::IntUAdd: + case SemIR::BuiltinFunctionKind::IntUSub: + case SemIR::BuiltinFunctionKind::IntUMul: + case SemIR::BuiltinFunctionKind::IntUDiv: + case SemIR::BuiltinFunctionKind::IntUMod: case SemIR::BuiltinFunctionKind::IntAnd: case SemIR::BuiltinFunctionKind::IntOr: case SemIR::BuiltinFunctionKind::IntXor: diff --git a/toolchain/check/testdata/array/canonicalize_index.carbon b/toolchain/check/testdata/array/canonicalize_index.carbon index b7fd05516487..e734160a4b7c 100644 --- a/toolchain/check/testdata/array/canonicalize_index.carbon +++ b/toolchain/check/testdata/array/canonicalize_index.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; var a: [i32; Add(1, 2)] = (1, 2, 3); let b: [i32; 3]* = &a; @@ -51,7 +51,7 @@ let b: [i32; 3]* = &a; // CHECK:STDOUT: %b.loc10: [i32; 3]* = bind_name b, %.loc10_20 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/array/fail_bound_negative.carbon b/toolchain/check/testdata/array/fail_bound_negative.carbon index 8aaedfa96abb..603a997dbea3 100644 --- a/toolchain/check/testdata/array/fail_bound_negative.carbon +++ b/toolchain/check/testdata/array/fail_bound_negative.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -fn Negate(n: i32) -> i32 = "int.negate"; +fn Negate(n: i32) -> i32 = "int.snegate"; // CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+3]]:14: ERROR: Array bound of -1 is negative. // CHECK:STDERR: var a: [i32; Negate(1)]; @@ -38,5 +38,5 @@ var a: [i32; Negate(1)]; // CHECK:STDOUT: %a: ref = bind_name a, %a.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/greater.carbon b/toolchain/check/testdata/builtins/int/greater.carbon index 32fc13f2f879..39a1bbc5c114 100644 --- a/toolchain/check/testdata/builtins/int/greater.carbon +++ b/toolchain/check/testdata/builtins/int/greater.carbon @@ -7,7 +7,7 @@ // --- int_greater.carbon fn Greater(a: i32, b: i32) -> bool = "int.greater"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; class True {} class False {} @@ -94,7 +94,7 @@ fn RuntimeCall(a: i32, b: i32) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @Greater(%a: i32, %b: i32) -> bool = "int.greater"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%true_: True, %false_: False) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/builtins/int/greater_eq.carbon b/toolchain/check/testdata/builtins/int/greater_eq.carbon index bdb486757c54..2f1edc2a691f 100644 --- a/toolchain/check/testdata/builtins/int/greater_eq.carbon +++ b/toolchain/check/testdata/builtins/int/greater_eq.carbon @@ -7,7 +7,7 @@ // --- int_greater_eq.carbon fn GreaterEq(a: i32, b: i32) -> bool = "int.greater_eq"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; class True {} class False {} @@ -94,7 +94,7 @@ fn RuntimeCall(a: i32, b: i32) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @GreaterEq(%a: i32, %b: i32) -> bool = "int.greater_eq"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%true_: True, %false_: False) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/builtins/int/left_shift.carbon b/toolchain/check/testdata/builtins/int/left_shift.carbon index 06ac1f0f032e..716a6e9eadb6 100644 --- a/toolchain/check/testdata/builtins/int/left_shift.carbon +++ b/toolchain/check/testdata/builtins/int/left_shift.carbon @@ -22,7 +22,7 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package BadShift api; fn LeftShift(a: i32, b: i32) -> i32 = "int.left_shift"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; // Shift greater than size is disallowed. let size_1: i32 = LeftShift(1, 31); @@ -215,5 +215,5 @@ let negative: i32 = LeftShift(1, Negate(1)); // CHECK:STDOUT: // CHECK:STDOUT: fn @LeftShift(%a: i32, %b: i32) -> i32 = "int.left_shift"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/less.carbon b/toolchain/check/testdata/builtins/int/less.carbon index 0eb551f7fac6..97c596e1a126 100644 --- a/toolchain/check/testdata/builtins/int/less.carbon +++ b/toolchain/check/testdata/builtins/int/less.carbon @@ -7,7 +7,7 @@ // --- int_less.carbon fn Less(a: i32, b: i32) -> bool = "int.less"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; class True {} class False {} @@ -94,7 +94,7 @@ fn RuntimeCall(a: i32, b: i32) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @Less(%a: i32, %b: i32) -> bool = "int.less"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%true_: True, %false_: False) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/builtins/int/less_eq.carbon b/toolchain/check/testdata/builtins/int/less_eq.carbon index c0a78335b89c..fe4151ae8765 100644 --- a/toolchain/check/testdata/builtins/int/less_eq.carbon +++ b/toolchain/check/testdata/builtins/int/less_eq.carbon @@ -7,7 +7,7 @@ // --- int_less_eq.carbon fn LessEq(a: i32, b: i32) -> bool = "int.less_eq"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; class True {} class False {} @@ -94,7 +94,7 @@ fn RuntimeCall(a: i32, b: i32) -> bool { // CHECK:STDOUT: // CHECK:STDOUT: fn @LessEq(%a: i32, %b: i32) -> bool = "int.less_eq"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @F(%true_: True, %false_: False) { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/builtins/int/make_type_signed.carbon b/toolchain/check/testdata/builtins/int/make_type_signed.carbon index bac143a151ec..294c1b2ba181 100644 --- a/toolchain/check/testdata/builtins/int/make_type_signed.carbon +++ b/toolchain/check/testdata/builtins/int/make_type_signed.carbon @@ -46,7 +46,7 @@ library "fail_negative_size" api; import library "types"; -fn Negate(n: i32) -> i32 = "int.negate"; +fn Negate(n: i32) -> i32 = "int.snegate"; // CHECK:STDERR: fail_negative_size.carbon:[[@LINE+4]]:8: ERROR: Integer type width of -1 is not positive. // CHECK:STDERR: var n: Int(Negate(1)); @@ -230,7 +230,7 @@ var m: Int(1000000000); // CHECK:STDOUT: %n.loc12: ref = bind_name n, %n.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @Int(%n: i32) -> type = "int.make_type_signed"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon b/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon index e0e58e9e80e2..97f4b2b5acce 100644 --- a/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon +++ b/toolchain/check/testdata/builtins/int/make_type_unsigned.carbon @@ -46,7 +46,7 @@ library "fail_negative_size" api; import library "types"; -fn Negate(n: i32) -> i32 = "int.negate"; +fn Negate(n: i32) -> i32 = "int.snegate"; // CHECK:STDERR: fail_negative_size.carbon:[[@LINE+4]]:8: ERROR: Integer type width of -1 is not positive. // CHECK:STDERR: var n: UInt(Negate(1)); @@ -230,7 +230,7 @@ var m: UInt(1000000000); // CHECK:STDOUT: %n.loc12: ref = bind_name n, %n.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @UInt(%n: i32) -> type = "int.make_type_unsigned"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/right_shift.carbon b/toolchain/check/testdata/builtins/int/right_shift.carbon index 1327b03f6c19..3a3dc66cd1da 100644 --- a/toolchain/check/testdata/builtins/int/right_shift.carbon +++ b/toolchain/check/testdata/builtins/int/right_shift.carbon @@ -24,7 +24,7 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package ArithShift api; fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; // -1 >> 1 is -1. var arr1: [i32; Negate(RightShift(Negate(1), 1))]; @@ -39,7 +39,7 @@ let arr2_p: [i32; 3]* = &arr2; package BadShift api; fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; // Shift greater than size is disallowed. let size_1: i32 = RightShift(1, 31); @@ -203,7 +203,7 @@ let negative: i32 = RightShift(1, Negate(1)); // CHECK:STDOUT: // CHECK:STDOUT: fn @RightShift(%a: i32, %b: i32) -> i32 = "int.right_shift"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: --- fail_bad_shift.carbon // CHECK:STDOUT: @@ -271,5 +271,5 @@ let negative: i32 = RightShift(1, Negate(1)); // CHECK:STDOUT: // CHECK:STDOUT: fn @RightShift(%a: i32, %b: i32) -> i32 = "int.right_shift"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/add.carbon b/toolchain/check/testdata/builtins/int/sadd.carbon similarity index 95% rename from toolchain/check/testdata/builtins/int/add.carbon rename to toolchain/check/testdata/builtins/int/sadd.carbon index 446db8b93a76..5971968bfaeb 100644 --- a/toolchain/check/testdata/builtins/int/add.carbon +++ b/toolchain/check/testdata/builtins/int/sadd.carbon @@ -6,7 +6,7 @@ // --- int_add.carbon -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; var arr: [i32; Add(1, 2)]; let arr_p: [i32; 3]* = &arr; @@ -19,22 +19,22 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailBadDecl api; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.add". -// CHECK:STDERR: fn TooFew(a: i32) -> i32 = "int.add"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.sadd". +// CHECK:STDERR: fn TooFew(a: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn TooFew(a: i32) -> i32 = "int.add"; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.add". -// CHECK:STDERR: fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.add"; +fn TooFew(a: i32) -> i32 = "int.sadd"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.sadd". +// CHECK:STDERR: fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.add"; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.add". -// CHECK:STDERR: fn BadReturnType(a: i32, b: i32) -> bool = "int.add"; +fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.sadd"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.sadd". +// CHECK:STDERR: fn BadReturnType(a: i32, b: i32) -> bool = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn BadReturnType(a: i32, b: i32) -> bool = "int.add"; -fn JustRight(a: i32, b: i32) -> i32 = "int.add"; +fn BadReturnType(a: i32, b: i32) -> bool = "int.sadd"; +fn JustRight(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:20: ERROR: Array bound is not a constant. // CHECK:STDERR: var too_few: [i32; TooFew(1)]; @@ -56,7 +56,7 @@ var bad_return_type: [i32; BadReturnType(1, 2)]; // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2, 3)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: Calling function declared here. -// CHECK:STDERR: fn JustRight(a: i32, b: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn JustRight(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2, 3)]; @@ -77,7 +77,7 @@ fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { package FailOverflow api; -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; let a: i32 = Add(0x7FFFFFFF, 0); // CHECK:STDERR: fail_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer overflow in calculation 2147483647 + 1. @@ -132,7 +132,7 @@ let b: i32 = Add(0x7FFFFFFF, 1); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -252,7 +252,7 @@ let b: i32 = Add(0x7FFFFFFF, 1); // CHECK:STDOUT: // CHECK:STDOUT: fn @BadReturnType(%a: i32, %b: i32) -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @JustRight(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @JustRight(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCallTooFew(%a: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -325,5 +325,5 @@ let b: i32 = Add(0x7FFFFFFF, 1); // CHECK:STDOUT: %b.loc10: i32 = bind_name b, %.loc10_32.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/div.carbon b/toolchain/check/testdata/builtins/int/sdiv.carbon similarity index 96% rename from toolchain/check/testdata/builtins/int/div.carbon rename to toolchain/check/testdata/builtins/int/sdiv.carbon index e6148240d34a..8178c5a1bcee 100644 --- a/toolchain/check/testdata/builtins/int/div.carbon +++ b/toolchain/check/testdata/builtins/int/sdiv.carbon @@ -6,7 +6,7 @@ // --- int_div.carbon -fn Div(a: i32, b: i32) -> i32 = "int.div"; +fn Div(a: i32, b: i32) -> i32 = "int.sdiv"; var arr: [i32; Div(3, 2)]; let arr_p: [i32; 1]* = &arr; @@ -19,9 +19,9 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailOverflow api; -fn Div(a: i32, b: i32) -> i32 = "int.div"; -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Div(a: i32, b: i32) -> i32 = "int.sdiv"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; +fn Negate(a: i32) -> i32 = "int.snegate"; // -0x7FFF_FFFF / -1 is OK. let a: i32 = Div(Negate(0x7FFF_FFFF), Negate(1)); @@ -40,7 +40,7 @@ let c: i32 = Div(Sub(Negate(0x7FFF_FFFF), 1), Negate(1)); package FailDivByZero api; -fn Div(a: i32, b: i32) -> i32 = "int.div"; +fn Div(a: i32, b: i32) -> i32 = "int.sdiv"; // CHECK:STDERR: fail_div_by_zero.carbon:[[@LINE+4]]:14: ERROR: Division by zero. // CHECK:STDERR: let a: i32 = Div(1, 0); @@ -100,7 +100,7 @@ let b: i32 = Div(0, 0); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div"; +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.sdiv"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -203,11 +203,11 @@ let b: i32 = Div(0, 0); // CHECK:STDOUT: %c: i32 = bind_name c, %.loc19_57.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div"; +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.sdiv"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub"; +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.ssub"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: --- fail_div_by_zero.carbon // CHECK:STDOUT: @@ -245,5 +245,5 @@ let b: i32 = Div(0, 0); // CHECK:STDOUT: %b.loc15: i32 = bind_name b, %.loc15_23.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div"; +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.sdiv"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/mod.carbon b/toolchain/check/testdata/builtins/int/smod.carbon similarity index 96% rename from toolchain/check/testdata/builtins/int/mod.carbon rename to toolchain/check/testdata/builtins/int/smod.carbon index 55ab57ae1876..a1c47ff64120 100644 --- a/toolchain/check/testdata/builtins/int/mod.carbon +++ b/toolchain/check/testdata/builtins/int/smod.carbon @@ -6,7 +6,7 @@ // --- int_div.carbon -fn Mod(a: i32, b: i32) -> i32 = "int.mod"; +fn Mod(a: i32, b: i32) -> i32 = "int.smod"; var arr: [i32; Mod(5, 3)]; let arr_p: [i32; 2]* = &arr; @@ -19,9 +19,9 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailOverflow api; -fn Mod(a: i32, b: i32) -> i32 = "int.mod"; -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; -fn Negate(a: i32) -> i32 = "int.negate"; +fn Mod(a: i32, b: i32) -> i32 = "int.smod"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; +fn Negate(a: i32) -> i32 = "int.snegate"; // -0x7FFF_FFFF % -1 is OK. let a: i32 = Mod(Negate(0x7FFF_FFFF), Negate(1)); @@ -41,7 +41,7 @@ let c: i32 = Mod(Sub(Negate(0x7FFF_FFFF), 1), Negate(1)); package FailDivByZero api; -fn Mod(a: i32, b: i32) -> i32 = "int.mod"; +fn Mod(a: i32, b: i32) -> i32 = "int.smod"; // Remainder of division by zero is not defined. @@ -103,7 +103,7 @@ let b: i32 = Mod(0, 0); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod"; +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.smod"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -207,11 +207,11 @@ let b: i32 = Mod(0, 0); // CHECK:STDOUT: %c: i32 = bind_name c, %.loc20_57.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod"; +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.smod"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub"; +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.ssub"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: --- fail_div_by_zero.carbon // CHECK:STDOUT: @@ -249,5 +249,5 @@ let b: i32 = Mod(0, 0); // CHECK:STDOUT: %b.loc17: i32 = bind_name b, %.loc17_23.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod"; +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.smod"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/mul.carbon b/toolchain/check/testdata/builtins/int/smul.carbon similarity index 96% rename from toolchain/check/testdata/builtins/int/mul.carbon rename to toolchain/check/testdata/builtins/int/smul.carbon index f3823df761cf..44abafaafba9 100644 --- a/toolchain/check/testdata/builtins/int/mul.carbon +++ b/toolchain/check/testdata/builtins/int/smul.carbon @@ -6,7 +6,7 @@ // --- int_mul.carbon -fn Mul(a: i32, b: i32) -> i32 = "int.mul"; +fn Mul(a: i32, b: i32) -> i32 = "int.smul"; var arr: [i32; Mul(3, 2)]; let arr_p: [i32; 6]* = &arr; @@ -19,7 +19,7 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailOverflow api; -fn Mul(a: i32, b: i32) -> i32 = "int.mul"; +fn Mul(a: i32, b: i32) -> i32 = "int.smul"; let a: i32 = Mul(0x7FFF, 0x10000); // CHECK:STDERR: fail_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer overflow in calculation 32768 * 65536. @@ -74,7 +74,7 @@ let b: i32 = Mul(0x8000, 0x10000); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.mul"; +// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.smul"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -126,5 +126,5 @@ let b: i32 = Mul(0x8000, 0x10000); // CHECK:STDOUT: %b.loc10: i32 = bind_name b, %.loc10_34.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.mul"; +// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.smul"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/negate.carbon b/toolchain/check/testdata/builtins/int/snegate.carbon similarity index 94% rename from toolchain/check/testdata/builtins/int/negate.carbon rename to toolchain/check/testdata/builtins/int/snegate.carbon index eb5ba39a3bd4..1a5d811b299e 100644 --- a/toolchain/check/testdata/builtins/int/negate.carbon +++ b/toolchain/check/testdata/builtins/int/snegate.carbon @@ -6,7 +6,7 @@ // --- int_negate.carbon -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; var arr: [i32; Negate(Negate(123))]; let arr_p: [i32; 123]* = &arr; @@ -21,22 +21,22 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailBadDecl api; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.negate". -// CHECK:STDERR: fn TooFew() -> i32 = "int.negate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.snegate". +// CHECK:STDERR: fn TooFew() -> i32 = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn TooFew() -> i32 = "int.negate"; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.negate". -// CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.negate"; +fn TooFew() -> i32 = "int.snegate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.snegate". +// CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn TooMany(a: i32, b: i32) -> i32 = "int.negate"; -// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.negate". -// CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.negate"; +fn TooMany(a: i32, b: i32) -> i32 = "int.snegate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.snegate". +// CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn BadReturnType(a: i32) -> bool = "int.negate"; -fn JustRight(a: i32) -> i32 = "int.negate"; +fn BadReturnType(a: i32) -> bool = "int.snegate"; +fn JustRight(a: i32) -> i32 = "int.snegate"; // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:20: ERROR: Array bound is not a constant. // CHECK:STDERR: var too_few: [i32; TooFew()]; @@ -58,7 +58,7 @@ var bad_return_type: [i32; BadReturnType(1)]; // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2)]; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: Calling function declared here. -// CHECK:STDERR: fn JustRight(a: i32) -> i32 = "int.negate"; +// CHECK:STDERR: fn JustRight(a: i32) -> i32 = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: var bad_call: [i32; JustRight(1, 2)]; @@ -68,7 +68,7 @@ fn RuntimeCallTooFew(a: i32) -> i32 { // CHECK:STDERR: return TooFew(a); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-42]]:1: Calling function declared here. - // CHECK:STDERR: fn TooFew() -> i32 = "int.negate"; + // CHECK:STDERR: fn TooFew() -> i32 = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: return TooFew(a); @@ -79,7 +79,7 @@ fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { // CHECK:STDERR: return TooMany(a, b, c); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-48]]:1: Calling function declared here. - // CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.negate"; + // CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: return TooMany(a, b, c); @@ -90,7 +90,7 @@ fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { // CHECK:STDERR: return BadReturnType(a, b); // CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-54]]:1: Calling function declared here. - // CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.negate"; + // CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.snegate"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: return BadReturnType(a, b); @@ -100,8 +100,8 @@ fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { package FailOverflow api; -fn Negate(a: i32) -> i32 = "int.negate"; -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; +fn Negate(a: i32) -> i32 = "int.snegate"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; // -(-INT_MAX) is INT_MAX. let a: i32 = Negate(Negate(0x7FFFFFFF)); @@ -167,7 +167,7 @@ let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1)); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -273,7 +273,7 @@ let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1)); // CHECK:STDOUT: // CHECK:STDOUT: fn @BadReturnType(%a: i32) -> bool; // CHECK:STDOUT: -// CHECK:STDOUT: fn @JustRight(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @JustRight(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCallTooFew(%a: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -363,7 +363,7 @@ let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1)); // CHECK:STDOUT: %b.loc14: i32 = bind_name b, %.loc14_48.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.snegate"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub"; +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.ssub"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/sub.carbon b/toolchain/check/testdata/builtins/int/ssub.carbon similarity index 97% rename from toolchain/check/testdata/builtins/int/sub.carbon rename to toolchain/check/testdata/builtins/int/ssub.carbon index 326909553ef5..803e2ea3ed61 100644 --- a/toolchain/check/testdata/builtins/int/sub.carbon +++ b/toolchain/check/testdata/builtins/int/ssub.carbon @@ -6,7 +6,7 @@ // --- int_sub.carbon -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; var arr: [i32; Sub(3, 2)]; let arr_p: [i32; 1]* = &arr; @@ -19,7 +19,7 @@ fn RuntimeCall(a: i32, b: i32) -> i32 { package FailOverflow api; -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; let a: i32 = Sub(0, 0x7FFFFFFF); let b: i32 = Sub(Sub(0, 0x7FFFFFFF), 1); @@ -75,7 +75,7 @@ let c: i32 = Sub(Sub(0, 0x7FFFFFFF), 2); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub"; +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.ssub"; // CHECK:STDOUT: // CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { // CHECK:STDOUT: !entry: @@ -145,5 +145,5 @@ let c: i32 = Sub(Sub(0, 0x7FFFFFFF), 2); // CHECK:STDOUT: %c: i32 = bind_name c, %.loc11_40.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub"; +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.ssub"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/uadd.carbon b/toolchain/check/testdata/builtins/int/uadd.carbon new file mode 100644 index 000000000000..852db0c8c1bd --- /dev/null +++ b/toolchain/check/testdata/builtins/int/uadd.carbon @@ -0,0 +1,326 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_add.carbon + +fn Add(a: i32, b: i32) -> i32 = "int.uadd"; + +var arr: [i32; Add(1, 2)]; +let arr_p: [i32; 3]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Add(a, b); +} + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.uadd". +// CHECK:STDERR: fn TooFew(a: i32) -> i32 = "int.uadd"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew(a: i32) -> i32 = "int.uadd"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.uadd". +// CHECK:STDERR: fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.uadd"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: i32, b: i32, c: i32) -> i32 = "int.uadd"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.uadd". +// CHECK:STDERR: fn BadReturnType(a: i32, b: i32) -> bool = "int.uadd"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn BadReturnType(a: i32, b: i32) -> bool = "int.uadd"; +fn JustRight(a: i32, b: i32) -> i32 = "int.uadd"; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:20: ERROR: Array bound is not a constant. +// CHECK:STDERR: var too_few: [i32; TooFew(1)]; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +var too_few: [i32; TooFew(1)]; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:21: ERROR: Array bound is not a constant. +// CHECK:STDERR: var too_many: [i32; TooMany(1, 2, 3)]; +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: +var too_many: [i32; TooMany(1, 2, 3)]; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:28: ERROR: Array bound is not a constant. +// CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1, 2)]; +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: +var bad_return_type: [i32; BadReturnType(1, 2)]; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:21: ERROR: 3 argument(s) passed to function expecting 2 argument(s). +// CHECK:STDERR: var bad_call: [i32; JustRight(1, 2, 3)]; +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: Calling function declared here. +// CHECK:STDERR: fn JustRight(a: i32, b: i32) -> i32 = "int.uadd"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var bad_call: [i32; JustRight(1, 2, 3)]; + +fn RuntimeCallTooFew(a: i32) -> i32 { + return TooFew(a); +} + +fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { + return BadReturnType(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Add(a: i32, b: i32) -> i32 = "int.uadd"; + +// Overflow is OK. +let a: i32 = Add(0x7FFFFFFF, 0); +let b: i32 = Add(0x7FFFFFFF, 1); + +// CHECK:STDOUT: --- int_add.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 3] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Add = %Add +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Add: = fn_decl @Add [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Add.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Add.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Add.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Add.ref: = name_ref Add, %Add [template = %Add] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Add.ref(%.loc4_20, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_25: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 3] = var arr +// CHECK:STDOUT: %arr: ref [i32; 3] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 3 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 3] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 3] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 3]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 3]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.uadd"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Add.ref: = name_ref Add, file.%Add [template = file.%Add] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_13: init i32 = call %Add.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_19.1: i32 = value_of_initializer %.loc8_13 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_13, %.loc8_19.1 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 3 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .too_few = %too_few +// CHECK:STDOUT: .too_many = %too_many +// CHECK:STDOUT: .bad_return_type = %bad_return_type +// CHECK:STDOUT: .bad_call = %bad_call +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: %a.loc8_11.1: i32 = param a +// CHECK:STDOUT: @TooFew.%a: i32 = bind_name a, %a.loc8_11.1 +// CHECK:STDOUT: @TooFew.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: i32 = param a +// CHECK:STDOUT: @TooMany.%a: i32 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: i32 = param b +// CHECK:STDOUT: @TooMany.%b: i32 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %c.loc13_28.1: i32 = param c +// CHECK:STDOUT: @TooMany.%c: i32 = bind_name c, %c.loc13_28.1 +// CHECK:STDOUT: @TooMany.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc18_18.1: i32 = param a +// CHECK:STDOUT: @BadReturnType.%a: i32 = bind_name a, %a.loc18_18.1 +// CHECK:STDOUT: %b.loc18_26.1: i32 = param b +// CHECK:STDOUT: @BadReturnType.%b: i32 = bind_name b, %b.loc18_26.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc19_14.1: i32 = param a +// CHECK:STDOUT: @JustRight.%a: i32 = bind_name a, %a.loc19_14.1 +// CHECK:STDOUT: %b.loc19_22.1: i32 = param b +// CHECK:STDOUT: @JustRight.%b: i32 = bind_name b, %b.loc19_22.1 +// CHECK:STDOUT: @JustRight.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, %TooFew [template = %TooFew] +// CHECK:STDOUT: %.loc25_27: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc25_26: init i32 = call %TooFew.ref(%.loc25_27) +// CHECK:STDOUT: %too_few.var: ref = var too_few +// CHECK:STDOUT: %too_few: ref = bind_name too_few, %too_few.var +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, %TooMany [template = %TooMany] +// CHECK:STDOUT: %.loc30_29: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc30_32: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc30_35: i32 = int_literal 3 [template = constants.%.3] +// CHECK:STDOUT: %.loc30_28: init i32 = call %TooMany.ref(%.loc30_29, %.loc30_32, %.loc30_35) +// CHECK:STDOUT: %too_many.var: ref = var too_many +// CHECK:STDOUT: %too_many: ref = bind_name too_many, %too_many.var +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, %BadReturnType [template = %BadReturnType] +// CHECK:STDOUT: %.loc35_42: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc35_45: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc35_41: init bool = call %BadReturnType.ref(%.loc35_42, %.loc35_45) +// CHECK:STDOUT: %bad_return_type.var: ref = var bad_return_type +// CHECK:STDOUT: %bad_return_type: ref = bind_name bad_return_type, %bad_return_type.var +// CHECK:STDOUT: %JustRight.ref: = name_ref JustRight, %JustRight [template = %JustRight] +// CHECK:STDOUT: %.loc43_31: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc43_34: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc43_37: i32 = int_literal 3 [template = constants.%.3] +// CHECK:STDOUT: %.loc43_30: init i32 = call %JustRight.ref() [template = ] +// CHECK:STDOUT: %.loc43_39: type = array_type %.loc43_30, i32 [template = ] +// CHECK:STDOUT: %bad_call.var: ref = var bad_call +// CHECK:STDOUT: %bad_call: ref = bind_name bad_call, %bad_call.var +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc45_22.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: i32 = bind_name a, %a.loc45_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc49_23.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: i32 = bind_name a, %a.loc49_23.1 +// CHECK:STDOUT: %b.loc49_31.1: i32 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: i32 = bind_name b, %b.loc49_31.1 +// CHECK:STDOUT: %c.loc49_39.1: i32 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: i32 = bind_name c, %c.loc49_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc53_29.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: i32 = bind_name a, %a.loc53_29.1 +// CHECK:STDOUT: %b.loc53_37.1: i32 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: i32 = bind_name b, %b.loc53_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(%a: i32) -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: i32, %b: i32, %c: i32) -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: i32, %b: i32) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: i32, %b: i32) -> i32 = "int.uadd"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %.loc46_16: init i32 = call %TooFew.ref(%a.ref) +// CHECK:STDOUT: %.loc46_19.1: i32 = value_of_initializer %.loc46_16 +// CHECK:STDOUT: %.loc46_19.2: i32 = converted %.loc46_16, %.loc46_19.1 +// CHECK:STDOUT: return %.loc46_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: i32, %b: i32, %c: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %c.ref: i32 = name_ref c, %c +// CHECK:STDOUT: %.loc50_17: init i32 = call %TooMany.ref(%a.ref, %b.ref, %c.ref) +// CHECK:STDOUT: %.loc50_26.1: i32 = value_of_initializer %.loc50_17 +// CHECK:STDOUT: %.loc50_26.2: i32 = converted %.loc50_17, %.loc50_26.1 +// CHECK:STDOUT: return %.loc50_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc54_23: init bool = call %BadReturnType.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc54_29.1: bool = value_of_initializer %.loc54_23 +// CHECK:STDOUT: %.loc54_29.2: bool = converted %.loc54_23, %.loc54_29.1 +// CHECK:STDOUT: return %.loc54_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Add = %Add +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Add: = fn_decl @Add [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Add.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Add.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Add.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Add.ref.loc7: = name_ref Add, %Add [template = %Add] +// CHECK:STDOUT: %.loc7_18: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc7_30: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc7_17: init i32 = call %Add.ref.loc7(%.loc7_18, %.loc7_30) [template = constants.%.1] +// CHECK:STDOUT: %.loc7_32.1: i32 = value_of_initializer %.loc7_17 [template = constants.%.1] +// CHECK:STDOUT: %.loc7_32.2: i32 = converted %.loc7_17, %.loc7_32.1 [template = constants.%.1] +// CHECK:STDOUT: %a.loc7: i32 = bind_name a, %.loc7_32.2 +// CHECK:STDOUT: %Add.ref.loc8: = name_ref Add, %Add [template = %Add] +// CHECK:STDOUT: %.loc8_18: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_30: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc8_17: init i32 = call %Add.ref.loc8(%.loc8_18, %.loc8_30) [template = constants.%.4] +// CHECK:STDOUT: %.loc8_32.1: i32 = value_of_initializer %.loc8_17 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_32.2: i32 = converted %.loc8_17, %.loc8_32.1 [template = constants.%.4] +// CHECK:STDOUT: %b.loc8: i32 = bind_name b, %.loc8_32.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.uadd"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/udiv.carbon b/toolchain/check/testdata/builtins/int/udiv.carbon new file mode 100644 index 000000000000..92a4372a183f --- /dev/null +++ b/toolchain/check/testdata/builtins/int/udiv.carbon @@ -0,0 +1,246 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_div.carbon + +fn Div(a: i32, b: i32) -> i32 = "int.udiv"; + +var arr: [i32; Div(3, 2)]; +let arr_p: [i32; 1]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Div(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Div(a: i32, b: i32) -> i32 = "int.udiv"; +fn Sub(a: i32, b: i32) -> i32 = "int.usub"; +fn Negate(a: i32) -> i32 = "int.unegate"; + +// -0x7FFF_FFFF / -1 is OK. +let a: i32 = Div(Negate(0x7FFF_FFFF), Negate(1)); + +// -0x8000_0000 / 1 is OK. +let b: i32 = Div(Sub(Negate(0x7FFF_FFFF), 1), 1); + +// -0x8000_0000 / -1 is OK. +let c: i32 = Div(Sub(Negate(0x7FFF_FFFF), 1), Negate(1)); + +// --- fail_div_by_zero.carbon + +package FailDivByZero api; + +fn Div(a: i32, b: i32) -> i32 = "int.udiv"; + +// CHECK:STDERR: fail_div_by_zero.carbon:[[@LINE+4]]:14: ERROR: Division by zero. +// CHECK:STDERR: let a: i32 = Div(1, 0); +// CHECK:STDERR: ^~~~ +// CHECK:STDERR: +let a: i32 = Div(1, 0); + +// CHECK:STDERR: fail_div_by_zero.carbon:[[@LINE+3]]:14: ERROR: Division by zero. +// CHECK:STDERR: let b: i32 = Div(0, 0); +// CHECK:STDERR: ^~~~ +let b: i32 = Div(0, 0); + +// CHECK:STDOUT: --- int_div.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 1] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Div = %Div +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Div: = fn_decl @Div [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Div.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Div.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Div.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Div.ref: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 3 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Div.ref(%.loc4_20, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_25: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 1] = var arr +// CHECK:STDOUT: %arr: ref [i32; 1] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 1] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 1] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 1]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 1]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.udiv"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Div.ref: = name_ref Div, file.%Div [template = file.%Div] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_13: init i32 = call %Div.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_19.1: i32 = value_of_initializer %.loc8_13 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_13, %.loc8_19.1 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -2147483647 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: i32 = int_literal -1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.6: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Div = %Div +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Div: = fn_decl @Div [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Div.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Div.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Div.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc5_8.1: i32 = param a +// CHECK:STDOUT: @Sub.%a: i32 = bind_name a, %a.loc5_8.1 +// CHECK:STDOUT: %b.loc5_16.1: i32 = param b +// CHECK:STDOUT: @Sub.%b: i32 = bind_name b, %b.loc5_16.1 +// CHECK:STDOUT: @Sub.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc6_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc6_11.1 +// CHECK:STDOUT: @Negate.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Div.ref.loc9: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %Negate.ref.loc9_18: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc9_25: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc9_24: init i32 = call %Negate.ref.loc9_18(%.loc9_25) [template = constants.%.2] +// CHECK:STDOUT: %Negate.ref.loc9_39: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc9_46: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc9_45: init i32 = call %Negate.ref.loc9_39(%.loc9_46) [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.1: i32 = value_of_initializer %.loc9_24 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_17.2: i32 = converted %.loc9_24, %.loc9_17.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_17.3: i32 = value_of_initializer %.loc9_45 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.4: i32 = converted %.loc9_45, %.loc9_17.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.5: init i32 = call %Div.ref.loc9(%.loc9_17.2, %.loc9_17.4) [template = constants.%.5] +// CHECK:STDOUT: %.loc9_49.1: i32 = value_of_initializer %.loc9_17.5 [template = constants.%.5] +// CHECK:STDOUT: %.loc9_49.2: i32 = converted %.loc9_17.5, %.loc9_49.1 [template = constants.%.5] +// CHECK:STDOUT: %a.loc9: i32 = bind_name a, %.loc9_49.2 +// CHECK:STDOUT: %Div.ref.loc12: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %Sub.ref.loc12: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc12_29: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc12_28: init i32 = call %Negate.ref.loc12(%.loc12_29) [template = constants.%.2] +// CHECK:STDOUT: %.loc12_43: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc12_21.1: i32 = value_of_initializer %.loc12_28 [template = constants.%.2] +// CHECK:STDOUT: %.loc12_21.2: i32 = converted %.loc12_28, %.loc12_21.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc12_21.3: init i32 = call %Sub.ref.loc12(%.loc12_21.2, %.loc12_43) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_47: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc12_17.1: i32 = value_of_initializer %.loc12_21.3 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_17.2: i32 = converted %.loc12_21.3, %.loc12_17.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_17.3: init i32 = call %Div.ref.loc12(%.loc12_17.2, %.loc12_47) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_49.1: i32 = value_of_initializer %.loc12_17.3 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_49.2: i32 = converted %.loc12_17.3, %.loc12_49.1 [template = constants.%.6] +// CHECK:STDOUT: %b.loc12: i32 = bind_name b, %.loc12_49.2 +// CHECK:STDOUT: %Div.ref.loc15: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %Sub.ref.loc15: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Negate.ref.loc15_22: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc15_29: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc15_28: init i32 = call %Negate.ref.loc15_22(%.loc15_29) [template = constants.%.2] +// CHECK:STDOUT: %.loc15_43: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc15_21.1: i32 = value_of_initializer %.loc15_28 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_21.2: i32 = converted %.loc15_28, %.loc15_21.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_21.3: init i32 = call %Sub.ref.loc15(%.loc15_21.2, %.loc15_43) [template = constants.%.6] +// CHECK:STDOUT: %Negate.ref.loc15_47: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc15_54: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc15_53: init i32 = call %Negate.ref.loc15_47(%.loc15_54) [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.1: i32 = value_of_initializer %.loc15_21.3 [template = constants.%.6] +// CHECK:STDOUT: %.loc15_17.2: i32 = converted %.loc15_21.3, %.loc15_17.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc15_17.3: i32 = value_of_initializer %.loc15_53 [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.4: i32 = converted %.loc15_53, %.loc15_17.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.5: init i32 = call %Div.ref.loc15(%.loc15_17.2, %.loc15_17.4) [template = constants.%.5] +// CHECK:STDOUT: %.loc15_57.1: i32 = value_of_initializer %.loc15_17.5 [template = constants.%.5] +// CHECK:STDOUT: %.loc15_57.2: i32 = converted %.loc15_17.5, %.loc15_57.1 [template = constants.%.5] +// CHECK:STDOUT: %c: i32 = bind_name c, %.loc15_57.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.udiv"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.usub"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.unegate"; +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_div_by_zero.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Div = %Div +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Div: = fn_decl @Div [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Div.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Div.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Div.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Div.ref.loc10: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %.loc10_18: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc10_21: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_17: init i32 = call %Div.ref.loc10(%.loc10_18, %.loc10_21) [template = ] +// CHECK:STDOUT: %.loc10_23.1: i32 = value_of_initializer %.loc10_17 [template = ] +// CHECK:STDOUT: %.loc10_23.2: i32 = converted %.loc10_17, %.loc10_23.1 [template = ] +// CHECK:STDOUT: %a.loc10: i32 = bind_name a, %.loc10_23.2 +// CHECK:STDOUT: %Div.ref.loc15: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %.loc15_18: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_21: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_17: init i32 = call %Div.ref.loc15(%.loc15_18, %.loc15_21) [template = ] +// CHECK:STDOUT: %.loc15_23.1: i32 = value_of_initializer %.loc15_17 [template = ] +// CHECK:STDOUT: %.loc15_23.2: i32 = converted %.loc15_17, %.loc15_23.1 [template = ] +// CHECK:STDOUT: %b.loc15: i32 = bind_name b, %.loc15_23.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.udiv"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/umod.carbon b/toolchain/check/testdata/builtins/int/umod.carbon new file mode 100644 index 000000000000..c113b800ea85 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/umod.carbon @@ -0,0 +1,248 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_div.carbon + +fn Mod(a: i32, b: i32) -> i32 = "int.umod"; + +var arr: [i32; Mod(5, 3)]; +let arr_p: [i32; 2]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Mod(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Mod(a: i32, b: i32) -> i32 = "int.umod"; +fn Sub(a: i32, b: i32) -> i32 = "int.usub"; +fn Negate(a: i32) -> i32 = "int.unegate"; + +// -0x7FFF_FFFF % -1 is OK. +let a: i32 = Mod(Negate(0x7FFF_FFFF), Negate(1)); + +// -0x8000_0000 % 1 is OK. +let b: i32 = Mod(Sub(Negate(0x7FFF_FFFF), 1), 1); + +// -0x8000_0000 / -1 is OK. +let c: i32 = Mod(Sub(Negate(0x7FFF_FFFF), 1), Negate(1)); + +// --- fail_div_by_zero.carbon + +package FailDivByZero api; + +fn Mod(a: i32, b: i32) -> i32 = "int.umod"; + +// Remainder of division by zero is not defined. + +// CHECK:STDERR: fail_div_by_zero.carbon:[[@LINE+4]]:14: ERROR: Division by zero. +// CHECK:STDERR: let a: i32 = Mod(1, 0); +// CHECK:STDERR: ^~~~ +// CHECK:STDERR: +let a: i32 = Mod(1, 0); + +// CHECK:STDERR: fail_div_by_zero.carbon:[[@LINE+3]]:14: ERROR: Division by zero. +// CHECK:STDERR: let b: i32 = Mod(0, 0); +// CHECK:STDERR: ^~~~ +let b: i32 = Mod(0, 0); + +// CHECK:STDOUT: --- int_div.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 5 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 2] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mod = %Mod +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mod: = fn_decl @Mod [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Mod.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Mod.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Mod.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mod.ref: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 5 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 3 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Mod.ref(%.loc4_20, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_25: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 2] = var arr +// CHECK:STDOUT: %arr: ref [i32; 2] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 2 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 2] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 2] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 2]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 2]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.umod"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Mod.ref: = name_ref Mod, file.%Mod [template = file.%Mod] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_13: init i32 = call %Mod.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_19.1: i32 = value_of_initializer %.loc8_13 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_13, %.loc8_19.1 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -2147483647 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: i32 = int_literal -1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: %.6: i32 = int_literal 0 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mod = %Mod +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mod: = fn_decl @Mod [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Mod.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Mod.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Mod.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc5_8.1: i32 = param a +// CHECK:STDOUT: @Sub.%a: i32 = bind_name a, %a.loc5_8.1 +// CHECK:STDOUT: %b.loc5_16.1: i32 = param b +// CHECK:STDOUT: @Sub.%b: i32 = bind_name b, %b.loc5_16.1 +// CHECK:STDOUT: @Sub.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc6_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc6_11.1 +// CHECK:STDOUT: @Negate.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mod.ref.loc9: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %Negate.ref.loc9_18: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc9_25: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc9_24: init i32 = call %Negate.ref.loc9_18(%.loc9_25) [template = constants.%.2] +// CHECK:STDOUT: %Negate.ref.loc9_39: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc9_46: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc9_45: init i32 = call %Negate.ref.loc9_39(%.loc9_46) [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.1: i32 = value_of_initializer %.loc9_24 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_17.2: i32 = converted %.loc9_24, %.loc9_17.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_17.3: i32 = value_of_initializer %.loc9_45 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.4: i32 = converted %.loc9_45, %.loc9_17.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_17.5: init i32 = call %Mod.ref.loc9(%.loc9_17.2, %.loc9_17.4) [template = constants.%.2] +// CHECK:STDOUT: %.loc9_49.1: i32 = value_of_initializer %.loc9_17.5 [template = constants.%.2] +// CHECK:STDOUT: %.loc9_49.2: i32 = converted %.loc9_17.5, %.loc9_49.1 [template = constants.%.2] +// CHECK:STDOUT: %a.loc9: i32 = bind_name a, %.loc9_49.2 +// CHECK:STDOUT: %Mod.ref.loc12: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %Sub.ref.loc12: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc12_29: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc12_28: init i32 = call %Negate.ref.loc12(%.loc12_29) [template = constants.%.2] +// CHECK:STDOUT: %.loc12_43: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc12_21.1: i32 = value_of_initializer %.loc12_28 [template = constants.%.2] +// CHECK:STDOUT: %.loc12_21.2: i32 = converted %.loc12_28, %.loc12_21.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc12_21.3: init i32 = call %Sub.ref.loc12(%.loc12_21.2, %.loc12_43) [template = constants.%.5] +// CHECK:STDOUT: %.loc12_47: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc12_17.1: i32 = value_of_initializer %.loc12_21.3 [template = constants.%.5] +// CHECK:STDOUT: %.loc12_17.2: i32 = converted %.loc12_21.3, %.loc12_17.1 [template = constants.%.5] +// CHECK:STDOUT: %.loc12_17.3: init i32 = call %Mod.ref.loc12(%.loc12_17.2, %.loc12_47) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_49.1: i32 = value_of_initializer %.loc12_17.3 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_49.2: i32 = converted %.loc12_17.3, %.loc12_49.1 [template = constants.%.6] +// CHECK:STDOUT: %b.loc12: i32 = bind_name b, %.loc12_49.2 +// CHECK:STDOUT: %Mod.ref.loc15: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %Sub.ref.loc15: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Negate.ref.loc15_22: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc15_29: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc15_28: init i32 = call %Negate.ref.loc15_22(%.loc15_29) [template = constants.%.2] +// CHECK:STDOUT: %.loc15_43: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc15_21.1: i32 = value_of_initializer %.loc15_28 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_21.2: i32 = converted %.loc15_28, %.loc15_21.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_21.3: init i32 = call %Sub.ref.loc15(%.loc15_21.2, %.loc15_43) [template = constants.%.5] +// CHECK:STDOUT: %Negate.ref.loc15_47: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc15_54: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc15_53: init i32 = call %Negate.ref.loc15_47(%.loc15_54) [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.1: i32 = value_of_initializer %.loc15_21.3 [template = constants.%.5] +// CHECK:STDOUT: %.loc15_17.2: i32 = converted %.loc15_21.3, %.loc15_17.1 [template = constants.%.5] +// CHECK:STDOUT: %.loc15_17.3: i32 = value_of_initializer %.loc15_53 [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.4: i32 = converted %.loc15_53, %.loc15_17.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc15_17.5: init i32 = call %Mod.ref.loc15(%.loc15_17.2, %.loc15_17.4) [template = constants.%.5] +// CHECK:STDOUT: %.loc15_57.1: i32 = value_of_initializer %.loc15_17.5 [template = constants.%.5] +// CHECK:STDOUT: %.loc15_57.2: i32 = converted %.loc15_17.5, %.loc15_57.1 [template = constants.%.5] +// CHECK:STDOUT: %c: i32 = bind_name c, %.loc15_57.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.umod"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.usub"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.unegate"; +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_div_by_zero.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 0 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mod = %Mod +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mod: = fn_decl @Mod [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Mod.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Mod.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Mod.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mod.ref.loc12: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %.loc12_18: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc12_21: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc12_17: init i32 = call %Mod.ref.loc12(%.loc12_18, %.loc12_21) [template = ] +// CHECK:STDOUT: %.loc12_23.1: i32 = value_of_initializer %.loc12_17 [template = ] +// CHECK:STDOUT: %.loc12_23.2: i32 = converted %.loc12_17, %.loc12_23.1 [template = ] +// CHECK:STDOUT: %a.loc12: i32 = bind_name a, %.loc12_23.2 +// CHECK:STDOUT: %Mod.ref.loc17: = name_ref Mod, %Mod [template = %Mod] +// CHECK:STDOUT: %.loc17_18: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc17_21: i32 = int_literal 0 [template = constants.%.2] +// CHECK:STDOUT: %.loc17_17: init i32 = call %Mod.ref.loc17(%.loc17_18, %.loc17_21) [template = ] +// CHECK:STDOUT: %.loc17_23.1: i32 = value_of_initializer %.loc17_17 [template = ] +// CHECK:STDOUT: %.loc17_23.2: i32 = converted %.loc17_17, %.loc17_23.1 [template = ] +// CHECK:STDOUT: %b.loc17: i32 = bind_name b, %.loc17_23.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.umod"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/umul.carbon b/toolchain/check/testdata/builtins/int/umul.carbon new file mode 100644 index 000000000000..487970ba7852 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/umul.carbon @@ -0,0 +1,127 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_mul.carbon + +fn Mul(a: i32, b: i32) -> i32 = "int.umul"; + +var arr: [i32; Mul(3, 2)]; +let arr_p: [i32; 6]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Mul(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Mul(a: i32, b: i32) -> i32 = "int.umul"; + +let a: i32 = Mul(0x7FFF, 0x10000); +let b: i32 = Mul(0x8000, 0x10000); + +// CHECK:STDOUT: --- int_mul.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 6 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 6] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mul = %Mul +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mul: = fn_decl @Mul [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Mul.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Mul.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Mul.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mul.ref: = name_ref Mul, %Mul [template = %Mul] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 3 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Mul.ref(%.loc4_20, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_25: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 6] = var arr +// CHECK:STDOUT: %arr: ref [i32; 6] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 6 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 6] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 6] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 6]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 6]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.umul"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Mul.ref: = name_ref Mul, file.%Mul [template = file.%Mul] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_13: init i32 = call %Mul.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_19.1: i32 = value_of_initializer %.loc8_13 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_13, %.loc8_19.1 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 32767 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 65536 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 2147418112 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 32768 [template] +// CHECK:STDOUT: %.5: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mul = %Mul +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mul: = fn_decl @Mul [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Mul.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Mul.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Mul.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Mul.ref.loc6: = name_ref Mul, %Mul [template = %Mul] +// CHECK:STDOUT: %.loc6_18: i32 = int_literal 32767 [template = constants.%.1] +// CHECK:STDOUT: %.loc6_26: i32 = int_literal 65536 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_17: init i32 = call %Mul.ref.loc6(%.loc6_18, %.loc6_26) [template = constants.%.3] +// CHECK:STDOUT: %.loc6_34.1: i32 = value_of_initializer %.loc6_17 [template = constants.%.3] +// CHECK:STDOUT: %.loc6_34.2: i32 = converted %.loc6_17, %.loc6_34.1 [template = constants.%.3] +// CHECK:STDOUT: %a.loc6: i32 = bind_name a, %.loc6_34.2 +// CHECK:STDOUT: %Mul.ref.loc7: = name_ref Mul, %Mul [template = %Mul] +// CHECK:STDOUT: %.loc7_18: i32 = int_literal 32768 [template = constants.%.4] +// CHECK:STDOUT: %.loc7_26: i32 = int_literal 65536 [template = constants.%.2] +// CHECK:STDOUT: %.loc7_17: init i32 = call %Mul.ref.loc7(%.loc7_18, %.loc7_26) [template = constants.%.5] +// CHECK:STDOUT: %.loc7_34.1: i32 = value_of_initializer %.loc7_17 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_34.2: i32 = converted %.loc7_17, %.loc7_34.1 [template = constants.%.5] +// CHECK:STDOUT: %b.loc7: i32 = bind_name b, %.loc7_34.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.umul"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/unegate.carbon b/toolchain/check/testdata/builtins/int/unegate.carbon new file mode 100644 index 000000000000..8214d1a2f762 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/unegate.carbon @@ -0,0 +1,365 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_negate.carbon + +fn Negate(a: i32) -> i32 = "int.unegate"; + +var arr: [i32; Negate(Negate(123))]; +let arr_p: [i32; 123]* = &arr; + +let n: i32 = Negate(1); + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Negate(a); +} + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.unegate". +// CHECK:STDERR: fn TooFew() -> i32 = "int.unegate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew() -> i32 = "int.unegate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.unegate". +// CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.unegate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: i32, b: i32) -> i32 = "int.unegate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "int.unegate". +// CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.unegate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn BadReturnType(a: i32) -> bool = "int.unegate"; +fn JustRight(a: i32) -> i32 = "int.unegate"; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:20: ERROR: Array bound is not a constant. +// CHECK:STDERR: var too_few: [i32; TooFew()]; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +var too_few: [i32; TooFew()]; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:21: ERROR: Array bound is not a constant. +// CHECK:STDERR: var too_many: [i32; TooMany(1, 2)]; +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: +var too_many: [i32; TooMany(1, 2)]; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:28: ERROR: Array bound is not a constant. +// CHECK:STDERR: var bad_return_type: [i32; BadReturnType(1)]; +// CHECK:STDERR: ^~~~~~~~~~~~~~ +// CHECK:STDERR: +var bad_return_type: [i32; BadReturnType(1)]; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:21: ERROR: 2 argument(s) passed to function expecting 1 argument(s). +// CHECK:STDERR: var bad_call: [i32; JustRight(1, 2)]; +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-21]]:1: Calling function declared here. +// CHECK:STDERR: fn JustRight(a: i32) -> i32 = "int.unegate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +var bad_call: [i32; JustRight(1, 2)]; + +fn RuntimeCallTooFew(a: i32) -> i32 { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: return TooFew(a); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-42]]:1: Calling function declared here. + // CHECK:STDERR: fn TooFew() -> i32 = "int.unegate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + return TooFew(a); +} + +fn RuntimeCallTooMany(a: i32, b: i32, c: i32) -> i32 { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 3 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: return TooMany(a, b, c); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-48]]:1: Calling function declared here. + // CHECK:STDERR: fn TooMany(a: i32, b: i32) -> i32 = "int.unegate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: ERROR: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: return BadReturnType(a, b); + // CHECK:STDERR: ^~~~~~~~~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-54]]:1: Calling function declared here. + // CHECK:STDERR: fn BadReturnType(a: i32) -> bool = "int.unegate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + return BadReturnType(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Negate(a: i32) -> i32 = "int.unegate"; +fn Sub(a: i32, b: i32) -> i32 = "int.usub"; + +// -(-INT_MAX) is INT_MAX. +let a: i32 = Negate(Negate(0x7FFFFFFF)); + +// -(-INT_MAX - 1) wraps around to INT_MIN. +let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1)); + +// CHECK:STDOUT: --- int_negate.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 123 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -123 [template] +// CHECK:STDOUT: %.3: type = array_type %.1, i32 [template] +// CHECK:STDOUT: %.4: type = ptr_type [i32; 123] [template] +// CHECK:STDOUT: %.5: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.6: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc2_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc2_11.1 +// CHECK:STDOUT: @Negate.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.ref.loc4_16: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %Negate.ref.loc4_23: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc4_30: i32 = int_literal 123 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_29: init i32 = call %Negate.ref.loc4_23(%.loc4_30) [template = constants.%.2] +// CHECK:STDOUT: %.loc4_22.1: i32 = value_of_initializer %.loc4_29 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_22.2: i32 = converted %.loc4_29, %.loc4_22.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_22.3: init i32 = call %Negate.ref.loc4_16(%.loc4_22.2) [template = constants.%.1] +// CHECK:STDOUT: %.loc4_35: type = array_type %.loc4_22.3, i32 [template = constants.%.3] +// CHECK:STDOUT: %arr.var: ref [i32; 123] = var arr +// CHECK:STDOUT: %arr: ref [i32; 123] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 123 [template = constants.%.1] +// CHECK:STDOUT: %.loc5_21: type = array_type %.loc5_18, i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_22: type = ptr_type [i32; 123] [template = constants.%.4] +// CHECK:STDOUT: %arr.ref: ref [i32; 123] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_26: [i32; 123]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 123]* = bind_name arr_p, %.loc5_26 +// CHECK:STDOUT: %Negate.ref.loc7: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc7_21: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_20: init i32 = call %Negate.ref.loc7(%.loc7_21) [template = constants.%.6] +// CHECK:STDOUT: %.loc7_23.1: i32 = value_of_initializer %.loc7_20 [template = constants.%.6] +// CHECK:STDOUT: %.loc7_23.2: i32 = converted %.loc7_20, %.loc7_23.1 [template = constants.%.6] +// CHECK:STDOUT: %n: i32 = bind_name n, %.loc7_23.2 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc9_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc9_16.1 +// CHECK:STDOUT: %b.loc9_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc9_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.unegate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Negate.ref: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %.loc10_16: init i32 = call %Negate.ref(%a.ref) +// CHECK:STDOUT: %.loc10_19.1: i32 = value_of_initializer %.loc10_16 +// CHECK:STDOUT: %.loc10_19.2: i32 = converted %.loc10_16, %.loc10_19.1 +// CHECK:STDOUT: return %.loc10_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .too_few = %too_few +// CHECK:STDOUT: .too_many = %too_many +// CHECK:STDOUT: .bad_return_type = %bad_return_type +// CHECK:STDOUT: .bad_call = %bad_call +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: @TooFew.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: i32 = param a +// CHECK:STDOUT: @TooMany.%a: i32 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: i32 = param b +// CHECK:STDOUT: @TooMany.%b: i32 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: @TooMany.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc18_18.1: i32 = param a +// CHECK:STDOUT: @BadReturnType.%a: i32 = bind_name a, %a.loc18_18.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc19_14.1: i32 = param a +// CHECK:STDOUT: @JustRight.%a: i32 = bind_name a, %a.loc19_14.1 +// CHECK:STDOUT: @JustRight.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, %TooFew [template = %TooFew] +// CHECK:STDOUT: %.loc25: init i32 = call %TooFew.ref() +// CHECK:STDOUT: %too_few.var: ref = var too_few +// CHECK:STDOUT: %too_few: ref = bind_name too_few, %too_few.var +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, %TooMany [template = %TooMany] +// CHECK:STDOUT: %.loc30_29: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc30_32: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc30_28: init i32 = call %TooMany.ref(%.loc30_29, %.loc30_32) +// CHECK:STDOUT: %too_many.var: ref = var too_many +// CHECK:STDOUT: %too_many: ref = bind_name too_many, %too_many.var +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, %BadReturnType [template = %BadReturnType] +// CHECK:STDOUT: %.loc35_42: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc35_41: init bool = call %BadReturnType.ref(%.loc35_42) +// CHECK:STDOUT: %bad_return_type.var: ref = var bad_return_type +// CHECK:STDOUT: %bad_return_type: ref = bind_name bad_return_type, %bad_return_type.var +// CHECK:STDOUT: %JustRight.ref: = name_ref JustRight, %JustRight [template = %JustRight] +// CHECK:STDOUT: %.loc44_31: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc44_34: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc44_30: init i32 = call %JustRight.ref() [template = ] +// CHECK:STDOUT: %.loc44_36: type = array_type %.loc44_30, i32 [template = ] +// CHECK:STDOUT: %bad_call.var: ref = var bad_call +// CHECK:STDOUT: %bad_call: ref = bind_name bad_call, %bad_call.var +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc46_22.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: i32 = bind_name a, %a.loc46_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc57_23.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: i32 = bind_name a, %a.loc57_23.1 +// CHECK:STDOUT: %b.loc57_31.1: i32 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: i32 = bind_name b, %b.loc57_31.1 +// CHECK:STDOUT: %c.loc57_39.1: i32 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: i32 = bind_name c, %c.loc57_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc68_29.1: i32 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: i32 = bind_name a, %a.loc68_29.1 +// CHECK:STDOUT: %b.loc68_37.1: i32 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: i32 = bind_name b, %b.loc68_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew() -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: i32, %b: i32) -> i32; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: i32) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: i32) -> i32 = "int.unegate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %.loc54_16: init i32 = call %TooFew.ref() [template = ] +// CHECK:STDOUT: %.loc54_19.1: i32 = value_of_initializer %.loc54_16 [template = ] +// CHECK:STDOUT: %.loc54_19.2: i32 = converted %.loc54_16, %.loc54_19.1 [template = ] +// CHECK:STDOUT: return %.loc54_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: i32, %b: i32, %c: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %c.ref: i32 = name_ref c, %c +// CHECK:STDOUT: %.loc65_17: init i32 = call %TooMany.ref() [template = ] +// CHECK:STDOUT: %.loc65_26.1: i32 = value_of_initializer %.loc65_17 [template = ] +// CHECK:STDOUT: %.loc65_26.2: i32 = converted %.loc65_17, %.loc65_26.1 [template = ] +// CHECK:STDOUT: return %.loc65_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc75_23: init bool = call %BadReturnType.ref() [template = ] +// CHECK:STDOUT: %.loc75_29.1: bool = value_of_initializer %.loc75_23 [template = ] +// CHECK:STDOUT: %.loc75_29.2: bool = converted %.loc75_23, %.loc75_29.1 [template = ] +// CHECK:STDOUT: return %.loc75_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -2147483647 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc4_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc4_11.1 +// CHECK:STDOUT: @Negate.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc5_8.1: i32 = param a +// CHECK:STDOUT: @Sub.%a: i32 = bind_name a, %a.loc5_8.1 +// CHECK:STDOUT: %b.loc5_16.1: i32 = param b +// CHECK:STDOUT: @Sub.%b: i32 = bind_name b, %b.loc5_16.1 +// CHECK:STDOUT: @Sub.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.ref.loc8_14: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %Negate.ref.loc8_21: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc8_28: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_27: init i32 = call %Negate.ref.loc8_21(%.loc8_28) [template = constants.%.2] +// CHECK:STDOUT: %.loc8_20.1: i32 = value_of_initializer %.loc8_27 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_20.2: i32 = converted %.loc8_27, %.loc8_20.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_20.3: init i32 = call %Negate.ref.loc8_14(%.loc8_20.2) [template = constants.%.1] +// CHECK:STDOUT: %.loc8_40.1: i32 = value_of_initializer %.loc8_20.3 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_40.2: i32 = converted %.loc8_20.3, %.loc8_40.1 [template = constants.%.1] +// CHECK:STDOUT: %a.loc8: i32 = bind_name a, %.loc8_40.2 +// CHECK:STDOUT: %Negate.ref.loc11_14: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %Sub.ref: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Negate.ref.loc11_25: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc11_32: i32 = int_literal 2147483647 [template = constants.%.1] +// CHECK:STDOUT: %.loc11_31: init i32 = call %Negate.ref.loc11_25(%.loc11_32) [template = constants.%.2] +// CHECK:STDOUT: %.loc11_45: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc11_24.1: i32 = value_of_initializer %.loc11_31 [template = constants.%.2] +// CHECK:STDOUT: %.loc11_24.2: i32 = converted %.loc11_31, %.loc11_24.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc11_24.3: init i32 = call %Sub.ref(%.loc11_24.2, %.loc11_45) [template = constants.%.4] +// CHECK:STDOUT: %.loc11_20.1: i32 = value_of_initializer %.loc11_24.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_20.2: i32 = converted %.loc11_24.3, %.loc11_20.1 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_20.3: init i32 = call %Negate.ref.loc11_14(%.loc11_20.2) [template = constants.%.4] +// CHECK:STDOUT: %.loc11_48.1: i32 = value_of_initializer %.loc11_20.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_48.2: i32 = converted %.loc11_20.3, %.loc11_48.1 [template = constants.%.4] +// CHECK:STDOUT: %b.loc11: i32 = bind_name b, %.loc11_48.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.unegate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.usub"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/usub.carbon b/toolchain/check/testdata/builtins/int/usub.carbon new file mode 100644 index 000000000000..b1d7b64c61d9 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/usub.carbon @@ -0,0 +1,146 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- int_sub.carbon + +fn Sub(a: i32, b: i32) -> i32 = "int.usub"; + +var arr: [i32; Sub(3, 2)]; +let arr_p: [i32; 1]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Sub(a, b); +} + +// --- overflow.carbon + +package Overflow api; + +fn Sub(a: i32, b: i32) -> i32 = "int.usub"; + +let a: i32 = Sub(0, 0x7FFFFFFF); +let b: i32 = Sub(Sub(0, 0x7FFFFFFF), 1); +let c: i32 = Sub(Sub(0, 0x7FFFFFFF), 2); + +// CHECK:STDOUT: --- int_sub.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 1] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Sub.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Sub.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Sub.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub.ref: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 3 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Sub.ref(%.loc4_20, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_25: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 1] = var arr +// CHECK:STDOUT: %arr: ref [i32; 1] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 1 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 1] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 1] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 1]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 1]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.usub"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Sub.ref: = name_ref Sub, file.%Sub [template = file.%Sub] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_13: init i32 = call %Sub.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_19.1: i32 = value_of_initializer %.loc8_13 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_13, %.loc8_19.1 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- overflow.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2147483647 [template] +// CHECK:STDOUT: %.3: i32 = int_literal -2147483647 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: %.6: i32 = int_literal 2 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc4_8.1: i32 = param a +// CHECK:STDOUT: @Sub.%a: i32 = bind_name a, %a.loc4_8.1 +// CHECK:STDOUT: %b.loc4_16.1: i32 = param b +// CHECK:STDOUT: @Sub.%b: i32 = bind_name b, %b.loc4_16.1 +// CHECK:STDOUT: @Sub.%return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Sub.ref.loc6: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %.loc6_18: i32 = int_literal 0 [template = constants.%.1] +// CHECK:STDOUT: %.loc6_21: i32 = int_literal 2147483647 [template = constants.%.2] +// CHECK:STDOUT: %.loc6_17: init i32 = call %Sub.ref.loc6(%.loc6_18, %.loc6_21) [template = constants.%.3] +// CHECK:STDOUT: %.loc6_32.1: i32 = value_of_initializer %.loc6_17 [template = constants.%.3] +// CHECK:STDOUT: %.loc6_32.2: i32 = converted %.loc6_17, %.loc6_32.1 [template = constants.%.3] +// CHECK:STDOUT: %a.loc6: i32 = bind_name a, %.loc6_32.2 +// CHECK:STDOUT: %Sub.ref.loc7_14: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Sub.ref.loc7_18: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %.loc7_22: i32 = int_literal 0 [template = constants.%.1] +// CHECK:STDOUT: %.loc7_25: i32 = int_literal 2147483647 [template = constants.%.2] +// CHECK:STDOUT: %.loc7_21: init i32 = call %Sub.ref.loc7_18(%.loc7_22, %.loc7_25) [template = constants.%.3] +// CHECK:STDOUT: %.loc7_38: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc7_17.1: i32 = value_of_initializer %.loc7_21 [template = constants.%.3] +// CHECK:STDOUT: %.loc7_17.2: i32 = converted %.loc7_21, %.loc7_17.1 [template = constants.%.3] +// CHECK:STDOUT: %.loc7_17.3: init i32 = call %Sub.ref.loc7_14(%.loc7_17.2, %.loc7_38) [template = constants.%.5] +// CHECK:STDOUT: %.loc7_40.1: i32 = value_of_initializer %.loc7_17.3 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_40.2: i32 = converted %.loc7_17.3, %.loc7_40.1 [template = constants.%.5] +// CHECK:STDOUT: %b.loc7: i32 = bind_name b, %.loc7_40.2 +// CHECK:STDOUT: %Sub.ref.loc8_14: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %Sub.ref.loc8_18: = name_ref Sub, %Sub [template = %Sub] +// CHECK:STDOUT: %.loc8_22: i32 = int_literal 0 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_25: i32 = int_literal 2147483647 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_21: init i32 = call %Sub.ref.loc8_18(%.loc8_22, %.loc8_25) [template = constants.%.3] +// CHECK:STDOUT: %.loc8_38: i32 = int_literal 2 [template = constants.%.6] +// CHECK:STDOUT: %.loc8_17.1: i32 = value_of_initializer %.loc8_21 [template = constants.%.3] +// CHECK:STDOUT: %.loc8_17.2: i32 = converted %.loc8_21, %.loc8_17.1 [template = constants.%.3] +// CHECK:STDOUT: %.loc8_17.3: init i32 = call %Sub.ref.loc8_14(%.loc8_17.2, %.loc8_38) [template = constants.%.2] +// CHECK:STDOUT: %.loc8_40.1: i32 = value_of_initializer %.loc8_17.3 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_40.2: i32 = converted %.loc8_17.3, %.loc8_40.1 [template = constants.%.2] +// CHECK:STDOUT: %c: i32 = bind_name c, %.loc8_40.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.usub"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/call.carbon b/toolchain/check/testdata/function/builtin/call.carbon index c878044811b9..4c3f9857b959 100644 --- a/toolchain/check/testdata/function/builtin/call.carbon +++ b/toolchain/check/testdata/function/builtin/call.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; var arr: [i32; Add(1, 2)]; @@ -41,5 +41,5 @@ var arr: [i32; Add(1, 2)]; // CHECK:STDOUT: %arr: ref [i32; 3] = bind_name arr, %arr.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/call_from_operator.carbon b/toolchain/check/testdata/function/builtin/call_from_operator.carbon index 93e37423e85b..bdfd14a7d63f 100644 --- a/toolchain/check/testdata/function/builtin/call_from_operator.carbon +++ b/toolchain/check/testdata/function/builtin/call_from_operator.carbon @@ -19,7 +19,7 @@ import Core; // TODO: This should be in `Core`, but currently impl lookup only looks in the // current file. impl i32 as Core.Add { - fn Op[self: Self](other: Self) -> Self = "int.add"; + fn Op[self: Self](other: Self) -> Self = "int.sadd"; } var arr: [i32; 1 + 2] = (3, 4, 3 + 4); @@ -141,7 +141,7 @@ var arr: [i32; 1 + 2] = (3, 4, 3 + 4); // CHECK:STDOUT: witness = %.1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Op.1[@impl.%self.loc7_9.2: i32](@impl.%other.loc7_21.2: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Op.1[@impl.%self.loc7_9.2: i32](@impl.%other.loc7_21.2: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: fn @Op.2[%self: Self](%other: Self) -> Self; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/definition.carbon b/toolchain/check/testdata/function/builtin/definition.carbon index f6b839576a21..39aa1a750486 100644 --- a/toolchain/check/testdata/function/builtin/definition.carbon +++ b/toolchain/check/testdata/function/builtin/definition.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: --- definition.carbon // CHECK:STDOUT: @@ -23,5 +23,5 @@ fn Add(a: i32, b: i32) -> i32 = "int.add"; // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/fail_redefined.carbon b/toolchain/check/testdata/function/builtin/fail_redefined.carbon index b1fb703b9f80..24d69207f292 100644 --- a/toolchain/check/testdata/function/builtin/fail_redefined.carbon +++ b/toolchain/check/testdata/function/builtin/fail_redefined.carbon @@ -4,34 +4,34 @@ // // AUTOUPDATE -fn A(n: i32, m: i32) -> i32 = "int.add"; +fn A(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: fail_redefined.carbon:[[@LINE+7]]:1: ERROR: Redefinition of `fn A`. // CHECK:STDERR: fn A(n: i32, m: i32) -> i32 { return n; } // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_redefined.carbon:[[@LINE-4]]:1: Previously defined here. -// CHECK:STDERR: fn A(n: i32, m: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn A(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fn A(n: i32, m: i32) -> i32 { return n; } fn B(n: i32, m: i32) -> i32 { return n; } // CHECK:STDERR: fail_redefined.carbon:[[@LINE+7]]:1: ERROR: Redefinition of `fn B`. -// CHECK:STDERR: fn B(n: i32, m: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn B(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_redefined.carbon:[[@LINE-4]]:1: Previously defined here. // CHECK:STDERR: fn B(n: i32, m: i32) -> i32 { return n; } // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn B(n: i32, m: i32) -> i32 = "int.add"; +fn B(n: i32, m: i32) -> i32 = "int.sadd"; -fn C(n: i32, m: i32) -> i32 = "int.add"; +fn C(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: fail_redefined.carbon:[[@LINE+6]]:1: ERROR: Redefinition of `fn C`. -// CHECK:STDERR: fn C(n: i32, m: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn C(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_redefined.carbon:[[@LINE-4]]:1: Previously defined here. -// CHECK:STDERR: fn C(n: i32, m: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn C(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -fn C(n: i32, m: i32) -> i32 = "int.add"; +fn C(n: i32, m: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: --- fail_redefined.carbon // CHECK:STDOUT: @@ -87,17 +87,17 @@ fn C(n: i32, m: i32) -> i32 = "int.add"; // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @A(%n: i32, %m: i32) -> i32 = "int.add" { +// CHECK:STDOUT: fn @A(%n: i32, %m: i32) -> i32 = "int.sadd" { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %n.ref: i32 = name_ref n, %n // CHECK:STDOUT: return %n.ref // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @B(%n: i32, %m: i32) -> i32 = "int.add" { +// CHECK:STDOUT: fn @B(%n: i32, %m: i32) -> i32 = "int.sadd" { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %n.ref: i32 = name_ref n, file.%n.loc17_6.2 // CHECK:STDOUT: return %n.ref // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @C(%n: i32, %m: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @C(%n: i32, %m: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/builtin/import.carbon b/toolchain/check/testdata/function/builtin/import.carbon index ea542ab8177f..c2b82f141ec1 100644 --- a/toolchain/check/testdata/function/builtin/import.carbon +++ b/toolchain/check/testdata/function/builtin/import.carbon @@ -10,7 +10,7 @@ package Core api; import library "prelude"; -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; // --- use.carbon @@ -33,7 +33,7 @@ var arr: [i32; Core.Add(1, 2)] = (1, 2, 3); // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: --- use.carbon // CHECK:STDOUT: @@ -65,7 +65,7 @@ var arr: [i32; Core.Add(1, 2)] = (1, 2, 3); // CHECK:STDOUT: %arr: ref [i32; 3] = bind_name arr, %arr.var // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @Add(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: diff --git a/toolchain/check/testdata/function/builtin/method.carbon b/toolchain/check/testdata/function/builtin/method.carbon index 2bad14174b48..a4e6274e2ba2 100644 --- a/toolchain/check/testdata/function/builtin/method.carbon +++ b/toolchain/check/testdata/function/builtin/method.carbon @@ -9,7 +9,7 @@ interface I { } impl i32 as I { - fn F[self: i32](other: i32) -> i32 = "int.add"; + fn F[self: i32](other: i32) -> i32 = "int.sadd"; } var arr: [i32; 1.(I.F)(2)]; @@ -95,5 +95,5 @@ var arr: [i32; 1.(I.F)(2)]; // CHECK:STDOUT: // CHECK:STDOUT: fn @F.1[@I.%self.loc8_8.2: Self](@I.%other.loc8_20.2: Self) -> Self; // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2[@impl.%self.loc12_8.2: i32](@impl.%other.loc12_19.2: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @F.2[@impl.%self.loc12_8.2: i32](@impl.%other.loc12_19.2: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon b/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon index 444e54cfaed4..9d7cd41f7c65 100644 --- a/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon +++ b/toolchain/check/testdata/interface/fail_todo_define_default_fn_inline.carbon @@ -12,9 +12,9 @@ interface Interface { default fn F() {} // CHECK:STDERR: fail_todo_define_default_fn_inline.carbon:[[@LINE+3]]:3: ERROR: Semantics TODO: `interface modifier`. - // CHECK:STDERR: default fn G(a: i32, b: i32) -> i32 = "int.add"; + // CHECK:STDERR: default fn G(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~ - default fn G(a: i32, b: i32) -> i32 = "int.add"; + default fn G(a: i32, b: i32) -> i32 = "int.sadd"; } // CHECK:STDOUT: --- fail_todo_define_default_fn_inline.carbon @@ -60,5 +60,5 @@ interface Interface { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@Interface.%a.loc17_16.2: i32, @Interface.%b.loc17_24.2: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @G(@Interface.%a.loc17_16.2: i32, @Interface.%b.loc17_24.2: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon b/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon index 7643f84367d9..cd81e28f259e 100644 --- a/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon +++ b/toolchain/check/testdata/interface/fail_todo_define_default_fn_out_of_line.carbon @@ -28,12 +28,12 @@ interface Interface { fn Interface.F() {} // CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope. -// CHECK:STDERR: fn Interface.G(a: i32, b: i32) -> i32 = "int.add"; +// CHECK:STDERR: fn Interface.G(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_todo_define_default_fn_out_of_line.carbon:[[@LINE-15]]:3: Name is previously declared here. // CHECK:STDERR: default fn G(a: i32, b: i32) -> i32; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -fn Interface.G(a: i32, b: i32) -> i32 = "int.add"; +fn Interface.G(a: i32, b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: --- fail_todo_define_default_fn_out_of_line.carbon // CHECK:STDOUT: @@ -90,5 +90,5 @@ fn Interface.G(a: i32, b: i32) -> i32 = "int.add"; // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @.2(%a: i32, %b: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @.2(%a: i32, %b: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/todo_define_not_default.carbon b/toolchain/check/testdata/interface/todo_define_not_default.carbon index 57ff9ba7a3b1..c95613f9a7b6 100644 --- a/toolchain/check/testdata/interface/todo_define_not_default.carbon +++ b/toolchain/check/testdata/interface/todo_define_not_default.carbon @@ -7,7 +7,7 @@ interface I { // TODO: A definition without `default` in an interface should be rejected. fn F() {} - fn G(a: i32, b: i32) -> i32 = "int.add"; + fn G(a: i32, b: i32) -> i32 = "int.sadd"; // TODO: An associated constant with an initializer without `default` in an // interface should be rejected. @@ -74,5 +74,5 @@ interface I { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @G(@I.%a.loc10_8.2: i32, @I.%b.loc10_16.2: i32) -> i32 = "int.add"; +// CHECK:STDOUT: fn @G(@I.%a.loc10_8.2: i32, @I.%b.loc10_16.2: i32) -> i32 = "int.sadd"; // CHECK:STDOUT: diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index ac3c40603305..04fe3f07d7fd 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -227,7 +227,7 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetTypeAsValue()); return; - case SemIR::BuiltinFunctionKind::IntNegate: { + case SemIR::BuiltinFunctionKind::IntSNegate: { // Lower `-x` as `0 - x`. auto* operand = context.GetValue(arg_ids[0]); context.SetLocal(inst_id, @@ -238,6 +238,15 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, /*HasNSW=*/SignedOverflowIsUB)); return; } + case SemIR::BuiltinFunctionKind::IntUNegate: { + // Lower `-x` as `0 - x`. + auto* operand = context.GetValue(arg_ids[0]); + context.SetLocal(inst_id, + context.builder().CreateSub( + llvm::ConstantInt::getNullValue(operand->getType()), + operand, "neg")); + return; + } case SemIR::BuiltinFunctionKind::IntComplement: { // Lower `^x` as `-1 ^ x`. auto* operand = context.GetValue(arg_ids[0]); @@ -247,7 +256,7 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, operand, "cmpl")); return; } - case SemIR::BuiltinFunctionKind::IntAdd: { + case SemIR::BuiltinFunctionKind::IntSAdd: { context.SetLocal(inst_id, context.builder().CreateAdd( context.GetValue(arg_ids[0]), context.GetValue(arg_ids[1]), "add", @@ -255,7 +264,7 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, /*HasNSW=*/SignedOverflowIsUB)); return; } - case SemIR::BuiltinFunctionKind::IntSub: { + case SemIR::BuiltinFunctionKind::IntSSub: { context.SetLocal(inst_id, context.builder().CreateSub( context.GetValue(arg_ids[0]), context.GetValue(arg_ids[1]), "sub", @@ -263,7 +272,7 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, /*HasNSW=*/SignedOverflowIsUB)); return; } - case SemIR::BuiltinFunctionKind::IntMul: { + case SemIR::BuiltinFunctionKind::IntSMul: { context.SetLocal(inst_id, context.builder().CreateMul( context.GetValue(arg_ids[0]), context.GetValue(arg_ids[1]), "mul", @@ -271,24 +280,46 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, /*HasNSW=*/SignedOverflowIsUB)); return; } - case SemIR::BuiltinFunctionKind::IntDiv: { - context.SetLocal(inst_id, IsSignedInt(context, inst_id) - ? context.builder().CreateSDiv( - context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "div") - : context.builder().CreateUDiv( - context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "div")); + case SemIR::BuiltinFunctionKind::IntSDiv: { + context.SetLocal(inst_id, context.builder().CreateSDiv( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "div")); return; } - case SemIR::BuiltinFunctionKind::IntMod: { - context.SetLocal(inst_id, IsSignedInt(context, inst_id) - ? context.builder().CreateSRem( - context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "rem") - : context.builder().CreateURem( - context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "rem")); + case SemIR::BuiltinFunctionKind::IntSMod: { + context.SetLocal(inst_id, context.builder().CreateSRem( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "rem")); + return; + } + case SemIR::BuiltinFunctionKind::IntUAdd: { + context.SetLocal(inst_id, context.builder().CreateAdd( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "add")); + return; + } + case SemIR::BuiltinFunctionKind::IntUSub: { + context.SetLocal(inst_id, context.builder().CreateSub( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "sub")); + return; + } + case SemIR::BuiltinFunctionKind::IntUMul: { + context.SetLocal(inst_id, context.builder().CreateMul( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "mul")); + return; + } + case SemIR::BuiltinFunctionKind::IntUDiv: { + context.SetLocal(inst_id, context.builder().CreateUDiv( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "div")); + return; + } + case SemIR::BuiltinFunctionKind::IntUMod: { + context.SetLocal(inst_id, context.builder().CreateURem( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "rem")); return; } case SemIR::BuiltinFunctionKind::IntAnd: { diff --git a/toolchain/lower/testdata/builtins/int.carbon b/toolchain/lower/testdata/builtins/int.carbon index 9b31d75e599a..dd5b3999adfc 100644 --- a/toolchain/lower/testdata/builtins/int.carbon +++ b/toolchain/lower/testdata/builtins/int.carbon @@ -4,22 +4,22 @@ // // AUTOUPDATE -fn Negate(a: i32) -> i32 = "int.negate"; +fn Negate(a: i32) -> i32 = "int.snegate"; fn TestNegate(a: i32) -> i32 { return Negate(a); } -fn Add(a: i32, b: i32) -> i32 = "int.add"; +fn Add(a: i32, b: i32) -> i32 = "int.sadd"; fn TestAdd(a: i32, b: i32) -> i32 { return Add(a, b); } -fn Sub(a: i32, b: i32) -> i32 = "int.sub"; +fn Sub(a: i32, b: i32) -> i32 = "int.ssub"; fn TestSub(a: i32, b: i32) -> i32 { return Sub(a, b); } -fn Mul(a: i32, b: i32) -> i32 = "int.mul"; +fn Mul(a: i32, b: i32) -> i32 = "int.smul"; fn TestMul(a: i32, b: i32) -> i32 { return Mul(a, b); } -fn Div(a: i32, b: i32) -> i32 = "int.div"; +fn Div(a: i32, b: i32) -> i32 = "int.sdiv"; fn TestDiv(a: i32, b: i32) -> i32 { return Div(a, b); } -fn Mod(a: i32, b: i32) -> i32 = "int.mod"; +fn Mod(a: i32, b: i32) -> i32 = "int.smod"; fn TestMod(a: i32, b: i32) -> i32 { return Mod(a, b); } fn Complement(a: i32) -> i32 = "int.complement"; diff --git a/toolchain/lower/testdata/builtins/method_vs_nonmethod.carbon b/toolchain/lower/testdata/builtins/method_vs_nonmethod.carbon index 00d7370f5a62..bbd4cb58dad2 100644 --- a/toolchain/lower/testdata/builtins/method_vs_nonmethod.carbon +++ b/toolchain/lower/testdata/builtins/method_vs_nonmethod.carbon @@ -4,8 +4,8 @@ // // AUTOUPDATE -fn AddNonmethod(a: i32, b: i32) -> i32 = "int.add"; -fn AddMethod[self: i32](b: i32) -> i32 = "int.add"; +fn AddNonmethod(a: i32, b: i32) -> i32 = "int.sadd"; +fn AddMethod[self: i32](b: i32) -> i32 = "int.sadd"; fn TestAddNonmethod(a: i32, b: i32) -> i32 { return AddNonmethod(a, b); } fn TestAddMethod(a: i32, b: i32) -> i32 { return a.(AddMethod)(b); } diff --git a/toolchain/lower/testdata/builtins/overloaded_operator.carbon b/toolchain/lower/testdata/builtins/overloaded_operator.carbon index 2e021db912f5..60a457e97e99 100644 --- a/toolchain/lower/testdata/builtins/overloaded_operator.carbon +++ b/toolchain/lower/testdata/builtins/overloaded_operator.carbon @@ -19,7 +19,7 @@ import Core; // TODO: Move this into prelude.carbon when possible. For now, impl lookup only // looks in the current file. impl i32 as Core.Add { - fn Op[self: i32](other: i32) -> i32 = "int.add"; + fn Op[self: i32](other: i32) -> i32 = "int.sadd"; } fn AddThreeIntegers(a: i32, b: i32, c: i32) -> i32 { diff --git a/toolchain/lower/testdata/builtins/uint.carbon b/toolchain/lower/testdata/builtins/uint.carbon index 0be02e87cc7f..c171fd3b0488 100644 --- a/toolchain/lower/testdata/builtins/uint.carbon +++ b/toolchain/lower/testdata/builtins/uint.carbon @@ -4,22 +4,22 @@ // // AUTOUPDATE -fn Negate(a: u64) -> u64 = "int.negate"; +fn Negate(a: u64) -> u64 = "int.unegate"; fn TestNegate(a: u64) -> u64 { return Negate(a); } -fn Add(a: u64, b: u64) -> u64 = "int.add"; +fn Add(a: u64, b: u64) -> u64 = "int.uadd"; fn TestAdd(a: u64, b: u64) -> u64 { return Add(a, b); } -fn Sub(a: u64, b: u64) -> u64 = "int.sub"; +fn Sub(a: u64, b: u64) -> u64 = "int.usub"; fn TestSub(a: u64, b: u64) -> u64 { return Sub(a, b); } -fn Mul(a: u64, b: u64) -> u64 = "int.mul"; +fn Mul(a: u64, b: u64) -> u64 = "int.umul"; fn TestMul(a: u64, b: u64) -> u64 { return Mul(a, b); } -fn Div(a: u64, b: u64) -> u64 = "int.div"; +fn Div(a: u64, b: u64) -> u64 = "int.udiv"; fn TestDiv(a: u64, b: u64) -> u64 { return Div(a, b); } -fn Mod(a: u64, b: u64) -> u64 = "int.mod"; +fn Mod(a: u64, b: u64) -> u64 = "int.umod"; fn TestMod(a: u64, b: u64) -> u64 { return Mod(a, b); } fn Complement(a: u64) -> u64 = "int.complement"; diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index 4896b4078910..dff83260d99e 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -164,29 +164,53 @@ constexpr BuiltinInfo FloatMakeType = {"float.make_type", constexpr BuiltinInfo BoolMakeType = {"bool.make_type", ValidateSignatureType>}; -// "int.negate": integer negation. -constexpr BuiltinInfo IntNegate = {"int.negate", - ValidateSignatureIntT>}; +// "int.snegate": integer negation. +constexpr BuiltinInfo IntSNegate = {"int.snegate", + ValidateSignatureIntT>}; -// "int.add": integer addition. -constexpr BuiltinInfo IntAdd = {"int.add", - ValidateSignatureIntT>}; +// "int.sadd": integer addition. +constexpr BuiltinInfo IntSAdd = {"int.sadd", + ValidateSignatureIntT>}; -// "int.sub": integer subtraction. -constexpr BuiltinInfo IntSub = {"int.sub", - ValidateSignatureIntT>}; +// "int.ssub": integer subtraction. +constexpr BuiltinInfo IntSSub = {"int.ssub", + ValidateSignatureIntT>}; -// "int.mul": integer multiplication. -constexpr BuiltinInfo IntMul = {"int.mul", - ValidateSignatureIntT>}; +// "int.smul": integer multiplication. +constexpr BuiltinInfo IntSMul = {"int.smul", + ValidateSignatureIntT>}; -// "int.div": integer division. -constexpr BuiltinInfo IntDiv = {"int.div", - ValidateSignatureIntT>}; +// "int.sdiv": integer division. +constexpr BuiltinInfo IntSDiv = {"int.sdiv", + ValidateSignatureIntT>}; + +// "int.smod": integer modulo. +constexpr BuiltinInfo IntSMod = {"int.smod", + ValidateSignatureIntT>}; + +// "int.unegate": unsigned integer negation. +constexpr BuiltinInfo IntUNegate = {"int.unegate", + ValidateSignatureIntT>}; + +// "int.uadd": unsigned integer addition. +constexpr BuiltinInfo IntUAdd = {"int.uadd", + ValidateSignatureIntT>}; + +// "int.usub": unsigned integer subtraction. +constexpr BuiltinInfo IntUSub = {"int.usub", + ValidateSignatureIntT>}; + +// "int.umul": unsigned integer multiplication. +constexpr BuiltinInfo IntUMul = {"int.umul", + ValidateSignatureIntT>}; + +// "int.udiv": unsigned integer division. +constexpr BuiltinInfo IntUDiv = {"int.udiv", + ValidateSignatureIntT>}; // "int.mod": integer modulo. -constexpr BuiltinInfo IntMod = {"int.mod", - ValidateSignatureIntT>}; +constexpr BuiltinInfo IntUMod = {"int.umod", + ValidateSignatureIntT>}; // "int.complement": integer bitwise complement. constexpr BuiltinInfo IntComplement = {"int.complement", diff --git a/toolchain/sem_ir/builtin_function_kind.def b/toolchain/sem_ir/builtin_function_kind.def index cd7adbcd20fe..d3e32b8eb1cf 100644 --- a/toolchain/sem_ir/builtin_function_kind.def +++ b/toolchain/sem_ir/builtin_function_kind.def @@ -26,12 +26,18 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatMakeType) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(BoolMakeType) // Integer arithmetic. -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntNegate) -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntAdd) -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSub) -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntMul) -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntDiv) -CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntMod) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSNegate) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSAdd) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSSub) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSMul) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSDiv) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSMod) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUNegate) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUAdd) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUSub) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUMul) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUDiv) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntUMod) // Integer bitwise. CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntComplement)