mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Add builtins for some basic integer operations. (#3816)
Supports unary `-`, and binary `+`, `-`, `*`, `/`, `%`, `==`, `!=`. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
a3d77d9b74
commit
ebbc648342
+165
-21
@@ -286,8 +286,134 @@ static auto PerformAggregateIndex(Context& context, SemIR::Inst inst)
|
||||
return context.constant_values().Get(elements[index_val.getZExtValue()]);
|
||||
}
|
||||
|
||||
// Issues a diagnostic for a compile-time division by zero.
|
||||
static auto DiagnoseDivisionByZero(Context& context, SemIRLocation loc)
|
||||
-> void {
|
||||
CARBON_DIAGNOSTIC(CompileTimeDivisionByZero, Error, "Division by zero.");
|
||||
context.emitter().Emit(loc, CompileTimeDivisionByZero);
|
||||
}
|
||||
|
||||
// Performs a builtin unary integer -> integer operation.
|
||||
static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLocation loc,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
SemIR::InstId arg_id)
|
||||
-> SemIR::ConstantId {
|
||||
CARBON_CHECK(builtin_kind == SemIR::BuiltinFunctionKind::IntNegate)
|
||||
<< "Unexpected builtin kind";
|
||||
|
||||
auto op = context.insts().GetAs<SemIR::IntLiteral>(arg_id);
|
||||
auto op_val = context.ints().Get(op.int_id);
|
||||
|
||||
if (op_val.isMinSignedValue()) {
|
||||
CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error,
|
||||
"Integer overflow in negation of {0}.", llvm::APSInt);
|
||||
context.emitter().Emit(loc, CompileTimeIntegerNegateOverflow,
|
||||
llvm::APSInt(op_val, false));
|
||||
}
|
||||
op_val.negate();
|
||||
|
||||
auto result = context.ints().Add(op_val);
|
||||
return MakeConstantResult(context, SemIR::IntLiteral{op.type_id, result},
|
||||
Phase::Template);
|
||||
}
|
||||
|
||||
// Performs a builtin binary integer -> integer operation.
|
||||
static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLocation loc,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
SemIR::InstId lhs_id,
|
||||
SemIR::InstId rhs_id)
|
||||
-> SemIR::ConstantId {
|
||||
auto lhs = context.insts().GetAs<SemIR::IntLiteral>(lhs_id);
|
||||
auto rhs = context.insts().GetAs<SemIR::IntLiteral>(rhs_id);
|
||||
auto lhs_val = context.ints().Get(lhs.int_id);
|
||||
auto rhs_val = context.ints().Get(rhs.int_id);
|
||||
|
||||
bool overflow = false;
|
||||
llvm::APInt result_val;
|
||||
llvm::StringLiteral op_str = "<error>";
|
||||
switch (builtin_kind) {
|
||||
case SemIR::BuiltinFunctionKind::IntAdd:
|
||||
result_val = lhs_val.sadd_ov(rhs_val, overflow);
|
||||
op_str = "+";
|
||||
break;
|
||||
case SemIR::BuiltinFunctionKind::IntSub:
|
||||
result_val = lhs_val.ssub_ov(rhs_val, overflow);
|
||||
op_str = "-";
|
||||
break;
|
||||
case SemIR::BuiltinFunctionKind::IntMul:
|
||||
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 = 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 = lhs_val.srem(rhs_val);
|
||||
// LLVM weirdly lacks `srem_ov`, so we work it out for ourselves:
|
||||
// <signed min> % -1 overflows because <signed min> / -1 overflows.
|
||||
overflow = (lhs_val.isMinSignedValue() && rhs_val.isAllOnes());
|
||||
op_str = "%";
|
||||
break;
|
||||
|
||||
default:
|
||||
CARBON_FATAL() << "Unexpected operation kind.";
|
||||
}
|
||||
|
||||
if (overflow) {
|
||||
CARBON_DIAGNOSTIC(CompileTimeIntegerOverflow, Error,
|
||||
"Integer overflow in calculation {0} {1} {2}.",
|
||||
llvm::APSInt, llvm::StringLiteral, llvm::APSInt);
|
||||
context.emitter().Emit(loc, CompileTimeIntegerOverflow,
|
||||
llvm::APSInt(lhs_val, false), op_str,
|
||||
llvm::APSInt(rhs_val, false));
|
||||
}
|
||||
|
||||
auto result = context.ints().Add(result_val);
|
||||
return MakeConstantResult(context, SemIR::IntLiteral{lhs.type_id, result},
|
||||
Phase::Template);
|
||||
}
|
||||
|
||||
// Performs a builtin integer comparison.
|
||||
static auto PerformBuiltinIntComparison(Context& context,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
SemIR::InstId lhs_id,
|
||||
SemIR::InstId rhs_id,
|
||||
SemIR::TypeId bool_type_id)
|
||||
-> SemIR::ConstantId {
|
||||
auto lhs_val = context.ints().Get(
|
||||
context.insts().GetAs<SemIR::IntLiteral>(lhs_id).int_id);
|
||||
auto rhs_val = context.ints().Get(
|
||||
context.insts().GetAs<SemIR::IntLiteral>(rhs_id).int_id);
|
||||
|
||||
bool result;
|
||||
switch (builtin_kind) {
|
||||
case SemIR::BuiltinFunctionKind::IntEq:
|
||||
result = (lhs_val == rhs_val);
|
||||
break;
|
||||
case SemIR::BuiltinFunctionKind::IntNeq:
|
||||
result = (lhs_val != rhs_val);
|
||||
break;
|
||||
default:
|
||||
CARBON_FATAL() << "Unexpected operation kind.";
|
||||
}
|
||||
|
||||
return MakeConstantResult(
|
||||
context,
|
||||
SemIR::BoolLiteral{bool_type_id, SemIR::BoolValue::FromBool(result)},
|
||||
Phase::Template);
|
||||
}
|
||||
|
||||
static auto PerformBuiltinCall(Context& context, SemIRLocation loc,
|
||||
SemIR::Call /*call*/,
|
||||
SemIR::Call call,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids,
|
||||
Phase phase) -> SemIR::ConstantId {
|
||||
@@ -295,28 +421,38 @@ static auto PerformBuiltinCall(Context& context, SemIRLocation loc,
|
||||
case SemIR::BuiltinFunctionKind::None:
|
||||
CARBON_FATAL() << "Not a builtin function.";
|
||||
|
||||
case SemIR::BuiltinFunctionKind::IntAdd: {
|
||||
// Unary integer -> integer operations.
|
||||
case SemIR::BuiltinFunctionKind::IntNegate: {
|
||||
// TODO: Complement.
|
||||
if (phase != Phase::Template) {
|
||||
break;
|
||||
}
|
||||
auto lhs = context.insts().GetAs<SemIR::IntLiteral>(arg_ids[0]);
|
||||
auto rhs = context.insts().GetAs<SemIR::IntLiteral>(arg_ids[1]);
|
||||
// TODO: Integer values should be stored in the correct bit width for
|
||||
// their types. For now we assume i32.
|
||||
auto lhs_val = context.ints().Get(lhs.int_id).sextOrTrunc(32);
|
||||
auto rhs_val = context.ints().Get(rhs.int_id).sextOrTrunc(32);
|
||||
bool overflow = false;
|
||||
auto result = context.ints().Add(lhs_val.sadd_ov(rhs_val, overflow));
|
||||
if (overflow) {
|
||||
CARBON_DIAGNOSTIC(CompileTimeIntegerOverflow, Error,
|
||||
"Integer overflow in calculation {0} + {1}.",
|
||||
llvm::APSInt, llvm::APSInt);
|
||||
context.emitter().Emit(loc, CompileTimeIntegerOverflow,
|
||||
llvm::APSInt(lhs_val, false),
|
||||
llvm::APSInt(rhs_val, false));
|
||||
return PerformBuiltinUnaryIntOp(context, loc, builtin_kind, arg_ids[0]);
|
||||
}
|
||||
|
||||
// Homogeneous binary integer -> integer operations.
|
||||
case SemIR::BuiltinFunctionKind::IntAdd:
|
||||
case SemIR::BuiltinFunctionKind::IntSub:
|
||||
case SemIR::BuiltinFunctionKind::IntMul:
|
||||
case SemIR::BuiltinFunctionKind::IntDiv:
|
||||
case SemIR::BuiltinFunctionKind::IntMod: {
|
||||
// TODO: Bitwise operators.
|
||||
if (phase != Phase::Template) {
|
||||
break;
|
||||
}
|
||||
return MakeConstantResult(context, SemIR::IntLiteral{lhs.type_id, result},
|
||||
phase);
|
||||
return PerformBuiltinBinaryIntOp(context, loc, builtin_kind, arg_ids[0],
|
||||
arg_ids[1]);
|
||||
}
|
||||
|
||||
// Integer comparisons.
|
||||
case SemIR::BuiltinFunctionKind::IntEq:
|
||||
case SemIR::BuiltinFunctionKind::IntNeq: {
|
||||
// TODO: Relational comparisons.
|
||||
if (phase != Phase::Template) {
|
||||
break;
|
||||
}
|
||||
return PerformBuiltinIntComparison(context, builtin_kind, arg_ids[0],
|
||||
arg_ids[1], call.type_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,9 +519,17 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
|
||||
// TODO: We should check that the size of the resulting array type
|
||||
// fits in 64 bits, not just that the bound does. Should we use a
|
||||
// 32-bit limit for 32-bit targets?
|
||||
// TODO: Also check for a negative bound, once that's something we
|
||||
// can represent.
|
||||
const auto& bound_val = context.ints().Get(int_bound->int_id);
|
||||
if (bound_val.isNegative()) {
|
||||
// TODO: Skip this test if the bound type is unsigned.
|
||||
CARBON_DIAGNOSTIC(ArrayBoundNegative, Error,
|
||||
"Array bound of {0} is negative.",
|
||||
llvm::APSInt);
|
||||
context.emitter().Emit(
|
||||
bound_id, ArrayBoundNegative,
|
||||
llvm::APSInt(bound_val, /*isUnsigned=*/false));
|
||||
return false;
|
||||
}
|
||||
if (bound_val.getActiveBits() > 64) {
|
||||
CARBON_DIAGNOSTIC(ArrayBoundTooLarge, Error,
|
||||
"Array bound of {0} is too large.",
|
||||
|
||||
+18
-8
@@ -4,27 +4,37 @@
|
||||
//
|
||||
// AUTOUPDATE
|
||||
|
||||
// TODO: Once we supoprt negating integer literals, check that we reject a
|
||||
// negative array bound.
|
||||
fn Negate(n: i32) -> i32 = "int.negate";
|
||||
|
||||
// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+3]]:14: ERROR: Semantics TODO: `missing or invalid operator interface`.
|
||||
// CHECK:STDERR: var a: [i32; -1];
|
||||
// CHECK:STDERR: ^~
|
||||
var a: [i32; -1];
|
||||
// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+3]]:14: ERROR: Array bound of -1 is negative.
|
||||
// CHECK:STDERR: var a: [i32; Negate(1)];
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
var a: [i32; Negate(1)];
|
||||
|
||||
// CHECK:STDOUT: --- fail_bound_negative.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 1 [template]
|
||||
// CHECK:STDOUT: %.2: i32 = int_literal 4294967295 [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Negate = %Negate
|
||||
// CHECK:STDOUT: .a = %a
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.loc13_15: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc13_16: type = array_type <error>, i32 [template = <error>]
|
||||
// CHECK:STDOUT: %Negate: <function> = fn_decl @Negate [template] {
|
||||
// CHECK:STDOUT: %n.loc7_11.1: i32 = param n
|
||||
// CHECK:STDOUT: @Negate.%n: i32 = bind_name n, %n.loc7_11.1
|
||||
// CHECK:STDOUT: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate.ref: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc12_21: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc12_20: init i32 = call %Negate.ref(%.loc12_21) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc12_23: type = array_type %.loc12_20, i32 [template = <error>]
|
||||
// CHECK:STDOUT: %a.var: ref <error> = var a
|
||||
// CHECK:STDOUT: %a: ref <error> = bind_name a, %a.var
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Negate(%n: i32) -> i32 = "int.negate";
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+16
-9
@@ -9,6 +9,7 @@
|
||||
fn Add(a: i32, b: i32) -> i32 = "int.add";
|
||||
|
||||
var arr: [i32; Add(1, 2)];
|
||||
let arr_p: [i32; 3]* = &arr;
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> i32 {
|
||||
return Add(a, b);
|
||||
@@ -114,12 +115,18 @@ let b: i32 = Add(0x7FFFFFFF, 1);
|
||||
// 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: <function> = fn_decl @RuntimeCall [template] {
|
||||
// CHECK:STDOUT: %a.loc6_16.1: i32 = param a
|
||||
// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc6_16.1
|
||||
// CHECK:STDOUT: %b.loc6_24.1: i32 = param b
|
||||
// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc6_24.1
|
||||
// CHECK:STDOUT: %return.var.loc6: ref i32 = var <return slot>
|
||||
// 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: %return.var.loc7: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -130,10 +137,10 @@ let b: i32 = Add(0x7FFFFFFF, 1);
|
||||
// CHECK:STDOUT: %Add.ref: <function> = 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: %.loc7_13.1: init i32 = call %Add.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc7_19: i32 = value_of_initializer %.loc7_13.1
|
||||
// CHECK:STDOUT: %.loc7_13.2: i32 = converted %.loc7_13.1, %.loc7_19
|
||||
// CHECK:STDOUT: return %.loc7_13.2
|
||||
// CHECK:STDOUT: %.loc8_13.1: init i32 = call %Add.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc8_19: i32 = value_of_initializer %.loc8_13.1
|
||||
// CHECK:STDOUT: %.loc8_13.2: i32 = converted %.loc8_13.1, %.loc8_19
|
||||
// CHECK:STDOUT: return %.loc8_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_bad_decl.carbon
|
||||
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
// 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.div";
|
||||
|
||||
var arr: [i32; Div(3, 2)];
|
||||
let arr_p: [i32; 1]* = &arr;
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> i32 {
|
||||
return Div(a, b);
|
||||
}
|
||||
|
||||
// --- fail_overflow.carbon
|
||||
|
||||
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";
|
||||
|
||||
// -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 overflows.
|
||||
// CHECK:STDERR: fail_overflow.carbon:[[@LINE+4]]:14: ERROR: Integer overflow in calculation -2147483648 / -1.
|
||||
// CHECK:STDERR: let c: i32 = Div(Sub(Negate(0x7FFF_FFFF), 1), Negate(1));
|
||||
// CHECK:STDERR: ^~~~
|
||||
// CHECK:STDERR:
|
||||
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.div";
|
||||
|
||||
// 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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Div = %Div
|
||||
// CHECK:STDOUT: .arr = %arr
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div: <function> = 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: %return.var.loc2: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div.ref: <function> = 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: <function> = 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: %return.var.loc7: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Div.ref: <function> = 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.1: init i32 = call %Div.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc8_19: i32 = value_of_initializer %.loc8_13.1
|
||||
// CHECK:STDOUT: %.loc8_13.2: i32 = converted %.loc8_13.1, %.loc8_19
|
||||
// CHECK:STDOUT: return %.loc8_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_overflow.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template]
|
||||
// CHECK:STDOUT: %.2: i32 = int_literal 2147483649 [template]
|
||||
// CHECK:STDOUT: %.3: i32 = int_literal 1 [template]
|
||||
// CHECK:STDOUT: %.4: i32 = int_literal 4294967295 [template]
|
||||
// CHECK:STDOUT: %.5: i32 = int_literal 2147483648 [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Div = %Div
|
||||
// CHECK:STDOUT: .Sub = %Sub
|
||||
// CHECK:STDOUT: .Negate = %Negate
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div: <function> = 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: %return.var.loc4: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub: <function> = 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: %return.var.loc5: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate: <function> = 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: %return.var.loc6: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div.ref.loc9: <function> = name_ref Div, %Div [template = %Div]
|
||||
// CHECK:STDOUT: %Negate.ref.loc9_18: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc9_25: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc9_24.1: init i32 = call %Negate.ref.loc9_18(%.loc9_25) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %Negate.ref.loc9_39: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc9_46: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc9_45.1: init i32 = call %Negate.ref.loc9_39(%.loc9_46) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_17.1: i32 = value_of_initializer %.loc9_24.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc9_24.2: i32 = converted %.loc9_24.1, %.loc9_17.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc9_17.2: i32 = value_of_initializer %.loc9_45.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_45.2: i32 = converted %.loc9_45.1, %.loc9_17.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_17.3: init i32 = call %Div.ref.loc9(%.loc9_24.2, %.loc9_45.2) [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc9_49: i32 = value_of_initializer %.loc9_17.3 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc9_17.4: i32 = converted %.loc9_17.3, %.loc9_49 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %a.loc9: i32 = bind_name a, %.loc9_17.4
|
||||
// CHECK:STDOUT: %Div.ref.loc12: <function> = name_ref Div, %Div [template = %Div]
|
||||
// CHECK:STDOUT: %Sub.ref.loc12: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Negate.ref.loc12: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc12_29: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc12_28.1: 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.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc12_28.2: i32 = converted %.loc12_28.1, %.loc12_21.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc12_21.2: init i32 = call %Sub.ref.loc12(%.loc12_28.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.2 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_21.3: i32 = converted %.loc12_21.2, %.loc12_17.1 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_17.2: init i32 = call %Div.ref.loc12(%.loc12_21.3, %.loc12_47) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_49: i32 = value_of_initializer %.loc12_17.2 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_17.3: i32 = converted %.loc12_17.2, %.loc12_49 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %b.loc12: i32 = bind_name b, %.loc12_17.3
|
||||
// CHECK:STDOUT: %Div.ref.loc19: <function> = name_ref Div, %Div [template = %Div]
|
||||
// CHECK:STDOUT: %Sub.ref.loc19: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Negate.ref.loc19_22: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc19_29: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc19_28.1: init i32 = call %Negate.ref.loc19_22(%.loc19_29) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc19_43: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc19_21.1: i32 = value_of_initializer %.loc19_28.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc19_28.2: i32 = converted %.loc19_28.1, %.loc19_21.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc19_21.2: init i32 = call %Sub.ref.loc19(%.loc19_28.2, %.loc19_43) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %Negate.ref.loc19_47: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc19_54: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc19_53.1: init i32 = call %Negate.ref.loc19_47(%.loc19_54) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc19_17.1: i32 = value_of_initializer %.loc19_21.2 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc19_21.3: i32 = converted %.loc19_21.2, %.loc19_17.1 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc19_17.2: i32 = value_of_initializer %.loc19_53.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc19_53.2: i32 = converted %.loc19_53.1, %.loc19_17.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc19_17.3: init i32 = call %Div.ref.loc19(%.loc19_21.3, %.loc19_53.2) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc19_57: i32 = value_of_initializer %.loc19_17.3 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc19_17.4: i32 = converted %.loc19_17.3, %.loc19_57 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %c: i32 = bind_name c, %.loc19_17.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate";
|
||||
// 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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Div = %Div
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div: <function> = 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: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Div.ref.loc10: <function> = 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.1: init i32 = call %Div.ref.loc10(%.loc10_18, %.loc10_21) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc10_23: i32 = value_of_initializer %.loc10_17.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc10_17.2: i32 = converted %.loc10_17.1, %.loc10_23 [template = <error>]
|
||||
// CHECK:STDOUT: %a.loc10: i32 = bind_name a, %.loc10_17.2
|
||||
// CHECK:STDOUT: %Div.ref.loc15: <function> = 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.1: init i32 = call %Div.ref.loc15(%.loc15_18, %.loc15_21) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc15_23: i32 = value_of_initializer %.loc15_17.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc15_17.2: i32 = converted %.loc15_17.1, %.loc15_23 [template = <error>]
|
||||
// CHECK:STDOUT: %b.loc15: i32 = bind_name b, %.loc15_17.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Div(%a: i32, %b: i32) -> i32 = "int.div";
|
||||
// CHECK:STDOUT:
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
// 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_eq.carbon
|
||||
|
||||
fn Eq(a: i32, b: i32) -> bool = "int.eq";
|
||||
|
||||
// TODO: Use a test that will fail to compile if we get the wrong value.
|
||||
let b_true: bool = Eq(1, 1);
|
||||
let b_false: bool = Eq(1, 2);
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> bool {
|
||||
return Eq(a, b);
|
||||
}
|
||||
|
||||
// --- fail_bad_decl.carbon
|
||||
|
||||
package FailBadDecl api;
|
||||
|
||||
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "int.eq".
|
||||
// CHECK:STDERR: fn WrongResult(a: i32, b: i32) -> i32 = "int.eq";
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
fn WrongResult(a: i32, b: i32) -> i32 = "int.eq";
|
||||
|
||||
// CHECK:STDOUT: --- int_eq.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 1 [template]
|
||||
// CHECK:STDOUT: %.2: bool = bool_literal true [template]
|
||||
// CHECK:STDOUT: %.3: i32 = int_literal 2 [template]
|
||||
// CHECK:STDOUT: %.4: bool = bool_literal false [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Eq = %Eq
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Eq: <function> = fn_decl @Eq [template] {
|
||||
// CHECK:STDOUT: %a.loc2_7.1: i32 = param a
|
||||
// CHECK:STDOUT: @Eq.%a: i32 = bind_name a, %a.loc2_7.1
|
||||
// CHECK:STDOUT: %b.loc2_15.1: i32 = param b
|
||||
// CHECK:STDOUT: @Eq.%b: i32 = bind_name b, %b.loc2_15.1
|
||||
// CHECK:STDOUT: %return.var.loc2: ref bool = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Eq.ref.loc5: <function> = name_ref Eq, %Eq [template = %Eq]
|
||||
// CHECK:STDOUT: %.loc5_23: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc5_26: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc5_22.1: init bool = call %Eq.ref.loc5(%.loc5_23, %.loc5_26) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc5_28: bool = value_of_initializer %.loc5_22.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc5_22.2: bool = converted %.loc5_22.1, %.loc5_28 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %b_true: bool = bind_name b_true, %.loc5_22.2
|
||||
// CHECK:STDOUT: %Eq.ref.loc6: <function> = name_ref Eq, %Eq [template = %Eq]
|
||||
// CHECK:STDOUT: %.loc6_24: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc6_27: i32 = int_literal 2 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc6_23.1: init bool = call %Eq.ref.loc6(%.loc6_24, %.loc6_27) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc6_29: bool = value_of_initializer %.loc6_23.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc6_23.2: bool = converted %.loc6_23.1, %.loc6_29 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %b_false: bool = bind_name b_false, %.loc6_23.2
|
||||
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
|
||||
// CHECK:STDOUT: %a.loc8_16.1: i32 = param a
|
||||
// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc8_16.1
|
||||
// CHECK:STDOUT: %b.loc8_24.1: i32 = param b
|
||||
// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc8_24.1
|
||||
// CHECK:STDOUT: %return.var.loc8: ref bool = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Eq(%a: i32, %b: i32) -> bool = "int.eq";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Eq.ref: <function> = name_ref Eq, file.%Eq [template = file.%Eq]
|
||||
// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a
|
||||
// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b
|
||||
// CHECK:STDOUT: %.loc9_12.1: init bool = call %Eq.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc9_18: bool = value_of_initializer %.loc9_12.1
|
||||
// CHECK:STDOUT: %.loc9_12.2: bool = converted %.loc9_12.1, %.loc9_18
|
||||
// CHECK:STDOUT: return %.loc9_12.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_bad_decl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .WrongResult = %WrongResult
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %WrongResult: <function> = fn_decl @WrongResult [template] {
|
||||
// CHECK:STDOUT: %a.loc7_16.1: i32 = param a
|
||||
// CHECK:STDOUT: @WrongResult.%a: i32 = bind_name a, %a.loc7_16.1
|
||||
// CHECK:STDOUT: %b.loc7_24.1: i32 = param b
|
||||
// CHECK:STDOUT: @WrongResult.%b: i32 = bind_name b, %b.loc7_24.1
|
||||
// CHECK:STDOUT: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @WrongResult(%a: i32, %b: i32) -> i32;
|
||||
// CHECK:STDOUT:
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
// 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.mod";
|
||||
|
||||
var arr: [i32; Mod(5, 3)];
|
||||
let arr_p: [i32; 2]* = &arr;
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> i32 {
|
||||
return Mod(a, b);
|
||||
}
|
||||
|
||||
// --- fail_overflow.carbon
|
||||
|
||||
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";
|
||||
|
||||
// -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 overflows, so -0x8000_0000 % -1 is disallowed, even though
|
||||
// its result is representable.
|
||||
// CHECK:STDERR: fail_overflow.carbon:[[@LINE+4]]:14: ERROR: Integer overflow in calculation -2147483648 % -1.
|
||||
// CHECK:STDERR: let c: i32 = Mod(Sub(Negate(0x7FFF_FFFF), 1), Negate(1));
|
||||
// CHECK:STDERR: ^~~~
|
||||
// CHECK:STDERR:
|
||||
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.mod";
|
||||
|
||||
// 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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Mod = %Mod
|
||||
// CHECK:STDOUT: .arr = %arr
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod: <function> = 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: %return.var.loc2: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod.ref: <function> = 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: <function> = 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: %return.var.loc7: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Mod.ref: <function> = 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.1: init i32 = call %Mod.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc8_19: i32 = value_of_initializer %.loc8_13.1
|
||||
// CHECK:STDOUT: %.loc8_13.2: i32 = converted %.loc8_13.1, %.loc8_19
|
||||
// CHECK:STDOUT: return %.loc8_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_overflow.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template]
|
||||
// CHECK:STDOUT: %.2: i32 = int_literal 2147483649 [template]
|
||||
// CHECK:STDOUT: %.3: i32 = int_literal 1 [template]
|
||||
// CHECK:STDOUT: %.4: i32 = int_literal 4294967295 [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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Mod = %Mod
|
||||
// CHECK:STDOUT: .Sub = %Sub
|
||||
// CHECK:STDOUT: .Negate = %Negate
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod: <function> = 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: %return.var.loc4: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub: <function> = 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: %return.var.loc5: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate: <function> = 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: %return.var.loc6: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod.ref.loc9: <function> = name_ref Mod, %Mod [template = %Mod]
|
||||
// CHECK:STDOUT: %Negate.ref.loc9_18: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc9_25: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc9_24.1: init i32 = call %Negate.ref.loc9_18(%.loc9_25) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %Negate.ref.loc9_39: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc9_46: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc9_45.1: init i32 = call %Negate.ref.loc9_39(%.loc9_46) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_17.1: i32 = value_of_initializer %.loc9_24.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc9_24.2: i32 = converted %.loc9_24.1, %.loc9_17.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc9_17.2: i32 = value_of_initializer %.loc9_45.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_45.2: i32 = converted %.loc9_45.1, %.loc9_17.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc9_17.3: init i32 = call %Mod.ref.loc9(%.loc9_24.2, %.loc9_45.2) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc9_49: i32 = value_of_initializer %.loc9_17.3 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc9_17.4: i32 = converted %.loc9_17.3, %.loc9_49 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %a.loc9: i32 = bind_name a, %.loc9_17.4
|
||||
// CHECK:STDOUT: %Mod.ref.loc12: <function> = name_ref Mod, %Mod [template = %Mod]
|
||||
// CHECK:STDOUT: %Sub.ref.loc12: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Negate.ref.loc12: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc12_29: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc12_28.1: 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.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc12_28.2: i32 = converted %.loc12_28.1, %.loc12_21.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc12_21.2: init i32 = call %Sub.ref.loc12(%.loc12_28.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.2 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc12_21.3: i32 = converted %.loc12_21.2, %.loc12_17.1 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc12_17.2: init i32 = call %Mod.ref.loc12(%.loc12_21.3, %.loc12_47) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_49: i32 = value_of_initializer %.loc12_17.2 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc12_17.3: i32 = converted %.loc12_17.2, %.loc12_49 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %b.loc12: i32 = bind_name b, %.loc12_17.3
|
||||
// CHECK:STDOUT: %Mod.ref.loc20: <function> = name_ref Mod, %Mod [template = %Mod]
|
||||
// CHECK:STDOUT: %Sub.ref.loc20: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Negate.ref.loc20_22: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc20_29: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc20_28.1: init i32 = call %Negate.ref.loc20_22(%.loc20_29) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc20_43: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc20_21.1: i32 = value_of_initializer %.loc20_28.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc20_28.2: i32 = converted %.loc20_28.1, %.loc20_21.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc20_21.2: init i32 = call %Sub.ref.loc20(%.loc20_28.2, %.loc20_43) [template = constants.%.6]
|
||||
// CHECK:STDOUT: %Negate.ref.loc20_47: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc20_54: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc20_53.1: init i32 = call %Negate.ref.loc20_47(%.loc20_54) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc20_17.1: i32 = value_of_initializer %.loc20_21.2 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc20_21.3: i32 = converted %.loc20_21.2, %.loc20_17.1 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc20_17.2: i32 = value_of_initializer %.loc20_53.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc20_53.2: i32 = converted %.loc20_53.1, %.loc20_17.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc20_17.3: init i32 = call %Mod.ref.loc20(%.loc20_21.3, %.loc20_53.2) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc20_57: i32 = value_of_initializer %.loc20_17.3 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc20_17.4: i32 = converted %.loc20_17.3, %.loc20_57 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %c: i32 = bind_name c, %.loc20_17.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate";
|
||||
// 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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Mod = %Mod
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod: <function> = 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: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mod.ref.loc12: <function> = 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.1: init i32 = call %Mod.ref.loc12(%.loc12_18, %.loc12_21) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc12_23: i32 = value_of_initializer %.loc12_17.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc12_17.2: i32 = converted %.loc12_17.1, %.loc12_23 [template = <error>]
|
||||
// CHECK:STDOUT: %a.loc12: i32 = bind_name a, %.loc12_17.2
|
||||
// CHECK:STDOUT: %Mod.ref.loc17: <function> = 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.1: init i32 = call %Mod.ref.loc17(%.loc17_18, %.loc17_21) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc17_23: i32 = value_of_initializer %.loc17_17.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc17_17.2: i32 = converted %.loc17_17.1, %.loc17_23 [template = <error>]
|
||||
// CHECK:STDOUT: %b.loc17: i32 = bind_name b, %.loc17_17.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Mod(%a: i32, %b: i32) -> i32 = "int.mod";
|
||||
// CHECK:STDOUT:
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
// 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.mul";
|
||||
|
||||
var arr: [i32; Mul(3, 2)];
|
||||
let arr_p: [i32; 6]* = &arr;
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> i32 {
|
||||
return Mul(a, b);
|
||||
}
|
||||
|
||||
// --- fail_overflow.carbon
|
||||
|
||||
package FailOverflow api;
|
||||
|
||||
fn Mul(a: i32, b: i32) -> i32 = "int.mul";
|
||||
|
||||
let a: i32 = Mul(0x7FFF, 0x10000);
|
||||
// CHECK:STDERR: fail_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer overflow in calculation 32768 * 65536.
|
||||
// CHECK:STDERR: let b: i32 = Mul(0x8000, 0x10000);
|
||||
// CHECK:STDERR: ^~~~
|
||||
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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Mul = %Mul
|
||||
// CHECK:STDOUT: .arr = %arr
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mul: <function> = 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: %return.var.loc2: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mul.ref: <function> = 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: <function> = 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: %return.var.loc7: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.mul";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Mul.ref: <function> = 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.1: init i32 = call %Mul.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc8_19: i32 = value_of_initializer %.loc8_13.1
|
||||
// CHECK:STDOUT: %.loc8_13.2: i32 = converted %.loc8_13.1, %.loc8_19
|
||||
// CHECK:STDOUT: return %.loc8_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Mul = %Mul
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mul: <function> = 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: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Mul.ref.loc6: <function> = 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.1: init i32 = call %Mul.ref.loc6(%.loc6_18, %.loc6_26) [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc6_34: i32 = value_of_initializer %.loc6_17.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc6_17.2: i32 = converted %.loc6_17.1, %.loc6_34 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %a.loc6: i32 = bind_name a, %.loc6_17.2
|
||||
// CHECK:STDOUT: %Mul.ref.loc10: <function> = name_ref Mul, %Mul [template = %Mul]
|
||||
// CHECK:STDOUT: %.loc10_18: i32 = int_literal 32768 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc10_26: i32 = int_literal 65536 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc10_17.1: init i32 = call %Mul.ref.loc10(%.loc10_18, %.loc10_26) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc10_34: i32 = value_of_initializer %.loc10_17.1 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc10_17.2: i32 = converted %.loc10_17.1, %.loc10_34 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %b.loc10: i32 = bind_name b, %.loc10_17.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Mul(%a: i32, %b: i32) -> i32 = "int.mul";
|
||||
// CHECK:STDOUT:
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
// 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.negate";
|
||||
|
||||
var arr: [i32; Negate(Negate(1))];
|
||||
let arr_p: [i32; 1]* = &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.negate".
|
||||
// CHECK:STDERR: fn TooFew() -> i32 = "int.negate";
|
||||
// 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";
|
||||
// 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";
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn BadReturnType(a: i32) -> bool = "int.negate";
|
||||
fn JustRight(a: i32) -> i32 = "int.negate";
|
||||
|
||||
// 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.negate";
|
||||
// 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.negate";
|
||||
// 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.negate";
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
return TooMany(a, b, c);
|
||||
}
|
||||
|
||||
fn RuntimeCallBadReturnType(a: i32, b: i32) -> bool {
|
||||
// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]: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.negate";
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
return BadReturnType(a, b);
|
||||
}
|
||||
|
||||
// --- fail_overflow.carbon
|
||||
|
||||
package FailOverflow api;
|
||||
|
||||
fn Negate(a: i32) -> i32 = "int.negate";
|
||||
fn Sub(a: i32, b: i32) -> i32 = "int.sub";
|
||||
|
||||
// -(-INT_MAX) is INT_MAX.
|
||||
let a: i32 = Negate(Negate(0x7FFFFFFF));
|
||||
|
||||
// -(-INT_MAX - 1) is too large for i32.
|
||||
// CHECK:STDERR: fail_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer overflow in negation of -2147483648.
|
||||
// CHECK:STDERR: let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1));
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1));
|
||||
|
||||
// CHECK:STDOUT: --- int_negate.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 1 [template]
|
||||
// CHECK:STDOUT: %.2: i32 = int_literal 4294967295 [template]
|
||||
// CHECK:STDOUT: %.3: type = array_type %.1, i32 [template]
|
||||
// CHECK:STDOUT: %.4: type = ptr_type [i32; 1] [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Negate = %Negate
|
||||
// CHECK:STDOUT: .arr = %arr
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate: <function> = 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: %return.var.loc2: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate.ref.loc4_16: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %Negate.ref.loc4_23: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc4_30: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc4_29.1: init i32 = call %Negate.ref.loc4_23(%.loc4_30) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc4_22.1: i32 = value_of_initializer %.loc4_29.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc4_29.2: i32 = converted %.loc4_29.1, %.loc4_22.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc4_22.2: init i32 = call %Negate.ref.loc4_16(%.loc4_29.2) [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc4_33: type = array_type %.loc4_22.2, i32 [template = constants.%.3]
|
||||
// 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.%.1]
|
||||
// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 1] [template = constants.%.4]
|
||||
// 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: %Negate.ref.loc7: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc7_21: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc7_20.1: init i32 = call %Negate.ref.loc7(%.loc7_21) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc7_23: i32 = value_of_initializer %.loc7_20.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc7_20.2: i32 = converted %.loc7_20.1, %.loc7_23 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %n: i32 = bind_name n, %.loc7_20.2
|
||||
// CHECK:STDOUT: %RuntimeCall: <function> = 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: %return.var.loc9: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Negate.ref: <function> = name_ref Negate, file.%Negate [template = file.%Negate]
|
||||
// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a
|
||||
// CHECK:STDOUT: %.loc10_16.1: init i32 = call %Negate.ref(%a.ref)
|
||||
// CHECK:STDOUT: %.loc10_19: i32 = value_of_initializer %.loc10_16.1
|
||||
// CHECK:STDOUT: %.loc10_16.2: i32 = converted %.loc10_16.1, %.loc10_19
|
||||
// CHECK:STDOUT: return %.loc10_16.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> = namespace [template] {
|
||||
// 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: %TooFew: <function> = fn_decl @TooFew [template] {
|
||||
// CHECK:STDOUT: %return.var.loc8: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %TooMany: <function> = 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: %return.var.loc13: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %BadReturnType: <function> = 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: %return.var.loc18: ref bool = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %JustRight: <function> = 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: %return.var.loc19: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, %TooFew [template = %TooFew]
|
||||
// CHECK:STDOUT: %.loc25: init i32 = call %TooFew.ref()
|
||||
// CHECK:STDOUT: %too_few.var: ref <error> = var too_few
|
||||
// CHECK:STDOUT: %too_few: ref <error> = bind_name too_few, %too_few.var
|
||||
// CHECK:STDOUT: %TooMany.ref: <function> = 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 <error> = var too_many
|
||||
// CHECK:STDOUT: %too_many: ref <error> = bind_name too_many, %too_many.var
|
||||
// CHECK:STDOUT: %BadReturnType.ref: <function> = 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 <error> = var bad_return_type
|
||||
// CHECK:STDOUT: %bad_return_type: ref <error> = bind_name bad_return_type, %bad_return_type.var
|
||||
// CHECK:STDOUT: %JustRight.ref: <function> = 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(<invalid>) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc44_36: type = array_type %.loc44_30, i32 [template = <error>]
|
||||
// CHECK:STDOUT: %bad_call.var: ref <error> = var bad_call
|
||||
// CHECK:STDOUT: %bad_call: ref <error> = bind_name bad_call, %bad_call.var
|
||||
// CHECK:STDOUT: %RuntimeCallTooFew: <function> = 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: %return.var.loc46: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %RuntimeCallTooMany: <function> = 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: %return.var.loc57: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %RuntimeCallBadReturnType: <function> = 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: %return.var.loc68: ref bool = var <return slot>
|
||||
// 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.negate";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %TooFew.ref: <function> = name_ref TooFew, file.%TooFew [template = file.%TooFew]
|
||||
// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a
|
||||
// CHECK:STDOUT: %.loc54_16.1: init i32 = call %TooFew.ref(<invalid>) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc54_19: i32 = value_of_initializer %.loc54_16.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc54_16.2: i32 = converted %.loc54_16.1, %.loc54_19 [template = <error>]
|
||||
// CHECK:STDOUT: return %.loc54_16.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: i32, %b: i32, %c: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %TooMany.ref: <function> = 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.1: init i32 = call %TooMany.ref(<invalid>) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc65_26: i32 = value_of_initializer %.loc65_17.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc65_17.2: i32 = converted %.loc65_17.1, %.loc65_26 [template = <error>]
|
||||
// CHECK:STDOUT: return %.loc65_17.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: i32, %b: i32) -> bool {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %BadReturnType.ref: <function> = 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: %.loc76_23.1: init bool = call %BadReturnType.ref(<invalid>) [template = <error>]
|
||||
// CHECK:STDOUT: %.loc76_29: bool = value_of_initializer %.loc76_23.1 [template = <error>]
|
||||
// CHECK:STDOUT: %.loc76_23.2: bool = converted %.loc76_23.1, %.loc76_29 [template = <error>]
|
||||
// CHECK:STDOUT: return %.loc76_23.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_overflow.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %.1: i32 = int_literal 2147483647 [template]
|
||||
// CHECK:STDOUT: %.2: i32 = int_literal 2147483649 [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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Negate = %Negate
|
||||
// CHECK:STDOUT: .Sub = %Sub
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate: <function> = 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: %return.var.loc4: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub: <function> = 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: %return.var.loc5: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Negate.ref.loc8_14: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %Negate.ref.loc8_21: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc8_28: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc8_27.1: init i32 = call %Negate.ref.loc8_21(%.loc8_28) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc8_20.1: i32 = value_of_initializer %.loc8_27.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc8_27.2: i32 = converted %.loc8_27.1, %.loc8_20.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc8_20.2: init i32 = call %Negate.ref.loc8_14(%.loc8_27.2) [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc8_40: i32 = value_of_initializer %.loc8_20.2 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc8_20.3: i32 = converted %.loc8_20.2, %.loc8_40 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %a.loc8: i32 = bind_name a, %.loc8_20.3
|
||||
// CHECK:STDOUT: %Negate.ref.loc14_14: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %Sub.ref: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Negate.ref.loc14_25: <function> = name_ref Negate, %Negate [template = %Negate]
|
||||
// CHECK:STDOUT: %.loc14_32: i32 = int_literal 2147483647 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc14_31.1: init i32 = call %Negate.ref.loc14_25(%.loc14_32) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc14_45: i32 = int_literal 1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc14_24.1: i32 = value_of_initializer %.loc14_31.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc14_31.2: i32 = converted %.loc14_31.1, %.loc14_24.1 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc14_24.2: init i32 = call %Sub.ref(%.loc14_31.2, %.loc14_45) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc14_20.1: i32 = value_of_initializer %.loc14_24.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc14_24.3: i32 = converted %.loc14_24.2, %.loc14_20.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc14_20.2: init i32 = call %Negate.ref.loc14_14(%.loc14_24.3) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc14_48: i32 = value_of_initializer %.loc14_20.2 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc14_20.3: i32 = converted %.loc14_20.2, %.loc14_48 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %b.loc14: i32 = bind_name b, %.loc14_20.3
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub";
|
||||
// CHECK:STDOUT:
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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_neq.carbon
|
||||
|
||||
fn Neq(a: i32, b: i32) -> bool = "int.neq";
|
||||
|
||||
// TODO: Use a test that will fail to compile if we get the wrong value.
|
||||
let b_true: bool = Neq(1, 2);
|
||||
let b_false: bool = Neq(1, 1);
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> bool {
|
||||
return Neq(a, b);
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- int_neq.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: bool = bool_literal true [template]
|
||||
// CHECK:STDOUT: %.4: bool = bool_literal false [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .Neq = %Neq
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Neq: <function> = fn_decl @Neq [template] {
|
||||
// CHECK:STDOUT: %a.loc2_8.1: i32 = param a
|
||||
// CHECK:STDOUT: @Neq.%a: i32 = bind_name a, %a.loc2_8.1
|
||||
// CHECK:STDOUT: %b.loc2_16.1: i32 = param b
|
||||
// CHECK:STDOUT: @Neq.%b: i32 = bind_name b, %b.loc2_16.1
|
||||
// CHECK:STDOUT: %return.var.loc2: ref bool = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Neq.ref.loc5: <function> = name_ref Neq, %Neq [template = %Neq]
|
||||
// CHECK:STDOUT: %.loc5_24: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc5_27: i32 = int_literal 2 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc5_23.1: init bool = call %Neq.ref.loc5(%.loc5_24, %.loc5_27) [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc5_29: bool = value_of_initializer %.loc5_23.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc5_23.2: bool = converted %.loc5_23.1, %.loc5_29 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %b_true: bool = bind_name b_true, %.loc5_23.2
|
||||
// CHECK:STDOUT: %Neq.ref.loc6: <function> = name_ref Neq, %Neq [template = %Neq]
|
||||
// CHECK:STDOUT: %.loc6_25: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc6_28: i32 = int_literal 1 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc6_24.1: init bool = call %Neq.ref.loc6(%.loc6_25, %.loc6_28) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc6_30: bool = value_of_initializer %.loc6_24.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc6_24.2: bool = converted %.loc6_24.1, %.loc6_30 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %b_false: bool = bind_name b_false, %.loc6_24.2
|
||||
// CHECK:STDOUT: %RuntimeCall: <function> = fn_decl @RuntimeCall [template] {
|
||||
// CHECK:STDOUT: %a.loc8_16.1: i32 = param a
|
||||
// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc8_16.1
|
||||
// CHECK:STDOUT: %b.loc8_24.1: i32 = param b
|
||||
// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc8_24.1
|
||||
// CHECK:STDOUT: %return.var.loc8: ref bool = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Neq(%a: i32, %b: i32) -> bool = "int.neq";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Neq.ref: <function> = name_ref Neq, file.%Neq [template = file.%Neq]
|
||||
// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a
|
||||
// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b
|
||||
// CHECK:STDOUT: %.loc9_13.1: init bool = call %Neq.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc9_19: bool = value_of_initializer %.loc9_13.1
|
||||
// CHECK:STDOUT: %.loc9_13.2: bool = converted %.loc9_13.1, %.loc9_19
|
||||
// CHECK:STDOUT: return %.loc9_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
// 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.sub";
|
||||
|
||||
var arr: [i32; Sub(3, 2)];
|
||||
let arr_p: [i32; 1]* = &arr;
|
||||
|
||||
fn RuntimeCall(a: i32, b: i32) -> i32 {
|
||||
return Sub(a, b);
|
||||
}
|
||||
|
||||
// --- fail_overflow.carbon
|
||||
|
||||
package FailOverflow api;
|
||||
|
||||
fn Sub(a: i32, b: i32) -> i32 = "int.sub";
|
||||
|
||||
let a: i32 = Sub(0, 0x7FFFFFFF);
|
||||
let b: i32 = Sub(Sub(0, 0x7FFFFFFF), 1);
|
||||
// CHECK:STDERR: fail_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer overflow in calculation -2147483647 - 2.
|
||||
// CHECK:STDERR: let c: i32 = Sub(Sub(0, 0x7FFFFFFF), 2);
|
||||
// CHECK:STDERR: ^~~~
|
||||
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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Sub = %Sub
|
||||
// CHECK:STDOUT: .arr = %arr
|
||||
// CHECK:STDOUT: .RuntimeCall = %RuntimeCall
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub: <function> = 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: %return.var.loc2: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub.ref: <function> = 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: <function> = 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: %return.var.loc7: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Sub.ref: <function> = 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.1: init i32 = call %Sub.ref(%a.ref, %b.ref)
|
||||
// CHECK:STDOUT: %.loc8_19: i32 = value_of_initializer %.loc8_13.1
|
||||
// CHECK:STDOUT: %.loc8_13.2: i32 = converted %.loc8_13.1, %.loc8_19
|
||||
// CHECK:STDOUT: return %.loc8_13.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_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 2147483649 [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> = namespace [template] {
|
||||
// CHECK:STDOUT: .Sub = %Sub
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub: <function> = 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: %return.var: ref i32 = var <return slot>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Sub.ref.loc6: <function> = 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.1: init i32 = call %Sub.ref.loc6(%.loc6_18, %.loc6_21) [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc6_32: i32 = value_of_initializer %.loc6_17.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc6_17.2: i32 = converted %.loc6_17.1, %.loc6_32 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %a.loc6: i32 = bind_name a, %.loc6_17.2
|
||||
// CHECK:STDOUT: %Sub.ref.loc7_14: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Sub.ref.loc7_18: <function> = 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.1: 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.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc7_21.2: i32 = converted %.loc7_21.1, %.loc7_17.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc7_17.2: init i32 = call %Sub.ref.loc7_14(%.loc7_21.2, %.loc7_38) [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc7_40: i32 = value_of_initializer %.loc7_17.2 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %.loc7_17.3: i32 = converted %.loc7_17.2, %.loc7_40 [template = constants.%.5]
|
||||
// CHECK:STDOUT: %b.loc7: i32 = bind_name b, %.loc7_17.3
|
||||
// CHECK:STDOUT: %Sub.ref.loc11_14: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %Sub.ref.loc11_18: <function> = name_ref Sub, %Sub [template = %Sub]
|
||||
// CHECK:STDOUT: %.loc11_22: i32 = int_literal 0 [template = constants.%.1]
|
||||
// CHECK:STDOUT: %.loc11_25: i32 = int_literal 2147483647 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc11_21.1: init i32 = call %Sub.ref.loc11_18(%.loc11_22, %.loc11_25) [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc11_38: i32 = int_literal 2 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc11_17.1: i32 = value_of_initializer %.loc11_21.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc11_21.2: i32 = converted %.loc11_21.1, %.loc11_17.1 [template = constants.%.3]
|
||||
// CHECK:STDOUT: %.loc11_17.2: init i32 = call %Sub.ref.loc11_14(%.loc11_21.2, %.loc11_38) [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc11_40: i32 = value_of_initializer %.loc11_17.2 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %.loc11_17.3: i32 = converted %.loc11_17.2, %.loc11_40 [template = constants.%.2]
|
||||
// CHECK:STDOUT: %c: i32 = bind_name c, %.loc11_17.3
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Sub(%a: i32, %b: i32) -> i32 = "int.sub";
|
||||
// CHECK:STDOUT:
|
||||
@@ -229,13 +229,16 @@ CARBON_DIAGNOSTIC_KIND(AddrOfEphemeralRef)
|
||||
CARBON_DIAGNOSTIC_KIND(AddrOfNonRef)
|
||||
CARBON_DIAGNOSTIC_KIND(AddrOnNonSelfParam)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrayBoundTooLarge)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrayBoundNegative)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrayIndexOutOfBounds)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrayInitFromLiteralArgCountMismatch)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrayInitFromExprArgCountMismatch)
|
||||
CARBON_DIAGNOSTIC_KIND(ArrowOperatorOfNonPointer)
|
||||
CARBON_DIAGNOSTIC_KIND(AssignmentToNonAssignable)
|
||||
CARBON_DIAGNOSTIC_KIND(BreakOutsideLoop)
|
||||
CARBON_DIAGNOSTIC_KIND(CompileTimeDivisionByZero)
|
||||
CARBON_DIAGNOSTIC_KIND(CompileTimeIntegerOverflow)
|
||||
CARBON_DIAGNOSTIC_KIND(CompileTimeIntegerNegateOverflow)
|
||||
CARBON_DIAGNOSTIC_KIND(ContinueOutsideLoop)
|
||||
CARBON_DIAGNOSTIC_KIND(CopyOfUncopyableType)
|
||||
CARBON_DIAGNOSTIC_KIND(DerefOfNonPointer)
|
||||
|
||||
@@ -172,12 +172,24 @@ auto HandleBuiltin(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
|
||||
static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
|
||||
SemIR::BuiltinFunctionKind builtin_kind,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids) -> void {
|
||||
constexpr bool SignedOverflowIsUB = false;
|
||||
|
||||
switch (builtin_kind) {
|
||||
case SemIR::BuiltinFunctionKind::None:
|
||||
CARBON_FATAL() << "No callee in function call.";
|
||||
|
||||
case SemIR::BuiltinFunctionKind::IntNegate: {
|
||||
// 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",
|
||||
/*HasNUW=*/false,
|
||||
/*HasNSW=*/SignedOverflowIsUB));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntAdd: {
|
||||
constexpr bool SignedOverflowIsUB = false;
|
||||
context.SetLocal(inst_id, context.builder().CreateAdd(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "add",
|
||||
@@ -185,6 +197,46 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
|
||||
/*HasNSW=*/SignedOverflowIsUB));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntSub: {
|
||||
context.SetLocal(inst_id, context.builder().CreateSub(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "sub",
|
||||
/*HasNUW=*/false,
|
||||
/*HasNSW=*/SignedOverflowIsUB));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntMul: {
|
||||
context.SetLocal(inst_id, context.builder().CreateMul(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "mul",
|
||||
/*HasNUW=*/false,
|
||||
/*HasNSW=*/SignedOverflowIsUB));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntDiv: {
|
||||
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, context.builder().CreateSRem(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "rem"));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntEq: {
|
||||
context.SetLocal(inst_id, context.builder().CreateICmpEQ(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "eq"));
|
||||
return;
|
||||
}
|
||||
case SemIR::BuiltinFunctionKind::IntNeq: {
|
||||
context.SetLocal(inst_id, context.builder().CreateICmpNE(
|
||||
context.GetValue(arg_ids[0]),
|
||||
context.GetValue(arg_ids[1]), "neq"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CARBON_FATAL() << "Unsupported builtin call.";
|
||||
|
||||
@@ -50,19 +50,24 @@ struct TypeParam {
|
||||
}
|
||||
};
|
||||
|
||||
// Constraint that requires the type to be an integer type. See
|
||||
// ValidateSignature for details.
|
||||
struct AnyInt {
|
||||
// Constraint that a type is a specific builtin. See ValidateSignature for
|
||||
// details.
|
||||
template <const InstId& BuiltinId>
|
||||
struct BuiltinType {
|
||||
static auto Check(const File& sem_ir, ValidateState& /*state*/,
|
||||
TypeId type_id) -> bool {
|
||||
if (sem_ir.types().GetInstId(type_id) == InstId::BuiltinIntType) {
|
||||
return true;
|
||||
}
|
||||
// TODO: Support iN for all N, and the Core.BigInt type we use to implement
|
||||
// for integer literals.
|
||||
return false;
|
||||
return sem_ir.types().GetInstId(type_id) == BuiltinId;
|
||||
}
|
||||
};
|
||||
|
||||
// Constraint that a type is `bool`.
|
||||
using Bool = BuiltinType<InstId::BuiltinBoolType>;
|
||||
|
||||
// Constraint that requires the type to be an integer type.
|
||||
//
|
||||
// TODO: This only matches i32 for now. Support iN for all N, and the
|
||||
// Core.BigInt type we use to implement for integer literals.
|
||||
using AnyInt = BuiltinType<InstId::BuiltinIntType>;
|
||||
} // namespace
|
||||
|
||||
// Validates that this builtin has a signature matching the specified signature.
|
||||
@@ -123,10 +128,38 @@ using IntT = TypeParam<0, AnyInt>;
|
||||
// Not a builtin function.
|
||||
constexpr BuiltinInfo None = {"", nullptr};
|
||||
|
||||
// "int.negate": integer negation.
|
||||
constexpr BuiltinInfo IntNegate = {"int.negate",
|
||||
ValidateSignature<auto(IntT)->IntT>};
|
||||
|
||||
// "int.add": integer addition.
|
||||
constexpr BuiltinInfo IntAdd = {"int.add",
|
||||
ValidateSignature<auto(IntT, IntT)->IntT>};
|
||||
|
||||
// "int.sub": integer subtraction.
|
||||
constexpr BuiltinInfo IntSub = {"int.sub",
|
||||
ValidateSignature<auto(IntT, IntT)->IntT>};
|
||||
|
||||
// "int.mul": integer multiplication.
|
||||
constexpr BuiltinInfo IntMul = {"int.mul",
|
||||
ValidateSignature<auto(IntT, IntT)->IntT>};
|
||||
|
||||
// "int.div": integer division.
|
||||
constexpr BuiltinInfo IntDiv = {"int.div",
|
||||
ValidateSignature<auto(IntT, IntT)->IntT>};
|
||||
|
||||
// "int.mod": integer modulo.
|
||||
constexpr BuiltinInfo IntMod = {"int.mod",
|
||||
ValidateSignature<auto(IntT, IntT)->IntT>};
|
||||
|
||||
// "int.eq": integer equality comparison.
|
||||
constexpr BuiltinInfo IntEq = {"int.eq",
|
||||
ValidateSignature<auto(IntT, IntT)->Bool>};
|
||||
|
||||
// "int.neq": integer non-equality comparison.
|
||||
constexpr BuiltinInfo IntNeq = {"int.neq",
|
||||
ValidateSignature<auto(IntT, IntT)->Bool>};
|
||||
|
||||
} // namespace BuiltinFunctionInfo
|
||||
|
||||
CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinFunctionKind) = {
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#endif
|
||||
|
||||
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(None)
|
||||
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(IntEq)
|
||||
CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntNeq)
|
||||
|
||||
#undef CARBON_SEM_IR_BUILTIN_FUNCTION_KIND
|
||||
|
||||
@@ -265,6 +265,11 @@ struct BoolValue : public IdBase, public Printable<BoolValue> {
|
||||
static const BoolValue False;
|
||||
static const BoolValue True;
|
||||
|
||||
// Returns the `BoolValue` corresponding to `b`.
|
||||
static constexpr auto FromBool(bool b) -> BoolValue {
|
||||
return b ? True : False;
|
||||
}
|
||||
|
||||
using IdBase::IdBase;
|
||||
auto Print(llvm::raw_ostream& out) const -> void {
|
||||
if (*this == False) {
|
||||
|
||||
Reference in New Issue
Block a user