From 5964795f34ac81b16598e4fc45cb32d4c6d223f8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 18 Apr 2024 18:42:35 -0700 Subject: [PATCH] Use separate builtins for signed / unsigned arithmetic. (#3892) Per offline discussion with chandlerc and jonmeow, use different builtins for signed versus unsigned integer ops instead of looking at the type. In this commit, the arithmetic builtins (add, sub, negate, mul, div, mod) are split. I'll apply the same change to comparisons and to right shift in separate PRs. --- toolchain/check/eval.cpp | 95 +++-- .../testdata/array/canonicalize_index.carbon | 4 +- .../testdata/array/fail_bound_negative.carbon | 4 +- .../testdata/builtins/int/greater.carbon | 4 +- .../testdata/builtins/int/greater_eq.carbon | 4 +- .../testdata/builtins/int/left_shift.carbon | 4 +- .../check/testdata/builtins/int/less.carbon | 4 +- .../testdata/builtins/int/less_eq.carbon | 4 +- .../builtins/int/make_type_signed.carbon | 4 +- .../builtins/int/make_type_unsigned.carbon | 4 +- .../testdata/builtins/int/right_shift.carbon | 8 +- .../builtins/int/{add.carbon => sadd.carbon} | 32 +- .../builtins/int/{div.carbon => sdiv.carbon} | 20 +- .../builtins/int/{mod.carbon => smod.carbon} | 20 +- .../builtins/int/{mul.carbon => smul.carbon} | 8 +- .../int/{negate.carbon => snegate.carbon} | 42 +- .../builtins/int/{sub.carbon => ssub.carbon} | 8 +- .../check/testdata/builtins/int/uadd.carbon | 326 ++++++++++++++++ .../check/testdata/builtins/int/udiv.carbon | 246 ++++++++++++ .../check/testdata/builtins/int/umod.carbon | 248 ++++++++++++ .../check/testdata/builtins/int/umul.carbon | 127 ++++++ .../testdata/builtins/int/unegate.carbon | 365 ++++++++++++++++++ .../check/testdata/builtins/int/usub.carbon | 146 +++++++ .../testdata/function/builtin/call.carbon | 4 +- .../builtin/call_from_operator.carbon | 4 +- .../function/builtin/definition.carbon | 4 +- .../function/builtin/fail_redefined.carbon | 22 +- .../testdata/function/builtin/import.carbon | 6 +- .../testdata/function/builtin/method.carbon | 4 +- .../fail_todo_define_default_fn_inline.carbon | 6 +- ..._todo_define_default_fn_out_of_line.carbon | 6 +- .../interface/todo_define_not_default.carbon | 4 +- toolchain/lower/handle.cpp | 71 +++- toolchain/lower/testdata/builtins/int.carbon | 12 +- .../builtins/method_vs_nonmethod.carbon | 4 +- .../builtins/overloaded_operator.carbon | 2 +- toolchain/lower/testdata/builtins/uint.carbon | 12 +- toolchain/sem_ir/builtin_function_kind.cpp | 58 ++- toolchain/sem_ir/builtin_function_kind.def | 18 +- 39 files changed, 1757 insertions(+), 207 deletions(-) rename toolchain/check/testdata/builtins/int/{add.carbon => sadd.carbon} (95%) rename toolchain/check/testdata/builtins/int/{div.carbon => sdiv.carbon} (96%) rename toolchain/check/testdata/builtins/int/{mod.carbon => smod.carbon} (96%) rename toolchain/check/testdata/builtins/int/{mul.carbon => smul.carbon} (96%) rename toolchain/check/testdata/builtins/int/{negate.carbon => snegate.carbon} (94%) rename toolchain/check/testdata/builtins/int/{sub.carbon => ssub.carbon} (97%) create mode 100644 toolchain/check/testdata/builtins/int/uadd.carbon create mode 100644 toolchain/check/testdata/builtins/int/udiv.carbon create mode 100644 toolchain/check/testdata/builtins/int/umod.carbon create mode 100644 toolchain/check/testdata/builtins/int/umul.carbon create mode 100644 toolchain/check/testdata/builtins/int/unegate.carbon create mode 100644 toolchain/check/testdata/builtins/int/usub.carbon 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)