From 762d07fa3ec12a2caa6a80f6d85d175f1dbd7644 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 3 Apr 2024 15:21:55 -0700 Subject: [PATCH] Add builtins for integer bitwise, bit-shift, and relational comparison operators. (#3853) --- .codespell_ignore | 1 + toolchain/check/eval.cpp | 142 +++++++-- .../{int_add.carbon => int/add.carbon} | 0 .../check/testdata/builtins/int/and.carbon | 75 +++++ .../testdata/builtins/int/complement.carbon | 86 ++++++ .../{int_div.carbon => int/div.carbon} | 0 .../check/testdata/builtins/int/eq.carbon | 162 +++++++++++ .../testdata/builtins/int/greater.carbon | 215 ++++++++++++++ .../testdata/builtins/int/greater_eq.carbon | 215 ++++++++++++++ .../testdata/builtins/int/left_shift.carbon | 215 ++++++++++++++ .../check/testdata/builtins/int/less.carbon | 215 ++++++++++++++ .../testdata/builtins/int/less_eq.carbon | 215 ++++++++++++++ .../{int_mod.carbon => int/mod.carbon} | 0 .../{int_mul.carbon => int/mul.carbon} | 0 .../{int_negate.carbon => int/negate.carbon} | 40 +-- .../check/testdata/builtins/int/neq.carbon | 136 +++++++++ .../check/testdata/builtins/int/or.carbon | 75 +++++ .../testdata/builtins/int/right_shift.carbon | 269 ++++++++++++++++++ .../{int_sub.carbon => int/sub.carbon} | 0 .../check/testdata/builtins/int/xor.carbon | 75 +++++ .../check/testdata/builtins/int_eq.carbon | 101 ------- .../check/testdata/builtins/int_neq.carbon | 75 ----- toolchain/diagnostics/diagnostic_kind.def | 1 + toolchain/lower/handle.cpp | 88 +++++- toolchain/lower/testdata/builtins/int.carbon | 136 +++++++++ toolchain/sem_ir/builtin_function_kind.cpp | 48 +++- toolchain/sem_ir/builtin_function_kind.def | 16 ++ 27 files changed, 2367 insertions(+), 234 deletions(-) rename toolchain/check/testdata/builtins/{int_add.carbon => int/add.carbon} (100%) create mode 100644 toolchain/check/testdata/builtins/int/and.carbon create mode 100644 toolchain/check/testdata/builtins/int/complement.carbon rename toolchain/check/testdata/builtins/{int_div.carbon => int/div.carbon} (100%) create mode 100644 toolchain/check/testdata/builtins/int/eq.carbon create mode 100644 toolchain/check/testdata/builtins/int/greater.carbon create mode 100644 toolchain/check/testdata/builtins/int/greater_eq.carbon create mode 100644 toolchain/check/testdata/builtins/int/left_shift.carbon create mode 100644 toolchain/check/testdata/builtins/int/less.carbon create mode 100644 toolchain/check/testdata/builtins/int/less_eq.carbon rename toolchain/check/testdata/builtins/{int_mod.carbon => int/mod.carbon} (100%) rename toolchain/check/testdata/builtins/{int_mul.carbon => int/mul.carbon} (100%) rename toolchain/check/testdata/builtins/{int_negate.carbon => int/negate.carbon} (94%) create mode 100644 toolchain/check/testdata/builtins/int/neq.carbon create mode 100644 toolchain/check/testdata/builtins/int/or.carbon create mode 100644 toolchain/check/testdata/builtins/int/right_shift.carbon rename toolchain/check/testdata/builtins/{int_sub.carbon => int/sub.carbon} (100%) create mode 100644 toolchain/check/testdata/builtins/int/xor.carbon delete mode 100644 toolchain/check/testdata/builtins/int_eq.carbon delete mode 100644 toolchain/check/testdata/builtins/int_neq.carbon diff --git a/.codespell_ignore b/.codespell_ignore index 80039e446f34..309736ef36f2 100644 --- a/.codespell_ignore +++ b/.codespell_ignore @@ -7,6 +7,7 @@ circularly compiletime copyable crate +createor crossreference falsy forin diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 0542910b895d..6479bc8e677d 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -74,6 +74,22 @@ static auto MakeNonConstantResult(Phase phase) -> SemIR::ConstantId { : SemIR::ConstantId::NotConstant; } +// Converts a bool value into a ConstantId. +static auto MakeBoolResult(Context& context, SemIR::TypeId bool_type_id, + bool result) -> SemIR::ConstantId { + return MakeConstantResult( + context, SemIR::BoolLiteral{bool_type_id, SemIR::BoolValue::From(result)}, + Phase::Template); +} + +// Converts an APInt value into a ConstantId. +static auto MakeIntResult(Context& context, SemIR::TypeId type_id, + llvm::APInt value) -> SemIR::ConstantId { + auto result = context.ints().Add(std::move(value)); + return MakeConstantResult(context, SemIR::IntLiteral{type_id, result}, + Phase::Template); +} + // `GetConstantValue` checks to see whether the provided ID describes a value // with constant phase, and if so, returns the corresponding constant value. // Overloads are provided for different kinds of ID. @@ -297,23 +313,28 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc 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(arg_id); auto op_val = context.ints().Get(op.int_id); - if (context.types().IsSignedInt(op.type_id) && op_val.isMinSignedValue()) { - CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error, - "Integer overflow in negation of {0}.", TypedInt); - context.emitter().Emit(loc, CompileTimeIntegerNegateOverflow, - TypedInt{op.type_id, op_val}); + switch (builtin_kind) { + case SemIR::BuiltinFunctionKind::IntNegate: + if (context.types().IsSignedInt(op.type_id) && + op_val.isMinSignedValue()) { + CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error, + "Integer overflow in negation of {0}.", TypedInt); + context.emitter().Emit(loc, CompileTimeIntegerNegateOverflow, + TypedInt{op.type_id, op_val}); + } + op_val.negate(); + break; + case SemIR::BuiltinFunctionKind::IntComplement: + op_val.flipAllBits(); + break; + default: + CARBON_FATAL() << "Unexpected builtin kind"; } - op_val.negate(); - auto result = context.ints().Add(op_val); - return MakeConstantResult(context, SemIR::IntLiteral{op.type_id, result}, - Phase::Template); + return MakeIntResult(context, op.type_id, std::move(op_val)); } // Performs a builtin binary integer -> integer operation. @@ -324,14 +345,15 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc, -> SemIR::ConstantId { auto lhs = context.insts().GetAs(lhs_id); auto rhs = context.insts().GetAs(rhs_id); - auto lhs_val = context.ints().Get(lhs.int_id); - auto rhs_val = context.ints().Get(rhs.int_id); + const auto& lhs_val = context.ints().Get(lhs.int_id); + const auto& rhs_val = context.ints().Get(rhs.int_id); bool is_signed = context.types().IsSignedInt(lhs.type_id); bool overflow = false; llvm::APInt result_val; llvm::StringLiteral op_str = ""; switch (builtin_kind) { + // Arithmetic. case SemIR::BuiltinFunctionKind::IntAdd: result_val = is_signed ? lhs_val.sadd_ov(rhs_val, overflow) : lhs_val + rhs_val; @@ -368,6 +390,49 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc, op_str = "%"; break; + // Bitwise. + case SemIR::BuiltinFunctionKind::IntAnd: + result_val = lhs_val & rhs_val; + op_str = "&"; + break; + case SemIR::BuiltinFunctionKind::IntOr: + result_val = lhs_val | rhs_val; + op_str = "|"; + break; + case SemIR::BuiltinFunctionKind::IntXor: + result_val = lhs_val ^ rhs_val; + op_str = "^"; + break; + + // Bit shift. + case SemIR::BuiltinFunctionKind::IntLeftShift: + case SemIR::BuiltinFunctionKind::IntRightShift: + op_str = (builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift) + ? llvm::StringLiteral("<<") + : llvm::StringLiteral(">>"); + if (rhs_val.uge(lhs_val.getBitWidth()) || + (rhs_val.isNegative() && context.types().IsSignedInt(rhs.type_id))) { + CARBON_DIAGNOSTIC( + CompileTimeShiftOutOfRange, Error, + "Shift distance not in range [0, {0}) in {1} {2} {3}.", unsigned, + TypedInt, llvm::StringLiteral, TypedInt); + context.emitter().Emit(loc, CompileTimeShiftOutOfRange, + lhs_val.getBitWidth(), + TypedInt{lhs.type_id, lhs_val}, op_str, + TypedInt{rhs.type_id, rhs_val}); + // TODO: Is it useful to recover by returning 0 or -1? + return SemIR::ConstantId::Error; + } + + if (builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift) { + result_val = lhs_val.shl(rhs_val); + } else if (is_signed) { + result_val = lhs_val.ashr(rhs_val); + } else { + result_val = lhs_val.lshr(rhs_val); + } + break; + default: CARBON_FATAL() << "Unexpected operation kind."; } @@ -381,9 +446,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc, TypedInt{rhs.type_id, rhs_val}); } - auto result = context.ints().Add(result_val); - return MakeConstantResult(context, SemIR::IntLiteral{lhs.type_id, result}, - Phase::Template); + return MakeIntResult(context, lhs.type_id, std::move(result_val)); } // Performs a builtin integer comparison. @@ -393,10 +456,11 @@ static auto PerformBuiltinIntComparison(Context& context, SemIR::InstId rhs_id, SemIR::TypeId bool_type_id) -> SemIR::ConstantId { - auto lhs_val = context.ints().Get( - context.insts().GetAs(lhs_id).int_id); - auto rhs_val = context.ints().Get( + auto lhs = context.insts().GetAs(lhs_id); + const auto& lhs_val = context.ints().Get(lhs.int_id); + const auto& rhs_val = context.ints().Get( context.insts().GetAs(rhs_id).int_id); + bool is_signed = context.types().IsSignedInt(lhs.type_id); bool result; switch (builtin_kind) { @@ -406,13 +470,23 @@ static auto PerformBuiltinIntComparison(Context& context, case SemIR::BuiltinFunctionKind::IntNeq: result = (lhs_val != rhs_val); break; + case SemIR::BuiltinFunctionKind::IntLess: + result = is_signed ? lhs_val.slt(rhs_val) : lhs_val.ult(rhs_val); + break; + case SemIR::BuiltinFunctionKind::IntLessEq: + result = is_signed ? lhs_val.sle(rhs_val) : lhs_val.ule(rhs_val); + break; + case SemIR::BuiltinFunctionKind::IntGreater: + result = is_signed ? lhs_val.sgt(rhs_val) : lhs_val.sgt(rhs_val); + break; + case SemIR::BuiltinFunctionKind::IntGreaterEq: + result = is_signed ? lhs_val.sge(rhs_val) : lhs_val.sge(rhs_val); + break; default: CARBON_FATAL() << "Unexpected operation kind."; } - return MakeConstantResult( - context, SemIR::BoolLiteral{bool_type_id, SemIR::BoolValue::From(result)}, - Phase::Template); + return MakeBoolResult(context, bool_type_id, result); } static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, @@ -424,20 +498,25 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, CARBON_FATAL() << "Not a builtin function."; // Unary integer -> integer operations. - case SemIR::BuiltinFunctionKind::IntNegate: { - // TODO: Complement. + case SemIR::BuiltinFunctionKind::IntNegate: + case SemIR::BuiltinFunctionKind::IntComplement: { if (phase != Phase::Template) { break; } return PerformBuiltinUnaryIntOp(context, loc, builtin_kind, arg_ids[0]); } - // Homogeneous binary integer -> integer operations. + // Binary integer -> integer operations. case SemIR::BuiltinFunctionKind::IntAdd: case SemIR::BuiltinFunctionKind::IntSub: case SemIR::BuiltinFunctionKind::IntMul: case SemIR::BuiltinFunctionKind::IntDiv: - case SemIR::BuiltinFunctionKind::IntMod: { + case SemIR::BuiltinFunctionKind::IntMod: + case SemIR::BuiltinFunctionKind::IntAnd: + case SemIR::BuiltinFunctionKind::IntOr: + case SemIR::BuiltinFunctionKind::IntXor: + case SemIR::BuiltinFunctionKind::IntLeftShift: + case SemIR::BuiltinFunctionKind::IntRightShift: { // TODO: Bitwise operators. if (phase != Phase::Template) { break; @@ -448,7 +527,11 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, // Integer comparisons. case SemIR::BuiltinFunctionKind::IntEq: - case SemIR::BuiltinFunctionKind::IntNeq: { + case SemIR::BuiltinFunctionKind::IntNeq: + case SemIR::BuiltinFunctionKind::IntLess: + case SemIR::BuiltinFunctionKind::IntLessEq: + case SemIR::BuiltinFunctionKind::IntGreater: + case SemIR::BuiltinFunctionKind::IntGreaterEq: { // TODO: Relational comparisons. if (phase != Phase::Template) { break; @@ -696,8 +779,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) if (phase == Phase::Template) { auto value = context.insts().GetAs(const_id.inst_id()); - value.value = SemIR::BoolValue::From(!value.value.ToBool()); - return MakeConstantResult(context, value, Phase::Template); + return MakeBoolResult(context, value.type_id, !value.value.ToBool()); } if (phase == Phase::UnknownDueToError) { return SemIR::ConstantId::Error; diff --git a/toolchain/check/testdata/builtins/int_add.carbon b/toolchain/check/testdata/builtins/int/add.carbon similarity index 100% rename from toolchain/check/testdata/builtins/int_add.carbon rename to toolchain/check/testdata/builtins/int/add.carbon diff --git a/toolchain/check/testdata/builtins/int/and.carbon b/toolchain/check/testdata/builtins/int/and.carbon new file mode 100644 index 000000000000..8e8c23bf26e5 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/and.carbon @@ -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_and.carbon + +fn And(a: i32, b: i32) -> i32 = "int.and"; + +var arr: [i32; And(12, 10)]; +let arr_p: [i32; 8]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return And(a, b); +} + +// CHECK:STDOUT: --- int_and.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 12 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 10 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 8 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 8] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .And = %And +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %And: = fn_decl @And [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @And.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @And.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %And.ref: = name_ref And, %And [template = %And] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_24: i32 = int_literal 10 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %And.ref(%.loc4_20, %.loc4_24) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_27: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 8] = var arr +// CHECK:STDOUT: %arr: ref [i32; 8] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 8 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 8] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 8] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 8]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 8]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @And(%a: i32, %b: i32) -> i32 = "int.and"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %And.ref: = name_ref And, file.%And [template = file.%And] +// 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 %And.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: diff --git a/toolchain/check/testdata/builtins/int/complement.carbon b/toolchain/check/testdata/builtins/int/complement.carbon new file mode 100644 index 000000000000..0562aaba991d --- /dev/null +++ b/toolchain/check/testdata/builtins/int/complement.carbon @@ -0,0 +1,86 @@ +// 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_complement.carbon + +fn Complement(a: i32) -> i32 = "int.complement"; +fn And(a: i32, b: i32) -> i32 = "int.and"; + +var arr: [i32; And(Complement(0x123456), 0xFFFFFF)]; +let arr_p: [i32; 0xEDCBA9]* = &arr; + +fn RuntimeCall(a: i32) -> i32 { + return Complement(a); +} + +// CHECK:STDOUT: --- int_complement.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1193046 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -1193047 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 16777215 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 15584169 [template] +// CHECK:STDOUT: %.5: type = array_type %.4, i32 [template] +// CHECK:STDOUT: %.6: type = ptr_type [i32; 15584169] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Complement = %Complement +// CHECK:STDOUT: .And = %And +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Complement: = fn_decl @Complement [template] { +// CHECK:STDOUT: %a.loc2_15.1: i32 = param a +// CHECK:STDOUT: @Complement.%a: i32 = bind_name a, %a.loc2_15.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %And: = fn_decl @And [template] { +// CHECK:STDOUT: %a.loc3_8.1: i32 = param a +// CHECK:STDOUT: @And.%a: i32 = bind_name a, %a.loc3_8.1 +// CHECK:STDOUT: %b.loc3_16.1: i32 = param b +// CHECK:STDOUT: @And.%b: i32 = bind_name b, %b.loc3_16.1 +// CHECK:STDOUT: %return.var.loc3: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %And.ref: = name_ref And, %And [template = %And] +// CHECK:STDOUT: %Complement.ref: = name_ref Complement, %Complement [template = %Complement] +// CHECK:STDOUT: %.loc5_31: i32 = int_literal 1193046 [template = constants.%.1] +// CHECK:STDOUT: %.loc5_30.1: init i32 = call %Complement.ref(%.loc5_31) [template = constants.%.2] +// CHECK:STDOUT: %.loc5_42: i32 = int_literal 16777215 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19.1: i32 = value_of_initializer %.loc5_30.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc5_30.2: i32 = converted %.loc5_30.1, %.loc5_19.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc5_19.2: init i32 = call %And.ref(%.loc5_30.2, %.loc5_42) [template = constants.%.4] +// CHECK:STDOUT: %.loc5_51: type = array_type %.loc5_19.2, i32 [template = constants.%.5] +// CHECK:STDOUT: %arr.var: ref [i32; 15584169] = var arr +// CHECK:STDOUT: %arr: ref [i32; 15584169] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc6_18: i32 = int_literal 15584169 [template = constants.%.4] +// CHECK:STDOUT: %.loc6_26: type = array_type %.loc6_18, i32 [template = constants.%.5] +// CHECK:STDOUT: %.loc6_27: type = ptr_type [i32; 15584169] [template = constants.%.6] +// CHECK:STDOUT: %arr.ref: ref [i32; 15584169] = name_ref arr, %arr +// CHECK:STDOUT: %.loc6_31: [i32; 15584169]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 15584169]* = bind_name arr_p, %.loc6_31 +// CHECK:STDOUT: %RuntimeCall: = 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: %return.var.loc8: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Complement(%a: i32) -> i32 = "int.complement"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @And(%a: i32, %b: i32) -> i32 = "int.and"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Complement.ref: = name_ref Complement, file.%Complement [template = file.%Complement] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %.loc9_20.1: init i32 = call %Complement.ref(%a.ref) +// CHECK:STDOUT: %.loc9_23: i32 = value_of_initializer %.loc9_20.1 +// CHECK:STDOUT: %.loc9_20.2: i32 = converted %.loc9_20.1, %.loc9_23 +// CHECK:STDOUT: return %.loc9_20.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int_div.carbon b/toolchain/check/testdata/builtins/int/div.carbon similarity index 100% rename from toolchain/check/testdata/builtins/int_div.carbon rename to toolchain/check/testdata/builtins/int/div.carbon diff --git a/toolchain/check/testdata/builtins/int/eq.carbon b/toolchain/check/testdata/builtins/int/eq.carbon new file mode 100644 index 000000000000..1f79fb48f7fd --- /dev/null +++ b/toolchain/check/testdata/builtins/int/eq.carbon @@ -0,0 +1,162 @@ +// 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"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + true_ as (if Eq(1, 1) then True else False); + false_ as (if Eq(1, 2) then True else False); +} + +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: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: bool = bool_literal true [template] +// CHECK:STDOUT: %.6: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.7: bool = bool_literal false [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Eq = %Eq +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Eq: = 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 +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc7_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc7_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc7_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc7_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc12_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc12_16.1 +// CHECK:STDOUT: %b.loc12_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc12_24.1 +// CHECK:STDOUT: %return.var.loc12: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Eq(%a: i32, %b: i32) -> bool = "int.eq"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %true_.ref: True = name_ref true_, %true_ +// CHECK:STDOUT: %Eq.ref.loc8: = name_ref Eq, file.%Eq [template = file.%Eq] +// CHECK:STDOUT: %.loc8_19: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_22: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_18.1: init bool = call %Eq.ref.loc8(%.loc8_19, %.loc8_22) [template = constants.%.5] +// CHECK:STDOUT: %.loc8_13.1: bool = value_of_initializer %.loc8_18.1 [template = constants.%.5] +// CHECK:STDOUT: %.loc8_18.2: bool = converted %.loc8_18.1, %.loc8_13.1 [template = constants.%.5] +// CHECK:STDOUT: if %.loc8_18.2 br !if.expr.then.loc8 else br !if.expr.else.loc8 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc8: +// CHECK:STDOUT: %True.ref.loc8: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc8(%True.ref.loc8) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc8: +// CHECK:STDOUT: %False.ref.loc8: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc8(%False.ref.loc8) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc8: +// CHECK:STDOUT: %.loc8_13.2: type = block_arg !if.expr.result.loc8 [template = constants.%True] +// CHECK:STDOUT: %false_.ref: False = name_ref false_, %false_ +// CHECK:STDOUT: %Eq.ref.loc9: = name_ref Eq, file.%Eq [template = file.%Eq] +// CHECK:STDOUT: %.loc9_20: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_23: i32 = int_literal 2 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_19.1: init bool = call %Eq.ref.loc9(%.loc9_20, %.loc9_23) [template = constants.%.7] +// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %.loc9_19.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc9_19.2: bool = converted %.loc9_19.1, %.loc9_14.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc9_19.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_14.2: type = block_arg !if.expr.result.loc9 [template = constants.%False] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Eq.ref: = 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: %.loc13_12.1: init bool = call %Eq.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc13_18: bool = value_of_initializer %.loc13_12.1 +// CHECK:STDOUT: %.loc13_12.2: bool = converted %.loc13_12.1, %.loc13_18 +// CHECK:STDOUT: return %.loc13_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .WrongResult = %WrongResult +// CHECK:STDOUT: } +// CHECK:STDOUT: %WrongResult: = 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 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @WrongResult(%a: i32, %b: i32) -> i32; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/greater.carbon b/toolchain/check/testdata/builtins/int/greater.carbon new file mode 100644 index 000000000000..7ebd03b86745 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/greater.carbon @@ -0,0 +1,215 @@ +// 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_greater.carbon + +fn Greater(a: i32, b: i32) -> bool = "int.greater"; +fn Negate(a: i32) -> i32 = "int.negate"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + false_ as (if Greater(1, 2) then True else False); + false_ as (if Greater(1, 1) then True else False); + true_ as (if Greater(1, 0) then True else False); + false_ as (if Greater(Negate(1), 0) then True else False); + true_ as (if Greater(0, Negate(1)) then True else False); +} + +fn RuntimeCall(a: i32, b: i32) -> bool { + return Greater(a, b); +} + +// CHECK:STDOUT: --- int_greater.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: bool = bool_literal false [template] +// CHECK:STDOUT: %.7: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.8: bool = bool_literal true [template] +// CHECK:STDOUT: %.9: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Greater = %Greater +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Greater: = fn_decl @Greater [template] { +// CHECK:STDOUT: %a.loc2_12.1: i32 = param a +// CHECK:STDOUT: @Greater.%a: i32 = bind_name a, %a.loc2_12.1 +// CHECK:STDOUT: %b.loc2_20.1: i32 = param b +// CHECK:STDOUT: @Greater.%b: i32 = bind_name b, %b.loc2_20.1 +// CHECK:STDOUT: %return.var.loc2: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc3_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc3_11.1 +// CHECK:STDOUT: %return.var.loc3: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc8_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc8_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc8_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc8_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc16_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc16_16.1 +// CHECK:STDOUT: %b.loc16_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc16_24.1 +// CHECK:STDOUT: %return.var.loc16: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Greater(%a: i32, %b: i32) -> bool = "int.greater"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %false_.ref.loc9: False = name_ref false_, %false_ +// CHECK:STDOUT: %Greater.ref.loc9: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %.loc9_25: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_28: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %.loc9_24.1: init bool = call %Greater.ref.loc9(%.loc9_25, %.loc9_28) [template = constants.%.6] +// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %.loc9_24.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_24.2: bool = converted %.loc9_24.1, %.loc9_14.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc9_24.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_14.2: type = block_arg !if.expr.result.loc9 [template = constants.%False] +// CHECK:STDOUT: %false_.ref.loc10: False = name_ref false_, %false_ +// CHECK:STDOUT: %Greater.ref.loc10: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %.loc10_25: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_28: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_24.1: init bool = call %Greater.ref.loc10(%.loc10_25, %.loc10_28) [template = constants.%.6] +// CHECK:STDOUT: %.loc10_14.1: bool = value_of_initializer %.loc10_24.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc10_24.2: bool = converted %.loc10_24.1, %.loc10_14.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc10_24.2 br !if.expr.then.loc10 else br !if.expr.else.loc10 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc10: +// CHECK:STDOUT: %True.ref.loc10: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc10(%True.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc10: +// CHECK:STDOUT: %False.ref.loc10: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc10(%False.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc10: +// CHECK:STDOUT: %.loc10_14.2: type = block_arg !if.expr.result.loc10 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc11: True = name_ref true_, %true_ +// CHECK:STDOUT: %Greater.ref.loc11: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %.loc11_24: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_27: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_23.1: init bool = call %Greater.ref.loc11(%.loc11_24, %.loc11_27) [template = constants.%.8] +// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %.loc11_23.1 [template = constants.%.8] +// CHECK:STDOUT: %.loc11_23.2: bool = converted %.loc11_23.1, %.loc11_13.1 [template = constants.%.8] +// CHECK:STDOUT: if %.loc11_23.2 br !if.expr.then.loc11 else br !if.expr.else.loc11 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc11: +// CHECK:STDOUT: %True.ref.loc11: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc11(%True.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc11: +// CHECK:STDOUT: %False.ref.loc11: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc11(%False.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc11: +// CHECK:STDOUT: %.loc11_13.2: type = block_arg !if.expr.result.loc11 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc12: False = name_ref false_, %false_ +// CHECK:STDOUT: %Greater.ref.loc12: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc12_32: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc12_31.1: init i32 = call %Negate.ref.loc12(%.loc12_32) [template = constants.%.9] +// CHECK:STDOUT: %.loc12_36: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc12_24.1: i32 = value_of_initializer %.loc12_31.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_31.2: i32 = converted %.loc12_31.1, %.loc12_24.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_24.2: init bool = call %Greater.ref.loc12(%.loc12_31.2, %.loc12_36) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_14.1: bool = value_of_initializer %.loc12_24.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_24.3: bool = converted %.loc12_24.2, %.loc12_14.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc12_24.3 br !if.expr.then.loc12 else br !if.expr.else.loc12 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc12: +// CHECK:STDOUT: %True.ref.loc12: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc12(%True.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc12: +// CHECK:STDOUT: %False.ref.loc12: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc12(%False.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc12: +// CHECK:STDOUT: %.loc12_14.2: type = block_arg !if.expr.result.loc12 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc13: True = name_ref true_, %true_ +// CHECK:STDOUT: %Greater.ref.loc13: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %.loc13_24: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %Negate.ref.loc13: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc13_34: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_33.1: init i32 = call %Negate.ref.loc13(%.loc13_34) [template = constants.%.9] +// CHECK:STDOUT: %.loc13_23.1: i32 = value_of_initializer %.loc13_33.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_33.2: i32 = converted %.loc13_33.1, %.loc13_23.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_23.2: init bool = call %Greater.ref.loc13(%.loc13_24, %.loc13_33.2) [template = constants.%.8] +// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %.loc13_23.2 [template = constants.%.8] +// CHECK:STDOUT: %.loc13_23.3: bool = converted %.loc13_23.2, %.loc13_13.1 [template = constants.%.8] +// CHECK:STDOUT: if %.loc13_23.3 br !if.expr.then.loc13 else br !if.expr.else.loc13 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc13: +// CHECK:STDOUT: %True.ref.loc13: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc13(%True.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc13: +// CHECK:STDOUT: %False.ref.loc13: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc13(%False.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc13: +// CHECK:STDOUT: %.loc13_13.2: type = block_arg !if.expr.result.loc13 [template = constants.%True] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Greater.ref: = name_ref Greater, file.%Greater [template = file.%Greater] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc17_17.1: init bool = call %Greater.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc17_23: bool = value_of_initializer %.loc17_17.1 +// CHECK:STDOUT: %.loc17_17.2: bool = converted %.loc17_17.1, %.loc17_23 +// CHECK:STDOUT: return %.loc17_17.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/greater_eq.carbon b/toolchain/check/testdata/builtins/int/greater_eq.carbon new file mode 100644 index 000000000000..b33a3e6aafa1 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/greater_eq.carbon @@ -0,0 +1,215 @@ +// 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_greater_eq.carbon + +fn GreaterEq(a: i32, b: i32) -> bool = "int.greater_eq"; +fn Negate(a: i32) -> i32 = "int.negate"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + false_ as (if GreaterEq(1, 2) then True else False); + true_ as (if GreaterEq(1, 1) then True else False); + true_ as (if GreaterEq(1, 0) then True else False); + false_ as (if GreaterEq(Negate(1), 0) then True else False); + true_ as (if GreaterEq(0, Negate(1)) then True else False); +} + +fn RuntimeCall(a: i32, b: i32) -> bool { + return GreaterEq(a, b); +} + +// CHECK:STDOUT: --- int_greater_eq.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: bool = bool_literal false [template] +// CHECK:STDOUT: %.7: bool = bool_literal true [template] +// CHECK:STDOUT: %.8: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.9: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .GreaterEq = %GreaterEq +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %GreaterEq: = fn_decl @GreaterEq [template] { +// CHECK:STDOUT: %a.loc2_14.1: i32 = param a +// CHECK:STDOUT: @GreaterEq.%a: i32 = bind_name a, %a.loc2_14.1 +// CHECK:STDOUT: %b.loc2_22.1: i32 = param b +// CHECK:STDOUT: @GreaterEq.%b: i32 = bind_name b, %b.loc2_22.1 +// CHECK:STDOUT: %return.var.loc2: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc3_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc3_11.1 +// CHECK:STDOUT: %return.var.loc3: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc8_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc8_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc8_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc8_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc16_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc16_16.1 +// CHECK:STDOUT: %b.loc16_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc16_24.1 +// CHECK:STDOUT: %return.var.loc16: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @GreaterEq(%a: i32, %b: i32) -> bool = "int.greater_eq"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %false_.ref.loc9: False = name_ref false_, %false_ +// CHECK:STDOUT: %GreaterEq.ref.loc9: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %.loc9_27: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_30: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %.loc9_26.1: init bool = call %GreaterEq.ref.loc9(%.loc9_27, %.loc9_30) [template = constants.%.6] +// CHECK:STDOUT: %.loc9_14.1: bool = value_of_initializer %.loc9_26.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_26.2: bool = converted %.loc9_26.1, %.loc9_14.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc9_26.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_14.2: type = block_arg !if.expr.result.loc9 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc10: True = name_ref true_, %true_ +// CHECK:STDOUT: %GreaterEq.ref.loc10: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %.loc10_26: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_29: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_25.1: init bool = call %GreaterEq.ref.loc10(%.loc10_26, %.loc10_29) [template = constants.%.7] +// CHECK:STDOUT: %.loc10_13.1: bool = value_of_initializer %.loc10_25.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc10_25.2: bool = converted %.loc10_25.1, %.loc10_13.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc10_25.2 br !if.expr.then.loc10 else br !if.expr.else.loc10 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc10: +// CHECK:STDOUT: %True.ref.loc10: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc10(%True.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc10: +// CHECK:STDOUT: %False.ref.loc10: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc10(%False.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc10: +// CHECK:STDOUT: %.loc10_13.2: type = block_arg !if.expr.result.loc10 [template = constants.%True] +// CHECK:STDOUT: %true_.ref.loc11: True = name_ref true_, %true_ +// CHECK:STDOUT: %GreaterEq.ref.loc11: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %.loc11_26: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_29: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %.loc11_25.1: init bool = call %GreaterEq.ref.loc11(%.loc11_26, %.loc11_29) [template = constants.%.7] +// CHECK:STDOUT: %.loc11_13.1: bool = value_of_initializer %.loc11_25.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_25.2: bool = converted %.loc11_25.1, %.loc11_13.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc11_25.2 br !if.expr.then.loc11 else br !if.expr.else.loc11 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc11: +// CHECK:STDOUT: %True.ref.loc11: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc11(%True.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc11: +// CHECK:STDOUT: %False.ref.loc11: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc11(%False.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc11: +// CHECK:STDOUT: %.loc11_13.2: type = block_arg !if.expr.result.loc11 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc12: False = name_ref false_, %false_ +// CHECK:STDOUT: %GreaterEq.ref.loc12: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc12_34: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc12_33.1: init i32 = call %Negate.ref.loc12(%.loc12_34) [template = constants.%.9] +// CHECK:STDOUT: %.loc12_38: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %.loc12_26.1: i32 = value_of_initializer %.loc12_33.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_33.2: i32 = converted %.loc12_33.1, %.loc12_26.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_26.2: init bool = call %GreaterEq.ref.loc12(%.loc12_33.2, %.loc12_38) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_14.1: bool = value_of_initializer %.loc12_26.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_26.3: bool = converted %.loc12_26.2, %.loc12_14.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc12_26.3 br !if.expr.then.loc12 else br !if.expr.else.loc12 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc12: +// CHECK:STDOUT: %True.ref.loc12: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc12(%True.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc12: +// CHECK:STDOUT: %False.ref.loc12: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc12(%False.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc12: +// CHECK:STDOUT: %.loc12_14.2: type = block_arg !if.expr.result.loc12 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc13: True = name_ref true_, %true_ +// CHECK:STDOUT: %GreaterEq.ref.loc13: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %.loc13_26: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %Negate.ref.loc13: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc13_36: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_35.1: init i32 = call %Negate.ref.loc13(%.loc13_36) [template = constants.%.9] +// CHECK:STDOUT: %.loc13_25.1: i32 = value_of_initializer %.loc13_35.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_35.2: i32 = converted %.loc13_35.1, %.loc13_25.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_25.2: init bool = call %GreaterEq.ref.loc13(%.loc13_26, %.loc13_35.2) [template = constants.%.7] +// CHECK:STDOUT: %.loc13_13.1: bool = value_of_initializer %.loc13_25.2 [template = constants.%.7] +// CHECK:STDOUT: %.loc13_25.3: bool = converted %.loc13_25.2, %.loc13_13.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc13_25.3 br !if.expr.then.loc13 else br !if.expr.else.loc13 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc13: +// CHECK:STDOUT: %True.ref.loc13: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc13(%True.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc13: +// CHECK:STDOUT: %False.ref.loc13: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc13(%False.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc13: +// CHECK:STDOUT: %.loc13_13.2: type = block_arg !if.expr.result.loc13 [template = constants.%True] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %GreaterEq.ref: = name_ref GreaterEq, file.%GreaterEq [template = file.%GreaterEq] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc17_19.1: init bool = call %GreaterEq.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc17_25: bool = value_of_initializer %.loc17_19.1 +// CHECK:STDOUT: %.loc17_19.2: bool = converted %.loc17_19.1, %.loc17_25 +// CHECK:STDOUT: return %.loc17_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/left_shift.carbon b/toolchain/check/testdata/builtins/int/left_shift.carbon new file mode 100644 index 000000000000..8da1c7e838e5 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/left_shift.carbon @@ -0,0 +1,215 @@ +// 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_left_shift.carbon + +fn LeftShift(a: i32, b: i32) -> i32 = "int.left_shift"; + +var arr: [i32; LeftShift(5, 2)]; +let arr_p: [i32; 20]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return LeftShift(a, b); +} + +// TODO: Test mixed types for LHS and RHS. + +// --- fail_bad_shift.carbon + +package BadShift api; + +fn LeftShift(a: i32, b: i32) -> i32 = "int.left_shift"; +fn Negate(a: i32) -> i32 = "int.negate"; + +// Shift greater than size is disallowed. +let size_1: i32 = LeftShift(1, 31); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:19: ERROR: Shift distance not in range [0, 32) in 1 << 32. +// CHECK:STDERR: let size_2: i32 = LeftShift(1, 32); +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: +let size_2: i32 = LeftShift(1, 32); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:19: ERROR: Shift distance not in range [0, 32) in 1 << 33. +// CHECK:STDERR: let size_3: i32 = LeftShift(1, 33); +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: +let size_3: i32 = LeftShift(1, 33); + +// Overflow is allowed if the shift distance is in bounds. +let overflow_1: i32 = LeftShift(1000, 31); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:23: ERROR: Shift distance not in range [0, 32) in 1000 << 32. +// CHECK:STDERR: let overflow_2: i32 = LeftShift(1000, 32); +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: +let overflow_2: i32 = LeftShift(1000, 32); + +// Oversize shifts aren't allowed even if there's no overflow. +let no_overflow_1: i32 = LeftShift(0, 31); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:26: ERROR: Shift distance not in range [0, 32) in 0 << 32. +// CHECK:STDERR: let no_overflow_2: i32 = LeftShift(0, 32); +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: +let no_overflow_2: i32 = LeftShift(0, 32); + +// Negative shifts aren't allowed either. +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+3]]:21: ERROR: Shift distance not in range [0, 32) in 1 << -1. +// CHECK:STDERR: let negative: i32 = LeftShift(1, Negate(1)); +// CHECK:STDERR: ^~~~~~~~~~ +let negative: i32 = LeftShift(1, Negate(1)); + +// CHECK:STDOUT: --- int_left_shift.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 5 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 20 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 20] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .LeftShift = %LeftShift +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %LeftShift: = fn_decl @LeftShift [template] { +// CHECK:STDOUT: %a.loc2_14.1: i32 = param a +// CHECK:STDOUT: @LeftShift.%a: i32 = bind_name a, %a.loc2_14.1 +// CHECK:STDOUT: %b.loc2_22.1: i32 = param b +// CHECK:STDOUT: @LeftShift.%b: i32 = bind_name b, %b.loc2_22.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %LeftShift.ref: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc4_26: i32 = int_literal 5 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_29: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_25: init i32 = call %LeftShift.ref(%.loc4_26, %.loc4_29) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_31: type = array_type %.loc4_25, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 20] = var arr +// CHECK:STDOUT: %arr: ref [i32; 20] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 20 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_20: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_21: type = ptr_type [i32; 20] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 20] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_25: [i32; 20]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 20]* = bind_name arr_p, %.loc5_25 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LeftShift(%a: i32, %b: i32) -> i32 = "int.left_shift"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %LeftShift.ref: = name_ref LeftShift, file.%LeftShift [template = file.%LeftShift] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_19.1: init i32 = call %LeftShift.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_25: i32 = value_of_initializer %.loc8_19.1 +// CHECK:STDOUT: %.loc8_19.2: i32 = converted %.loc8_19.1, %.loc8_25 +// CHECK:STDOUT: return %.loc8_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_shift.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 31 [template] +// CHECK:STDOUT: %.3: i32 = int_literal -2147483648 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 32 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 33 [template] +// CHECK:STDOUT: %.6: i32 = int_literal 1000 [template] +// CHECK:STDOUT: %.7: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.8: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .LeftShift = %LeftShift +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: } +// CHECK:STDOUT: %LeftShift: = fn_decl @LeftShift [template] { +// CHECK:STDOUT: %a.loc4_14.1: i32 = param a +// CHECK:STDOUT: @LeftShift.%a: i32 = bind_name a, %a.loc4_14.1 +// CHECK:STDOUT: %b.loc4_22.1: i32 = param b +// CHECK:STDOUT: @LeftShift.%b: i32 = bind_name b, %b.loc4_22.1 +// CHECK:STDOUT: %return.var.loc4: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc5_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc5_11.1 +// CHECK:STDOUT: %return.var.loc5: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %LeftShift.ref.loc8: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc8_29: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_32: i32 = int_literal 31 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_28.1: init i32 = call %LeftShift.ref.loc8(%.loc8_29, %.loc8_32) [template = constants.%.3] +// CHECK:STDOUT: %.loc8_35: i32 = value_of_initializer %.loc8_28.1 [template = constants.%.3] +// CHECK:STDOUT: %.loc8_28.2: i32 = converted %.loc8_28.1, %.loc8_35 [template = constants.%.3] +// CHECK:STDOUT: %size_1: i32 = bind_name size_1, %.loc8_28.2 +// CHECK:STDOUT: %LeftShift.ref.loc13: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc13_29: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc13_32: i32 = int_literal 32 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_28.1: init i32 = call %LeftShift.ref.loc13(%.loc13_29, %.loc13_32) [template = ] +// CHECK:STDOUT: %.loc13_35: i32 = value_of_initializer %.loc13_28.1 [template = ] +// CHECK:STDOUT: %.loc13_28.2: i32 = converted %.loc13_28.1, %.loc13_35 [template = ] +// CHECK:STDOUT: %size_2: i32 = bind_name size_2, %.loc13_28.2 +// CHECK:STDOUT: %LeftShift.ref.loc18: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc18_29: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc18_32: i32 = int_literal 33 [template = constants.%.5] +// CHECK:STDOUT: %.loc18_28.1: init i32 = call %LeftShift.ref.loc18(%.loc18_29, %.loc18_32) [template = ] +// CHECK:STDOUT: %.loc18_35: i32 = value_of_initializer %.loc18_28.1 [template = ] +// CHECK:STDOUT: %.loc18_28.2: i32 = converted %.loc18_28.1, %.loc18_35 [template = ] +// CHECK:STDOUT: %size_3: i32 = bind_name size_3, %.loc18_28.2 +// CHECK:STDOUT: %LeftShift.ref.loc21: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc21_33: i32 = int_literal 1000 [template = constants.%.6] +// CHECK:STDOUT: %.loc21_39: i32 = int_literal 31 [template = constants.%.2] +// CHECK:STDOUT: %.loc21_32.1: init i32 = call %LeftShift.ref.loc21(%.loc21_33, %.loc21_39) [template = constants.%.7] +// CHECK:STDOUT: %.loc21_42: i32 = value_of_initializer %.loc21_32.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc21_32.2: i32 = converted %.loc21_32.1, %.loc21_42 [template = constants.%.7] +// CHECK:STDOUT: %overflow_1: i32 = bind_name overflow_1, %.loc21_32.2 +// CHECK:STDOUT: %LeftShift.ref.loc26: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc26_33: i32 = int_literal 1000 [template = constants.%.6] +// CHECK:STDOUT: %.loc26_39: i32 = int_literal 32 [template = constants.%.4] +// CHECK:STDOUT: %.loc26_32.1: init i32 = call %LeftShift.ref.loc26(%.loc26_33, %.loc26_39) [template = ] +// CHECK:STDOUT: %.loc26_42: i32 = value_of_initializer %.loc26_32.1 [template = ] +// CHECK:STDOUT: %.loc26_32.2: i32 = converted %.loc26_32.1, %.loc26_42 [template = ] +// CHECK:STDOUT: %overflow_2: i32 = bind_name overflow_2, %.loc26_32.2 +// CHECK:STDOUT: %LeftShift.ref.loc29: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc29_36: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc29_39: i32 = int_literal 31 [template = constants.%.2] +// CHECK:STDOUT: %.loc29_35.1: init i32 = call %LeftShift.ref.loc29(%.loc29_36, %.loc29_39) [template = constants.%.7] +// CHECK:STDOUT: %.loc29_42: i32 = value_of_initializer %.loc29_35.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc29_35.2: i32 = converted %.loc29_35.1, %.loc29_42 [template = constants.%.7] +// CHECK:STDOUT: %no_overflow_1: i32 = bind_name no_overflow_1, %.loc29_35.2 +// CHECK:STDOUT: %LeftShift.ref.loc34: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc34_36: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc34_39: i32 = int_literal 32 [template = constants.%.4] +// CHECK:STDOUT: %.loc34_35.1: init i32 = call %LeftShift.ref.loc34(%.loc34_36, %.loc34_39) [template = ] +// CHECK:STDOUT: %.loc34_42: i32 = value_of_initializer %.loc34_35.1 [template = ] +// CHECK:STDOUT: %.loc34_35.2: i32 = converted %.loc34_35.1, %.loc34_42 [template = ] +// CHECK:STDOUT: %no_overflow_2: i32 = bind_name no_overflow_2, %.loc34_35.2 +// CHECK:STDOUT: %LeftShift.ref.loc40: = name_ref LeftShift, %LeftShift [template = %LeftShift] +// CHECK:STDOUT: %.loc40_31: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %Negate.ref: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc40_41: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc40_40.1: init i32 = call %Negate.ref(%.loc40_41) [template = constants.%.8] +// CHECK:STDOUT: %.loc40_30.1: i32 = value_of_initializer %.loc40_40.1 [template = constants.%.8] +// CHECK:STDOUT: %.loc40_40.2: i32 = converted %.loc40_40.1, %.loc40_30.1 [template = constants.%.8] +// CHECK:STDOUT: %.loc40_30.2: init i32 = call %LeftShift.ref.loc40(%.loc40_31, %.loc40_40.2) [template = ] +// CHECK:STDOUT: %.loc40_44: i32 = value_of_initializer %.loc40_30.2 [template = ] +// CHECK:STDOUT: %.loc40_30.3: i32 = converted %.loc40_30.2, %.loc40_44 [template = ] +// CHECK:STDOUT: %negative: i32 = bind_name negative, %.loc40_30.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LeftShift(%a: i32, %b: i32) -> i32 = "int.left_shift"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/less.carbon b/toolchain/check/testdata/builtins/int/less.carbon new file mode 100644 index 000000000000..fd65adb3488b --- /dev/null +++ b/toolchain/check/testdata/builtins/int/less.carbon @@ -0,0 +1,215 @@ +// 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_less.carbon + +fn Less(a: i32, b: i32) -> bool = "int.less"; +fn Negate(a: i32) -> i32 = "int.negate"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + true_ as (if Less(1, 2) then True else False); + false_ as (if Less(1, 1) then True else False); + false_ as (if Less(1, 0) then True else False); + true_ as (if Less(Negate(1), 0) then True else False); + false_ as (if Less(0, Negate(1)) then True else False); +} + +fn RuntimeCall(a: i32, b: i32) -> bool { + return Less(a, b); +} + +// CHECK:STDOUT: --- int_less.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: bool = bool_literal true [template] +// CHECK:STDOUT: %.7: bool = bool_literal false [template] +// CHECK:STDOUT: %.8: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.9: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Less = %Less +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Less: = fn_decl @Less [template] { +// CHECK:STDOUT: %a.loc2_9.1: i32 = param a +// CHECK:STDOUT: @Less.%a: i32 = bind_name a, %a.loc2_9.1 +// CHECK:STDOUT: %b.loc2_17.1: i32 = param b +// CHECK:STDOUT: @Less.%b: i32 = bind_name b, %b.loc2_17.1 +// CHECK:STDOUT: %return.var.loc2: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc3_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc3_11.1 +// CHECK:STDOUT: %return.var.loc3: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc8_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc8_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc8_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc8_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc16_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc16_16.1 +// CHECK:STDOUT: %b.loc16_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc16_24.1 +// CHECK:STDOUT: %return.var.loc16: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Less(%a: i32, %b: i32) -> bool = "int.less"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %true_.ref.loc9: True = name_ref true_, %true_ +// CHECK:STDOUT: %Less.ref.loc9: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %.loc9_21: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_24: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %.loc9_20.1: init bool = call %Less.ref.loc9(%.loc9_21, %.loc9_24) [template = constants.%.6] +// CHECK:STDOUT: %.loc9_13.1: bool = value_of_initializer %.loc9_20.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_20.2: bool = converted %.loc9_20.1, %.loc9_13.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc9_20.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_13.2: type = block_arg !if.expr.result.loc9 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc10: False = name_ref false_, %false_ +// CHECK:STDOUT: %Less.ref.loc10: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %.loc10_22: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_25: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_21.1: init bool = call %Less.ref.loc10(%.loc10_22, %.loc10_25) [template = constants.%.7] +// CHECK:STDOUT: %.loc10_14.1: bool = value_of_initializer %.loc10_21.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc10_21.2: bool = converted %.loc10_21.1, %.loc10_14.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc10_21.2 br !if.expr.then.loc10 else br !if.expr.else.loc10 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc10: +// CHECK:STDOUT: %True.ref.loc10: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc10(%True.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc10: +// CHECK:STDOUT: %False.ref.loc10: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc10(%False.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc10: +// CHECK:STDOUT: %.loc10_14.2: type = block_arg !if.expr.result.loc10 [template = constants.%False] +// CHECK:STDOUT: %false_.ref.loc11: False = name_ref false_, %false_ +// CHECK:STDOUT: %Less.ref.loc11: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %.loc11_22: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_25: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %.loc11_21.1: init bool = call %Less.ref.loc11(%.loc11_22, %.loc11_25) [template = constants.%.7] +// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_21.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_21.2: bool = converted %.loc11_21.1, %.loc11_14.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc11_21.2 br !if.expr.then.loc11 else br !if.expr.else.loc11 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc11: +// CHECK:STDOUT: %True.ref.loc11: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc11(%True.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc11: +// CHECK:STDOUT: %False.ref.loc11: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc11(%False.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc11: +// CHECK:STDOUT: %.loc11_14.2: type = block_arg !if.expr.result.loc11 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc12: True = name_ref true_, %true_ +// CHECK:STDOUT: %Less.ref.loc12: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc12_28: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc12_27.1: init i32 = call %Negate.ref.loc12(%.loc12_28) [template = constants.%.9] +// CHECK:STDOUT: %.loc12_32: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %.loc12_20.1: i32 = value_of_initializer %.loc12_27.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_27.2: i32 = converted %.loc12_27.1, %.loc12_20.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_20.2: init bool = call %Less.ref.loc12(%.loc12_27.2, %.loc12_32) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_13.1: bool = value_of_initializer %.loc12_20.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_20.3: bool = converted %.loc12_20.2, %.loc12_13.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc12_20.3 br !if.expr.then.loc12 else br !if.expr.else.loc12 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc12: +// CHECK:STDOUT: %True.ref.loc12: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc12(%True.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc12: +// CHECK:STDOUT: %False.ref.loc12: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc12(%False.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc12: +// CHECK:STDOUT: %.loc12_13.2: type = block_arg !if.expr.result.loc12 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc13: False = name_ref false_, %false_ +// CHECK:STDOUT: %Less.ref.loc13: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %.loc13_22: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %Negate.ref.loc13: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc13_32: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_31.1: init i32 = call %Negate.ref.loc13(%.loc13_32) [template = constants.%.9] +// CHECK:STDOUT: %.loc13_21.1: i32 = value_of_initializer %.loc13_31.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_31.2: i32 = converted %.loc13_31.1, %.loc13_21.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_21.2: init bool = call %Less.ref.loc13(%.loc13_22, %.loc13_31.2) [template = constants.%.7] +// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %.loc13_21.2 [template = constants.%.7] +// CHECK:STDOUT: %.loc13_21.3: bool = converted %.loc13_21.2, %.loc13_14.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc13_21.3 br !if.expr.then.loc13 else br !if.expr.else.loc13 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc13: +// CHECK:STDOUT: %True.ref.loc13: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc13(%True.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc13: +// CHECK:STDOUT: %False.ref.loc13: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc13(%False.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc13: +// CHECK:STDOUT: %.loc13_14.2: type = block_arg !if.expr.result.loc13 [template = constants.%False] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Less.ref: = name_ref Less, file.%Less [template = file.%Less] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc17_14.1: init bool = call %Less.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc17_20: bool = value_of_initializer %.loc17_14.1 +// CHECK:STDOUT: %.loc17_14.2: bool = converted %.loc17_14.1, %.loc17_20 +// CHECK:STDOUT: return %.loc17_14.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/less_eq.carbon b/toolchain/check/testdata/builtins/int/less_eq.carbon new file mode 100644 index 000000000000..9fd4d576a26d --- /dev/null +++ b/toolchain/check/testdata/builtins/int/less_eq.carbon @@ -0,0 +1,215 @@ +// 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_less_eq.carbon + +fn LessEq(a: i32, b: i32) -> bool = "int.less_eq"; +fn Negate(a: i32) -> i32 = "int.negate"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + true_ as (if LessEq(1, 2) then True else False); + true_ as (if LessEq(1, 1) then True else False); + false_ as (if LessEq(1, 0) then True else False); + true_ as (if LessEq(Negate(1), 0) then True else False); + false_ as (if LessEq(0, Negate(1)) then True else False); +} + +fn RuntimeCall(a: i32, b: i32) -> bool { + return LessEq(a, b); +} + +// CHECK:STDOUT: --- int_less_eq.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: bool = bool_literal true [template] +// CHECK:STDOUT: %.7: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.8: bool = bool_literal false [template] +// CHECK:STDOUT: %.9: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .LessEq = %LessEq +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %LessEq: = fn_decl @LessEq [template] { +// CHECK:STDOUT: %a.loc2_11.1: i32 = param a +// CHECK:STDOUT: @LessEq.%a: i32 = bind_name a, %a.loc2_11.1 +// CHECK:STDOUT: %b.loc2_19.1: i32 = param b +// CHECK:STDOUT: @LessEq.%b: i32 = bind_name b, %b.loc2_19.1 +// CHECK:STDOUT: %return.var.loc2: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc3_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc3_11.1 +// CHECK:STDOUT: %return.var.loc3: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc8_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc8_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc8_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc8_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc16_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc16_16.1 +// CHECK:STDOUT: %b.loc16_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc16_24.1 +// CHECK:STDOUT: %return.var.loc16: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @LessEq(%a: i32, %b: i32) -> bool = "int.less_eq"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %true_.ref.loc9: True = name_ref true_, %true_ +// CHECK:STDOUT: %LessEq.ref.loc9: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %.loc9_23: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_26: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %.loc9_22.1: init bool = call %LessEq.ref.loc9(%.loc9_23, %.loc9_26) [template = constants.%.6] +// CHECK:STDOUT: %.loc9_13.1: bool = value_of_initializer %.loc9_22.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_22.2: bool = converted %.loc9_22.1, %.loc9_13.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc9_22.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_13.2: type = block_arg !if.expr.result.loc9 [template = constants.%True] +// CHECK:STDOUT: %true_.ref.loc10: True = name_ref true_, %true_ +// CHECK:STDOUT: %LessEq.ref.loc10: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %.loc10_23: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_26: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc10_22.1: init bool = call %LessEq.ref.loc10(%.loc10_23, %.loc10_26) [template = constants.%.6] +// CHECK:STDOUT: %.loc10_13.1: bool = value_of_initializer %.loc10_22.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc10_22.2: bool = converted %.loc10_22.1, %.loc10_13.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc10_22.2 br !if.expr.then.loc10 else br !if.expr.else.loc10 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc10: +// CHECK:STDOUT: %True.ref.loc10: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc10(%True.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc10: +// CHECK:STDOUT: %False.ref.loc10: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc10(%False.ref.loc10) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc10: +// CHECK:STDOUT: %.loc10_13.2: type = block_arg !if.expr.result.loc10 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc11: False = name_ref false_, %false_ +// CHECK:STDOUT: %LessEq.ref.loc11: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %.loc11_24: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc11_27: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_23.1: init bool = call %LessEq.ref.loc11(%.loc11_24, %.loc11_27) [template = constants.%.8] +// CHECK:STDOUT: %.loc11_14.1: bool = value_of_initializer %.loc11_23.1 [template = constants.%.8] +// CHECK:STDOUT: %.loc11_23.2: bool = converted %.loc11_23.1, %.loc11_14.1 [template = constants.%.8] +// CHECK:STDOUT: if %.loc11_23.2 br !if.expr.then.loc11 else br !if.expr.else.loc11 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc11: +// CHECK:STDOUT: %True.ref.loc11: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc11(%True.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc11: +// CHECK:STDOUT: %False.ref.loc11: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc11(%False.ref.loc11) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc11: +// CHECK:STDOUT: %.loc11_14.2: type = block_arg !if.expr.result.loc11 [template = constants.%False] +// CHECK:STDOUT: %true_.ref.loc12: True = name_ref true_, %true_ +// CHECK:STDOUT: %LessEq.ref.loc12: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %Negate.ref.loc12: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc12_30: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc12_29.1: init i32 = call %Negate.ref.loc12(%.loc12_30) [template = constants.%.9] +// CHECK:STDOUT: %.loc12_34: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc12_22.1: i32 = value_of_initializer %.loc12_29.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_29.2: i32 = converted %.loc12_29.1, %.loc12_22.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc12_22.2: init bool = call %LessEq.ref.loc12(%.loc12_29.2, %.loc12_34) [template = constants.%.6] +// CHECK:STDOUT: %.loc12_13.1: bool = value_of_initializer %.loc12_22.2 [template = constants.%.6] +// CHECK:STDOUT: %.loc12_22.3: bool = converted %.loc12_22.2, %.loc12_13.1 [template = constants.%.6] +// CHECK:STDOUT: if %.loc12_22.3 br !if.expr.then.loc12 else br !if.expr.else.loc12 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc12: +// CHECK:STDOUT: %True.ref.loc12: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc12(%True.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc12: +// CHECK:STDOUT: %False.ref.loc12: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc12(%False.ref.loc12) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc12: +// CHECK:STDOUT: %.loc12_13.2: type = block_arg !if.expr.result.loc12 [template = constants.%True] +// CHECK:STDOUT: %false_.ref.loc13: False = name_ref false_, %false_ +// CHECK:STDOUT: %LessEq.ref.loc13: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %.loc13_24: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %Negate.ref.loc13: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %.loc13_34: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_33.1: init i32 = call %Negate.ref.loc13(%.loc13_34) [template = constants.%.9] +// CHECK:STDOUT: %.loc13_23.1: i32 = value_of_initializer %.loc13_33.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_33.2: i32 = converted %.loc13_33.1, %.loc13_23.1 [template = constants.%.9] +// CHECK:STDOUT: %.loc13_23.2: init bool = call %LessEq.ref.loc13(%.loc13_24, %.loc13_33.2) [template = constants.%.8] +// CHECK:STDOUT: %.loc13_14.1: bool = value_of_initializer %.loc13_23.2 [template = constants.%.8] +// CHECK:STDOUT: %.loc13_23.3: bool = converted %.loc13_23.2, %.loc13_14.1 [template = constants.%.8] +// CHECK:STDOUT: if %.loc13_23.3 br !if.expr.then.loc13 else br !if.expr.else.loc13 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc13: +// CHECK:STDOUT: %True.ref.loc13: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc13(%True.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc13: +// CHECK:STDOUT: %False.ref.loc13: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc13(%False.ref.loc13) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc13: +// CHECK:STDOUT: %.loc13_14.2: type = block_arg !if.expr.result.loc13 [template = constants.%False] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %LessEq.ref: = name_ref LessEq, file.%LessEq [template = file.%LessEq] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc17_16.1: init bool = call %LessEq.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc17_22: bool = value_of_initializer %.loc17_16.1 +// CHECK:STDOUT: %.loc17_16.2: bool = converted %.loc17_16.1, %.loc17_22 +// CHECK:STDOUT: return %.loc17_16.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int_mod.carbon b/toolchain/check/testdata/builtins/int/mod.carbon similarity index 100% rename from toolchain/check/testdata/builtins/int_mod.carbon rename to toolchain/check/testdata/builtins/int/mod.carbon diff --git a/toolchain/check/testdata/builtins/int_mul.carbon b/toolchain/check/testdata/builtins/int/mul.carbon similarity index 100% rename from toolchain/check/testdata/builtins/int_mul.carbon rename to toolchain/check/testdata/builtins/int/mul.carbon diff --git a/toolchain/check/testdata/builtins/int_negate.carbon b/toolchain/check/testdata/builtins/int/negate.carbon similarity index 94% rename from toolchain/check/testdata/builtins/int_negate.carbon rename to toolchain/check/testdata/builtins/int/negate.carbon index 8628066f045b..baae674664bd 100644 --- a/toolchain/check/testdata/builtins/int_negate.carbon +++ b/toolchain/check/testdata/builtins/int/negate.carbon @@ -8,8 +8,8 @@ fn Negate(a: i32) -> i32 = "int.negate"; -var arr: [i32; Negate(Negate(1))]; -let arr_p: [i32; 1]* = &arr; +var arr: [i32; Negate(Negate(123))]; +let arr_p: [i32; 123]* = &arr; let n: i32 = Negate(1); @@ -115,10 +115,12 @@ 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 -1 [template] +// CHECK:STDOUT: %.1: i32 = int_literal 123 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -123 [template] // CHECK:STDOUT: %.3: type = array_type %.1, i32 [template] -// CHECK:STDOUT: %.4: type = ptr_type [i32; 1] [template] +// CHECK:STDOUT: %.4: type = ptr_type [i32; 123] [template] +// CHECK:STDOUT: %.5: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.6: i32 = int_literal -1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -134,25 +136,25 @@ let b: i32 = Negate(Sub(Negate(0x7FFFFFFF), 1)); // CHECK:STDOUT: } // CHECK:STDOUT: %Negate.ref.loc4_16: = name_ref Negate, %Negate [template = %Negate] // CHECK:STDOUT: %Negate.ref.loc4_23: = name_ref Negate, %Negate [template = %Negate] -// CHECK:STDOUT: %.loc4_30: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_30: i32 = int_literal 123 [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: %.loc4_35: type = array_type %.loc4_22.2, i32 [template = constants.%.3] +// CHECK:STDOUT: %arr.var: ref [i32; 123] = var arr +// CHECK:STDOUT: %arr: ref [i32; 123] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 123 [template = constants.%.1] +// CHECK:STDOUT: %.loc5_21: type = array_type %.loc5_18, i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_22: type = ptr_type [i32; 123] [template = constants.%.4] +// CHECK:STDOUT: %arr.ref: ref [i32; 123] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_26: [i32; 123]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 123]* = bind_name arr_p, %.loc5_26 // CHECK:STDOUT: %Negate.ref.loc7: = name_ref Negate, %Negate [template = %Negate] -// CHECK:STDOUT: %.loc7_21: i32 = int_literal 1 [template = constants.%.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: %.loc7_21: i32 = int_literal 1 [template = constants.%.5] +// CHECK:STDOUT: %.loc7_20.1: init i32 = call %Negate.ref.loc7(%.loc7_21) [template = constants.%.6] +// CHECK:STDOUT: %.loc7_23: i32 = value_of_initializer %.loc7_20.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc7_20.2: i32 = converted %.loc7_20.1, %.loc7_23 [template = constants.%.6] // CHECK:STDOUT: %n: i32 = bind_name n, %.loc7_20.2 // CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { // CHECK:STDOUT: %a.loc9_16.1: i32 = param a diff --git a/toolchain/check/testdata/builtins/int/neq.carbon b/toolchain/check/testdata/builtins/int/neq.carbon new file mode 100644 index 000000000000..e49c3cb05e7c --- /dev/null +++ b/toolchain/check/testdata/builtins/int/neq.carbon @@ -0,0 +1,136 @@ +// 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"; + +class True {} +class False {} + +fn F(true_: True, false_: False) { + false_ as (if Neq(1, 1) then True else False); + true_ as (if Neq(1, 2) then True else False); +} + +fn RuntimeCall(a: i32, b: i32) -> bool { + return Neq(a, b); +} + +// CHECK:STDOUT: --- int_neq.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %True: type = class_type @True [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %False: type = class_type @False [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: bool = bool_literal false [template] +// CHECK:STDOUT: %.6: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.7: bool = bool_literal true [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Neq = %Neq +// CHECK:STDOUT: .True = %True.decl +// CHECK:STDOUT: .False = %False.decl +// CHECK:STDOUT: .F = %F +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Neq: = 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 +// CHECK:STDOUT: } +// CHECK:STDOUT: %True.decl: type = class_decl @True [template = constants.%True] {} +// CHECK:STDOUT: %False.decl: type = class_decl @False [template = constants.%False] {} +// CHECK:STDOUT: %F: = fn_decl @F [template] { +// CHECK:STDOUT: %True.ref: type = name_ref True, %True.decl [template = constants.%True] +// CHECK:STDOUT: %true_.loc7_6.1: True = param true_ +// CHECK:STDOUT: @F.%true_: True = bind_name true_, %true_.loc7_6.1 +// CHECK:STDOUT: %False.ref: type = name_ref False, %False.decl [template = constants.%False] +// CHECK:STDOUT: %false_.loc7_19.1: False = param false_ +// CHECK:STDOUT: @F.%false_: False = bind_name false_, %false_.loc7_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc12_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc12_16.1 +// CHECK:STDOUT: %b.loc12_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc12_24.1 +// CHECK:STDOUT: %return.var.loc12: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @True { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%True +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @False { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%False +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Neq(%a: i32, %b: i32) -> bool = "int.neq"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%true_: True, %false_: False) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %false_.ref: False = name_ref false_, %false_ +// CHECK:STDOUT: %Neq.ref.loc8: = name_ref Neq, file.%Neq [template = file.%Neq] +// CHECK:STDOUT: %.loc8_21: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_24: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_20.1: init bool = call %Neq.ref.loc8(%.loc8_21, %.loc8_24) [template = constants.%.5] +// CHECK:STDOUT: %.loc8_14.1: bool = value_of_initializer %.loc8_20.1 [template = constants.%.5] +// CHECK:STDOUT: %.loc8_20.2: bool = converted %.loc8_20.1, %.loc8_14.1 [template = constants.%.5] +// CHECK:STDOUT: if %.loc8_20.2 br !if.expr.then.loc8 else br !if.expr.else.loc8 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc8: +// CHECK:STDOUT: %True.ref.loc8: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc8(%True.ref.loc8) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc8: +// CHECK:STDOUT: %False.ref.loc8: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc8(%False.ref.loc8) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc8: +// CHECK:STDOUT: %.loc8_14.2: type = block_arg !if.expr.result.loc8 [template = constants.%False] +// CHECK:STDOUT: %true_.ref: True = name_ref true_, %true_ +// CHECK:STDOUT: %Neq.ref.loc9: = name_ref Neq, file.%Neq [template = file.%Neq] +// CHECK:STDOUT: %.loc9_20: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_23: i32 = int_literal 2 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_19.1: init bool = call %Neq.ref.loc9(%.loc9_20, %.loc9_23) [template = constants.%.7] +// CHECK:STDOUT: %.loc9_13.1: bool = value_of_initializer %.loc9_19.1 [template = constants.%.7] +// CHECK:STDOUT: %.loc9_19.2: bool = converted %.loc9_19.1, %.loc9_13.1 [template = constants.%.7] +// CHECK:STDOUT: if %.loc9_19.2 br !if.expr.then.loc9 else br !if.expr.else.loc9 +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.then.loc9: +// CHECK:STDOUT: %True.ref.loc9: type = name_ref True, file.%True.decl [template = constants.%True] +// CHECK:STDOUT: br !if.expr.result.loc9(%True.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.else.loc9: +// CHECK:STDOUT: %False.ref.loc9: type = name_ref False, file.%False.decl [template = constants.%False] +// CHECK:STDOUT: br !if.expr.result.loc9(%False.ref.loc9) +// CHECK:STDOUT: +// CHECK:STDOUT: !if.expr.result.loc9: +// CHECK:STDOUT: %.loc9_13.2: type = block_arg !if.expr.result.loc9 [template = constants.%True] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Neq.ref: = 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: %.loc13_13.1: init bool = call %Neq.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc13_19: bool = value_of_initializer %.loc13_13.1 +// CHECK:STDOUT: %.loc13_13.2: bool = converted %.loc13_13.1, %.loc13_19 +// CHECK:STDOUT: return %.loc13_13.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/or.carbon b/toolchain/check/testdata/builtins/int/or.carbon new file mode 100644 index 000000000000..bd5d1ec74eaf --- /dev/null +++ b/toolchain/check/testdata/builtins/int/or.carbon @@ -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_or.carbon + +fn Or(a: i32, b: i32) -> i32 = "int.or"; + +var arr: [i32; Or(12, 10)]; +let arr_p: [i32; 14]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Or(a, b); +} + +// CHECK:STDOUT: --- int_or.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 12 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 10 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 14 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 14] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Or = %Or +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Or: = fn_decl @Or [template] { +// CHECK:STDOUT: %a.loc2_7.1: i32 = param a +// CHECK:STDOUT: @Or.%a: i32 = bind_name a, %a.loc2_7.1 +// CHECK:STDOUT: %b.loc2_15.1: i32 = param b +// CHECK:STDOUT: @Or.%b: i32 = bind_name b, %b.loc2_15.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Or.ref: = name_ref Or, %Or [template = %Or] +// CHECK:STDOUT: %.loc4_19: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_23: i32 = int_literal 10 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_18: init i32 = call %Or.ref(%.loc4_19, %.loc4_23) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_26: type = array_type %.loc4_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 14] = var arr +// CHECK:STDOUT: %arr: ref [i32; 14] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 14 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_20: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_21: type = ptr_type [i32; 14] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 14] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_25: [i32; 14]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 14]* = bind_name arr_p, %.loc5_25 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Or(%a: i32, %b: i32) -> i32 = "int.or"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Or.ref: = name_ref Or, file.%Or [template = file.%Or] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_12.1: init i32 = call %Or.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_18: i32 = value_of_initializer %.loc8_12.1 +// CHECK:STDOUT: %.loc8_12.2: i32 = converted %.loc8_12.1, %.loc8_18 +// CHECK:STDOUT: return %.loc8_12.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/right_shift.carbon b/toolchain/check/testdata/builtins/int/right_shift.carbon new file mode 100644 index 000000000000..61c5de76b80e --- /dev/null +++ b/toolchain/check/testdata/builtins/int/right_shift.carbon @@ -0,0 +1,269 @@ +// 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_right_shift.carbon + +fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; + +var arr: [i32; RightShift(22, 2)]; +let arr_p: [i32; 5]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return RightShift(a, b); +} + +// TODO: Test mixed types for LHS and RHS. + +// --- arith_shift.carbon + +// TODO: Also test unsigned / logical right shift. + +package ArithShift api; + +fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; +fn Negate(a: i32) -> i32 = "int.negate"; + +// -1 >> 1 is -1. +var arr1: [i32; Negate(RightShift(Negate(1), 1))]; +let arr1_p: [i32; 1]* = &arr1; + +// -10 >> 2 is -3. +var arr2: [i32; Negate(RightShift(Negate(10), 2))]; +let arr2_p: [i32; 3]* = &arr2; + +// --- fail_bad_shift.carbon + +package BadShift api; + +fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; +fn Negate(a: i32) -> i32 = "int.negate"; + +// Shift greater than size is disallowed. +let size_1: i32 = RightShift(1, 31); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:19: ERROR: Shift distance not in range [0, 32) in 1 >> 32. +// CHECK:STDERR: let size_2: i32 = RightShift(1, 32); +// CHECK:STDERR: ^~~~~~~~~~~ +// CHECK:STDERR: +let size_2: i32 = RightShift(1, 32); +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+4]]:19: ERROR: Shift distance not in range [0, 32) in 1 >> 33. +// CHECK:STDERR: let size_3: i32 = RightShift(1, 33); +// CHECK:STDERR: ^~~~~~~~~~~ +// CHECK:STDERR: +let size_3: i32 = RightShift(1, 33); + +// Negative shifts aren't allowed either. +// CHECK:STDERR: fail_bad_shift.carbon:[[@LINE+3]]:21: ERROR: Shift distance not in range [0, 32) in 1 >> -1. +// CHECK:STDERR: let negative: i32 = RightShift(1, Negate(1)); +// CHECK:STDERR: ^~~~~~~~~~~ +let negative: i32 = RightShift(1, Negate(1)); + +// CHECK:STDOUT: --- int_right_shift.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 22 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 5 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 5] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .RightShift = %RightShift +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift: = fn_decl @RightShift [template] { +// CHECK:STDOUT: %a.loc2_15.1: i32 = param a +// CHECK:STDOUT: @RightShift.%a: i32 = bind_name a, %a.loc2_15.1 +// CHECK:STDOUT: %b.loc2_23.1: i32 = param b +// CHECK:STDOUT: @RightShift.%b: i32 = bind_name b, %b.loc2_23.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift.ref: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %.loc4_27: i32 = int_literal 22 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_31: i32 = int_literal 2 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_26: init i32 = call %RightShift.ref(%.loc4_27, %.loc4_31) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_33: type = array_type %.loc4_26, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 5] = var arr +// CHECK:STDOUT: %arr: ref [i32; 5] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 5 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 5] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 5] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 5]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 5]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RightShift(%a: i32, %b: i32) -> i32 = "int.right_shift"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %RightShift.ref: = name_ref RightShift, file.%RightShift [template = file.%RightShift] +// CHECK:STDOUT: %a.ref: i32 = name_ref a, %a +// CHECK:STDOUT: %b.ref: i32 = name_ref b, %b +// CHECK:STDOUT: %.loc8_20.1: init i32 = call %RightShift.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc8_26: i32 = value_of_initializer %.loc8_20.1 +// CHECK:STDOUT: %.loc8_20.2: i32 = converted %.loc8_20.1, %.loc8_26 +// CHECK:STDOUT: return %.loc8_20.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- arith_shift.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal -1 [template] +// CHECK:STDOUT: %.3: type = array_type %.1, i32 [template] +// CHECK:STDOUT: %.4: type = ptr_type [i32; 1] [template] +// CHECK:STDOUT: %.5: i32 = int_literal 10 [template] +// CHECK:STDOUT: %.6: i32 = int_literal -10 [template] +// CHECK:STDOUT: %.7: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.8: i32 = int_literal -3 [template] +// CHECK:STDOUT: %.9: i32 = int_literal 3 [template] +// CHECK:STDOUT: %.10: type = array_type %.9, i32 [template] +// CHECK:STDOUT: %.11: type = ptr_type [i32; 3] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .RightShift = %RightShift +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .arr1 = %arr1 +// CHECK:STDOUT: .arr2 = %arr2 +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift: = fn_decl @RightShift [template] { +// CHECK:STDOUT: %a.loc6_15.1: i32 = param a +// CHECK:STDOUT: @RightShift.%a: i32 = bind_name a, %a.loc6_15.1 +// CHECK:STDOUT: %b.loc6_23.1: i32 = param b +// CHECK:STDOUT: @RightShift.%b: i32 = bind_name b, %b.loc6_23.1 +// CHECK:STDOUT: %return.var.loc6: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc7_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc7_11.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.ref.loc10_17: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %RightShift.ref.loc10: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %Negate.ref.loc10_35: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc10_42: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc10_41.1: init i32 = call %Negate.ref.loc10_35(%.loc10_42) [template = constants.%.2] +// CHECK:STDOUT: %.loc10_46: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc10_34.1: i32 = value_of_initializer %.loc10_41.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_41.2: i32 = converted %.loc10_41.1, %.loc10_34.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_34.2: init i32 = call %RightShift.ref.loc10(%.loc10_41.2, %.loc10_46) [template = constants.%.2] +// CHECK:STDOUT: %.loc10_23.1: i32 = value_of_initializer %.loc10_34.2 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_34.3: i32 = converted %.loc10_34.2, %.loc10_23.1 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_23.2: init i32 = call %Negate.ref.loc10_17(%.loc10_34.3) [template = constants.%.1] +// CHECK:STDOUT: %.loc10_49: type = array_type %.loc10_23.2, i32 [template = constants.%.3] +// CHECK:STDOUT: %arr1.var: ref [i32; 1] = var arr1 +// CHECK:STDOUT: %arr1: ref [i32; 1] = bind_name arr1, %arr1.var +// CHECK:STDOUT: %.loc11_19: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc11_20: type = array_type %.loc11_19, i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc11_21: type = ptr_type [i32; 1] [template = constants.%.4] +// CHECK:STDOUT: %arr1.ref: ref [i32; 1] = name_ref arr1, %arr1 +// CHECK:STDOUT: %.loc11_25: [i32; 1]* = addr_of %arr1.ref +// CHECK:STDOUT: %arr1_p: [i32; 1]* = bind_name arr1_p, %.loc11_25 +// CHECK:STDOUT: %Negate.ref.loc14_17: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %RightShift.ref.loc14: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %Negate.ref.loc14_35: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc14_42: i32 = int_literal 10 [template = constants.%.5] +// CHECK:STDOUT: %.loc14_41.1: init i32 = call %Negate.ref.loc14_35(%.loc14_42) [template = constants.%.6] +// CHECK:STDOUT: %.loc14_47: i32 = int_literal 2 [template = constants.%.7] +// CHECK:STDOUT: %.loc14_34.1: i32 = value_of_initializer %.loc14_41.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc14_41.2: i32 = converted %.loc14_41.1, %.loc14_34.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc14_34.2: init i32 = call %RightShift.ref.loc14(%.loc14_41.2, %.loc14_47) [template = constants.%.8] +// CHECK:STDOUT: %.loc14_23.1: i32 = value_of_initializer %.loc14_34.2 [template = constants.%.8] +// CHECK:STDOUT: %.loc14_34.3: i32 = converted %.loc14_34.2, %.loc14_23.1 [template = constants.%.8] +// CHECK:STDOUT: %.loc14_23.2: init i32 = call %Negate.ref.loc14_17(%.loc14_34.3) [template = constants.%.9] +// CHECK:STDOUT: %.loc14_50: type = array_type %.loc14_23.2, i32 [template = constants.%.10] +// CHECK:STDOUT: %arr2.var: ref [i32; 3] = var arr2 +// CHECK:STDOUT: %arr2: ref [i32; 3] = bind_name arr2, %arr2.var +// CHECK:STDOUT: %.loc15_19: i32 = int_literal 3 [template = constants.%.9] +// CHECK:STDOUT: %.loc15_20: type = array_type %.loc15_19, i32 [template = constants.%.10] +// CHECK:STDOUT: %.loc15_21: type = ptr_type [i32; 3] [template = constants.%.11] +// CHECK:STDOUT: %arr2.ref: ref [i32; 3] = name_ref arr2, %arr2 +// CHECK:STDOUT: %.loc15_25: [i32; 3]* = addr_of %arr2.ref +// CHECK:STDOUT: %arr2_p: [i32; 3]* = bind_name arr2_p, %.loc15_25 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RightShift(%a: i32, %b: i32) -> i32 = "int.right_shift"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_shift.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 31 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 0 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 32 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 33 [template] +// CHECK:STDOUT: %.6: i32 = int_literal -1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .RightShift = %RightShift +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift: = fn_decl @RightShift [template] { +// CHECK:STDOUT: %a.loc4_15.1: i32 = param a +// CHECK:STDOUT: @RightShift.%a: i32 = bind_name a, %a.loc4_15.1 +// CHECK:STDOUT: %b.loc4_23.1: i32 = param b +// CHECK:STDOUT: @RightShift.%b: i32 = bind_name b, %b.loc4_23.1 +// CHECK:STDOUT: %return.var.loc4: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc5_11.1: i32 = param a +// CHECK:STDOUT: @Negate.%a: i32 = bind_name a, %a.loc5_11.1 +// CHECK:STDOUT: %return.var.loc5: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RightShift.ref.loc8: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %.loc8_30: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_33: i32 = int_literal 31 [template = constants.%.2] +// CHECK:STDOUT: %.loc8_29.1: init i32 = call %RightShift.ref.loc8(%.loc8_30, %.loc8_33) [template = constants.%.3] +// CHECK:STDOUT: %.loc8_36: i32 = value_of_initializer %.loc8_29.1 [template = constants.%.3] +// CHECK:STDOUT: %.loc8_29.2: i32 = converted %.loc8_29.1, %.loc8_36 [template = constants.%.3] +// CHECK:STDOUT: %size_1: i32 = bind_name size_1, %.loc8_29.2 +// CHECK:STDOUT: %RightShift.ref.loc13: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %.loc13_30: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc13_33: i32 = int_literal 32 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_29.1: init i32 = call %RightShift.ref.loc13(%.loc13_30, %.loc13_33) [template = ] +// CHECK:STDOUT: %.loc13_36: i32 = value_of_initializer %.loc13_29.1 [template = ] +// CHECK:STDOUT: %.loc13_29.2: i32 = converted %.loc13_29.1, %.loc13_36 [template = ] +// CHECK:STDOUT: %size_2: i32 = bind_name size_2, %.loc13_29.2 +// CHECK:STDOUT: %RightShift.ref.loc18: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %.loc18_30: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc18_33: i32 = int_literal 33 [template = constants.%.5] +// CHECK:STDOUT: %.loc18_29.1: init i32 = call %RightShift.ref.loc18(%.loc18_30, %.loc18_33) [template = ] +// CHECK:STDOUT: %.loc18_36: i32 = value_of_initializer %.loc18_29.1 [template = ] +// CHECK:STDOUT: %.loc18_29.2: i32 = converted %.loc18_29.1, %.loc18_36 [template = ] +// CHECK:STDOUT: %size_3: i32 = bind_name size_3, %.loc18_29.2 +// CHECK:STDOUT: %RightShift.ref.loc24: = name_ref RightShift, %RightShift [template = %RightShift] +// CHECK:STDOUT: %.loc24_32: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %Negate.ref: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc24_42: i32 = int_literal 1 [template = constants.%.1] +// CHECK:STDOUT: %.loc24_41.1: init i32 = call %Negate.ref(%.loc24_42) [template = constants.%.6] +// CHECK:STDOUT: %.loc24_31.1: i32 = value_of_initializer %.loc24_41.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc24_41.2: i32 = converted %.loc24_41.1, %.loc24_31.1 [template = constants.%.6] +// CHECK:STDOUT: %.loc24_31.2: init i32 = call %RightShift.ref.loc24(%.loc24_32, %.loc24_41.2) [template = ] +// CHECK:STDOUT: %.loc24_45: i32 = value_of_initializer %.loc24_31.2 [template = ] +// CHECK:STDOUT: %.loc24_31.3: i32 = converted %.loc24_31.2, %.loc24_45 [template = ] +// CHECK:STDOUT: %negative: i32 = bind_name negative, %.loc24_31.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RightShift(%a: i32, %b: i32) -> i32 = "int.right_shift"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: i32) -> i32 = "int.negate"; +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int_sub.carbon b/toolchain/check/testdata/builtins/int/sub.carbon similarity index 100% rename from toolchain/check/testdata/builtins/int_sub.carbon rename to toolchain/check/testdata/builtins/int/sub.carbon diff --git a/toolchain/check/testdata/builtins/int/xor.carbon b/toolchain/check/testdata/builtins/int/xor.carbon new file mode 100644 index 000000000000..65a7680c8d91 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/xor.carbon @@ -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_xor.carbon + +fn Xor(a: i32, b: i32) -> i32 = "int.xor"; + +var arr: [i32; Xor(12, 10)]; +let arr_p: [i32; 6]* = &arr; + +fn RuntimeCall(a: i32, b: i32) -> i32 { + return Xor(a, b); +} + +// CHECK:STDOUT: --- int_xor.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 12 [template] +// CHECK:STDOUT: %.2: i32 = int_literal 10 [template] +// CHECK:STDOUT: %.3: i32 = int_literal 6 [template] +// CHECK:STDOUT: %.4: type = array_type %.3, i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type [i32; 6] [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Xor = %Xor +// CHECK:STDOUT: .arr = %arr +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Xor: = fn_decl @Xor [template] { +// CHECK:STDOUT: %a.loc2_8.1: i32 = param a +// CHECK:STDOUT: @Xor.%a: i32 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: i32 = param b +// CHECK:STDOUT: @Xor.%b: i32 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: %return.var.loc2: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Xor.ref: = name_ref Xor, %Xor [template = %Xor] +// CHECK:STDOUT: %.loc4_20: i32 = int_literal 12 [template = constants.%.1] +// CHECK:STDOUT: %.loc4_24: i32 = int_literal 10 [template = constants.%.2] +// CHECK:STDOUT: %.loc4_19: init i32 = call %Xor.ref(%.loc4_20, %.loc4_24) [template = constants.%.3] +// CHECK:STDOUT: %.loc4_27: type = array_type %.loc4_19, i32 [template = constants.%.4] +// CHECK:STDOUT: %arr.var: ref [i32; 6] = var arr +// CHECK:STDOUT: %arr: ref [i32; 6] = bind_name arr, %arr.var +// CHECK:STDOUT: %.loc5_18: i32 = int_literal 6 [template = constants.%.3] +// CHECK:STDOUT: %.loc5_19: type = array_type %.loc5_18, i32 [template = constants.%.4] +// CHECK:STDOUT: %.loc5_20: type = ptr_type [i32; 6] [template = constants.%.5] +// CHECK:STDOUT: %arr.ref: ref [i32; 6] = name_ref arr, %arr +// CHECK:STDOUT: %.loc5_24: [i32; 6]* = addr_of %arr.ref +// CHECK:STDOUT: %arr_p: [i32; 6]* = bind_name arr_p, %.loc5_24 +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc7_16.1: i32 = param a +// CHECK:STDOUT: @RuntimeCall.%a: i32 = bind_name a, %a.loc7_16.1 +// CHECK:STDOUT: %b.loc7_24.1: i32 = param b +// CHECK:STDOUT: @RuntimeCall.%b: i32 = bind_name b, %b.loc7_24.1 +// CHECK:STDOUT: %return.var.loc7: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Xor(%a: i32, %b: i32) -> i32 = "int.xor"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: i32, %b: i32) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Xor.ref: = name_ref Xor, file.%Xor [template = file.%Xor] +// 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 %Xor.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: diff --git a/toolchain/check/testdata/builtins/int_eq.carbon b/toolchain/check/testdata/builtins/int_eq.carbon deleted file mode 100644 index 00a2a740bba0..000000000000 --- a/toolchain/check/testdata/builtins/int_eq.carbon +++ /dev/null @@ -1,101 +0,0 @@ -// 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 [template] { -// CHECK:STDOUT: .Eq = %Eq -// CHECK:STDOUT: .RuntimeCall = %RuntimeCall -// CHECK:STDOUT: } -// CHECK:STDOUT: %Eq: = 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 -// CHECK:STDOUT: } -// CHECK:STDOUT: %Eq.ref.loc5: = 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: = 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: = 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 -// 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: = 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 [template] { -// CHECK:STDOUT: .WrongResult = %WrongResult -// CHECK:STDOUT: } -// CHECK:STDOUT: %WrongResult: = 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 -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @WrongResult(%a: i32, %b: i32) -> i32; -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int_neq.carbon b/toolchain/check/testdata/builtins/int_neq.carbon deleted file mode 100644 index c49e74b55b3b..000000000000 --- a/toolchain/check/testdata/builtins/int_neq.carbon +++ /dev/null @@ -1,75 +0,0 @@ -// 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 [template] { -// CHECK:STDOUT: .Neq = %Neq -// CHECK:STDOUT: .RuntimeCall = %RuntimeCall -// CHECK:STDOUT: } -// CHECK:STDOUT: %Neq: = 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 -// CHECK:STDOUT: } -// CHECK:STDOUT: %Neq.ref.loc5: = 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: = 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: = 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 -// 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: = 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: diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 2183574dbf41..517d034fe597 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -246,6 +246,7 @@ CARBON_DIAGNOSTIC_KIND(BreakOutsideLoop) CARBON_DIAGNOSTIC_KIND(CompileTimeDivisionByZero) CARBON_DIAGNOSTIC_KIND(CompileTimeIntegerOverflow) CARBON_DIAGNOSTIC_KIND(CompileTimeIntegerNegateOverflow) +CARBON_DIAGNOSTIC_KIND(CompileTimeShiftOutOfRange) CARBON_DIAGNOSTIC_KIND(ContinueOutsideLoop) CARBON_DIAGNOSTIC_KIND(CopyOfUncopyableType) CARBON_DIAGNOSTIC_KIND(DerefOfNonPointer) diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index 096da8312d3f..72faea545b37 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -12,7 +12,6 @@ #include "llvm/Support/Casting.h" #include "toolchain/lower/function_context.h" #include "toolchain/sem_ir/builtin_function_kind.h" -#include "toolchain/sem_ir/function.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/typed_insts.h" @@ -168,6 +167,36 @@ auto HandleBuiltin(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, CARBON_FATAL() << "TODO: Add support: " << inst; } +// Get the predicate to use for an `icmp` instruction generated for the +// specified builtin. +static auto GetBuiltinICmpPredicate(SemIR::BuiltinFunctionKind builtin_kind, + bool is_signed) + -> llvm::CmpInst::Predicate { + switch (builtin_kind) { + case SemIR::BuiltinFunctionKind::IntEq: + return llvm::CmpInst::ICMP_EQ; + case SemIR::BuiltinFunctionKind::IntNeq: + return llvm::CmpInst::ICMP_NE; + case SemIR::BuiltinFunctionKind::IntLess: + return is_signed ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT; + case SemIR::BuiltinFunctionKind::IntLessEq: + return is_signed ? llvm::CmpInst::ICMP_SLE : llvm::CmpInst::ICMP_ULE; + case SemIR::BuiltinFunctionKind::IntGreater: + return is_signed ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT; + case SemIR::BuiltinFunctionKind::IntGreaterEq: + return is_signed ? llvm::CmpInst::ICMP_SGE : llvm::CmpInst::ICMP_UGE; + default: + CARBON_FATAL() << "Unexpected builtin kind " << builtin_kind; + } +} + +// Returns whether the specified instruction has a signed integer type. +static auto IsSignedInt(FunctionContext& context, SemIR::InstId int_id) + -> bool { + return context.sem_ir().types().IsSignedInt( + context.sem_ir().insts().Get(int_id).type_id()); +} + // Handles a call to a builtin function. static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, SemIR::BuiltinFunctionKind builtin_kind, @@ -191,6 +220,15 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, /*HasNSW=*/SignedOverflowIsUB)); return; } + case SemIR::BuiltinFunctionKind::IntComplement: { + // Lower `^x` as `-1 ^ x`. + auto* operand = context.GetValue(arg_ids[0]); + context.SetLocal(inst_id, + context.builder().CreateXor( + llvm::ConstantInt::getSigned(operand->getType(), -1), + operand, "cmpl")); + return; + } case SemIR::BuiltinFunctionKind::IntAdd: { context.SetLocal(inst_id, context.builder().CreateAdd( context.GetValue(arg_ids[0]), @@ -227,16 +265,52 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, context.GetValue(arg_ids[1]), "rem")); return; } - case SemIR::BuiltinFunctionKind::IntEq: { - context.SetLocal(inst_id, context.builder().CreateICmpEQ( + case SemIR::BuiltinFunctionKind::IntAnd: { + context.SetLocal(inst_id, context.builder().CreateAnd( context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "eq")); + context.GetValue(arg_ids[1]), "and")); return; } - case SemIR::BuiltinFunctionKind::IntNeq: { - context.SetLocal(inst_id, context.builder().CreateICmpNE( + case SemIR::BuiltinFunctionKind::IntOr: { + context.SetLocal(inst_id, context.builder().CreateOr( context.GetValue(arg_ids[0]), - context.GetValue(arg_ids[1]), "neq")); + context.GetValue(arg_ids[1]), "or")); + return; + } + case SemIR::BuiltinFunctionKind::IntXor: { + context.SetLocal(inst_id, context.builder().CreateXor( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "xor")); + return; + } + case SemIR::BuiltinFunctionKind::IntLeftShift: { + context.SetLocal(inst_id, context.builder().CreateShl( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "shl")); + return; + } + case SemIR::BuiltinFunctionKind::IntRightShift: { + context.SetLocal(inst_id, IsSignedInt(context, inst_id) + ? context.builder().CreateAShr( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "shr") + : context.builder().CreateLShr( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "shr")); + return; + } + case SemIR::BuiltinFunctionKind::IntEq: + case SemIR::BuiltinFunctionKind::IntNeq: + case SemIR::BuiltinFunctionKind::IntLess: + case SemIR::BuiltinFunctionKind::IntLessEq: + case SemIR::BuiltinFunctionKind::IntGreater: + case SemIR::BuiltinFunctionKind::IntGreaterEq: { + context.SetLocal(inst_id, + context.builder().CreateICmp( + GetBuiltinICmpPredicate( + builtin_kind, IsSignedInt(context, arg_ids[0])), + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "cmp")); return; } } diff --git a/toolchain/lower/testdata/builtins/int.carbon b/toolchain/lower/testdata/builtins/int.carbon index 706cc8477e76..9b31d75e599a 100644 --- a/toolchain/lower/testdata/builtins/int.carbon +++ b/toolchain/lower/testdata/builtins/int.carbon @@ -4,13 +4,149 @@ // // AUTOUPDATE +fn Negate(a: i32) -> i32 = "int.negate"; +fn TestNegate(a: i32) -> i32 { return Negate(a); } + fn Add(a: i32, b: i32) -> i32 = "int.add"; fn TestAdd(a: i32, b: i32) -> i32 { return Add(a, b); } +fn Sub(a: i32, b: i32) -> i32 = "int.sub"; +fn TestSub(a: i32, b: i32) -> i32 { return Sub(a, b); } + +fn Mul(a: i32, b: i32) -> i32 = "int.mul"; +fn TestMul(a: i32, b: i32) -> i32 { return Mul(a, b); } + +fn Div(a: i32, b: i32) -> i32 = "int.div"; +fn TestDiv(a: i32, b: i32) -> i32 { return Div(a, b); } + +fn Mod(a: i32, b: i32) -> i32 = "int.mod"; +fn TestMod(a: i32, b: i32) -> i32 { return Mod(a, b); } + +fn Complement(a: i32) -> i32 = "int.complement"; +fn TestComplement(a: i32) -> i32 { return Complement(a); } + +fn And(a: i32, b: i32) -> i32 = "int.and"; +fn TestAnd(a: i32, b: i32) -> i32 { return And(a, b); } + +fn Or(a: i32, b: i32) -> i32 = "int.or"; +fn TestOr(a: i32, b: i32) -> i32 { return Or(a, b); } + +fn Xor(a: i32, b: i32) -> i32 = "int.xor"; +fn TestXor(a: i32, b: i32) -> i32 { return Xor(a, b); } + +fn LeftShift(a: i32, b: i32) -> i32 = "int.left_shift"; +fn TestLeftShift(a: i32, b: i32) -> i32 { return LeftShift(a, b); } + +fn RightShift(a: i32, b: i32) -> i32 = "int.right_shift"; +fn TestRightShift(a: i32, b: i32) -> i32 { return RightShift(a, b); } + +fn Eq(a: i32, b: i32) -> bool = "int.eq"; +fn TestEq(a: i32, b: i32) -> bool { return Eq(a, b); } + +fn Neq(a: i32, b: i32) -> bool = "int.neq"; +fn TestNeq(a: i32, b: i32) -> bool { return Neq(a, b); } + +fn Less(a: i32, b: i32) -> bool = "int.less"; +fn TestLess(a: i32, b: i32) -> bool { return Less(a, b); } + +fn LessEq(a: i32, b: i32) -> bool = "int.less_eq"; +fn TestLessEq(a: i32, b: i32) -> bool { return LessEq(a, b); } + +fn Greater(a: i32, b: i32) -> bool = "int.greater"; +fn TestGreater(a: i32, b: i32) -> bool { return Greater(a, b); } + +fn GreaterEq(a: i32, b: i32) -> bool = "int.greater_eq"; +fn TestGreaterEq(a: i32, b: i32) -> bool { return GreaterEq(a, b); } + // CHECK:STDOUT: ; ModuleID = 'int.carbon' // CHECK:STDOUT: source_filename = "int.carbon" // CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestNegate(i32 %a) { +// CHECK:STDOUT: %neg = sub i32 0, %a +// CHECK:STDOUT: ret i32 %neg +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: define i32 @TestAdd(i32 %a, i32 %b) { // CHECK:STDOUT: %add = add i32 %a, %b // CHECK:STDOUT: ret i32 %add // CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestSub(i32 %a, i32 %b) { +// CHECK:STDOUT: %sub = sub i32 %a, %b +// CHECK:STDOUT: ret i32 %sub +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestMul(i32 %a, i32 %b) { +// CHECK:STDOUT: %mul = mul i32 %a, %b +// CHECK:STDOUT: ret i32 %mul +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestDiv(i32 %a, i32 %b) { +// CHECK:STDOUT: %div = sdiv i32 %a, %b +// CHECK:STDOUT: ret i32 %div +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestMod(i32 %a, i32 %b) { +// CHECK:STDOUT: %rem = srem i32 %a, %b +// CHECK:STDOUT: ret i32 %rem +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestComplement(i32 %a) { +// CHECK:STDOUT: %cmpl = xor i32 -1, %a +// CHECK:STDOUT: ret i32 %cmpl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestAnd(i32 %a, i32 %b) { +// CHECK:STDOUT: %and = and i32 %a, %b +// CHECK:STDOUT: ret i32 %and +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestOr(i32 %a, i32 %b) { +// CHECK:STDOUT: %or = or i32 %a, %b +// CHECK:STDOUT: ret i32 %or +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestXor(i32 %a, i32 %b) { +// CHECK:STDOUT: %xor = xor i32 %a, %b +// CHECK:STDOUT: ret i32 %xor +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestLeftShift(i32 %a, i32 %b) { +// CHECK:STDOUT: %shl = shl i32 %a, %b +// CHECK:STDOUT: ret i32 %shl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @TestRightShift(i32 %a, i32 %b) { +// CHECK:STDOUT: %shr = ashr i32 %a, %b +// CHECK:STDOUT: ret i32 %shr +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestEq(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp eq i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestNeq(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp ne i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestLess(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp slt i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestLessEq(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp sle i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestGreater(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp sgt i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @TestGreaterEq(i32 %a, i32 %b) { +// CHECK:STDOUT: %cmp = icmp sge i32 %a, %b +// CHECK:STDOUT: ret i1 %cmp +// CHECK:STDOUT: } diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index 268f7d2cf2da..1b4896f3df5b 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -24,14 +24,14 @@ struct BuiltinInfo { }; // The maximum number of type parameters any builtin needs. -constexpr int MaxTypeParams = 1; +constexpr int MaxTypeParams = 2; // State used when validating a builtin signature that persists between // individual checks. struct ValidateState { // The type values of type parameters in the builtin signature. Invalid if // either no value has been deduced yet or the parameter is not used. - TypeId type_params[MaxTypeParams] = {TypeId::Invalid}; + TypeId type_params[MaxTypeParams] = {TypeId::Invalid, TypeId::Invalid}; }; // Constraint that a type is generic type parameter `I` of the builtin, @@ -125,6 +125,10 @@ namespace BuiltinFunctionInfo { // generic type parameter that is constrained to be an integer type. using IntT = TypeParam<0, AnyInt>; +// Convenience name used in the builtin type signatures below for a second +// generic type parameter that is constrained to be an integer type. +using IntU = TypeParam<1, AnyInt>; + // Not a builtin function. constexpr BuiltinInfo None = {"", nullptr}; @@ -152,6 +156,30 @@ constexpr BuiltinInfo IntDiv = {"int.div", constexpr BuiltinInfo IntMod = {"int.mod", ValidateSignatureIntT>}; +// "int.complement": integer bitwise complement. +constexpr BuiltinInfo IntComplement = {"int.complement", + ValidateSignatureIntT>}; + +// "int.and": integer bitwise and. +constexpr BuiltinInfo IntAnd = {"int.and", + ValidateSignatureIntT>}; + +// "int.or": integer bitwise or. +constexpr BuiltinInfo IntOr = {"int.or", + ValidateSignatureIntT>}; + +// "int.xor": integer bitwise xor. +constexpr BuiltinInfo IntXor = {"int.xor", + ValidateSignatureIntT>}; + +// "int.left_shift": integer left shift. +constexpr BuiltinInfo IntLeftShift = { + "int.left_shift", ValidateSignatureIntT>}; + +// "int.left_shift": integer right shift. +constexpr BuiltinInfo IntRightShift = { + "int.right_shift", ValidateSignatureIntT>}; + // "int.eq": integer equality comparison. constexpr BuiltinInfo IntEq = {"int.eq", ValidateSignatureBool>}; @@ -160,6 +188,22 @@ constexpr BuiltinInfo IntEq = {"int.eq", constexpr BuiltinInfo IntNeq = {"int.neq", ValidateSignatureBool>}; +// "int.less": integer less than comparison. +constexpr BuiltinInfo IntLess = {"int.less", + ValidateSignatureBool>}; + +// "int.less_eq": integer less than or equal comparison. +constexpr BuiltinInfo IntLessEq = {"int.less_eq", + ValidateSignatureBool>}; + +// "int.greater": integer greater than comparison. +constexpr BuiltinInfo IntGreater = {"int.greater", + ValidateSignatureBool>}; + +// "int.greater_eq": integer greater than or equal comparison. +constexpr BuiltinInfo IntGreaterEq = { + "int.greater_eq", ValidateSignatureBool>}; + } // namespace BuiltinFunctionInfo CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinFunctionKind) = { diff --git a/toolchain/sem_ir/builtin_function_kind.def b/toolchain/sem_ir/builtin_function_kind.def index 600c49aba506..13f1c8241148 100644 --- a/toolchain/sem_ir/builtin_function_kind.def +++ b/toolchain/sem_ir/builtin_function_kind.def @@ -17,13 +17,29 @@ #endif CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(None) + +// Integer arithmetic. CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntNegate) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntAdd) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntSub) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntMul) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntDiv) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntMod) + +// Integer bitwise. +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntComplement) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntAnd) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntOr) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntXor) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLeftShift) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntRightShift) + +// Integer comparison. CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntEq) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntNeq) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLess) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLessEq) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreater) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreaterEq) #undef CARBON_SEM_IR_BUILTIN_FUNCTION_KIND