diff --git a/toolchain/base/value_store.h b/toolchain/base/value_store.h index a3ef581d934e..e925f0e51ba8 100644 --- a/toolchain/base/value_store.h +++ b/toolchain/base/value_store.h @@ -9,6 +9,7 @@ #include "common/check.h" #include "common/ostream.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Sequence.h" @@ -59,6 +60,18 @@ struct IntId : public IdBase, public Printable { }; constexpr IntId IntId::Invalid(IntId::InvalidIndex); +// Corresponds to a float value represented by an APFloat. +struct FloatId : public IdBase, public Printable { + using ValueType = const llvm::APFloat; + static const FloatId Invalid; + using IdBase::IdBase; + auto Print(llvm::raw_ostream& out) const -> void { + out << "float"; + IdBase::Print(out); + } +}; +constexpr FloatId FloatId::Invalid(FloatId::InvalidIndex); + // Corresponds to a Real value. struct RealId : public IdBase, public Printable { using ValueType = const Real; @@ -274,6 +287,8 @@ class SharedValueStores : public Yaml::Printable { auto ints() const -> const ValueStore& { return ints_; } auto reals() -> ValueStore& { return reals_; } auto reals() const -> const ValueStore& { return reals_; } + auto floats() -> ValueStore& { return floats_; } + auto floats() const -> const ValueStore& { return floats_; } auto string_literal_values() -> StringStoreWrapper& { return string_literal_values_; } @@ -300,6 +315,7 @@ class SharedValueStores : public Yaml::Printable { private: ValueStore ints_; ValueStore reals_; + ValueStore floats_; ValueStore strings_; StringStoreWrapper identifiers_; diff --git a/toolchain/base/value_store_test.cpp b/toolchain/base/value_store_test.cpp index 28639a32fbb6..bf377f5c719a 100644 --- a/toolchain/base/value_store_test.cpp +++ b/toolchain/base/value_store_test.cpp @@ -59,6 +59,24 @@ TEST(ValueStore, Real) { EXPECT_THAT(real2.is_decimal, Eq(real2_copy.is_decimal)); } +TEST(ValueStore, Float) { + llvm::APFloat float1(1.0); + llvm::APFloat float2(2.0); + + SharedValueStores value_stores; + FloatId id1 = value_stores.floats().Add(float1); + FloatId id2 = value_stores.floats().Add(float2); + + ASSERT_TRUE(id1.is_valid()); + ASSERT_TRUE(id2.is_valid()); + EXPECT_THAT(id1, Not(Eq(id2))); + + EXPECT_THAT(value_stores.floats().Get(id1).compare(float1), + Eq(llvm::APFloatBase::cmpEqual)); + EXPECT_THAT(value_stores.floats().Get(id2).compare(float2), + Eq(llvm::APFloatBase::cmpEqual)); +} + TEST(ValueStore, String) { std::string a = "a"; std::string b = "b"; diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index bd4a7de2a536..46359628d8f8 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -978,6 +978,7 @@ class TypeCompleter { case SemIR::Converted::Kind: case SemIR::Deref::Kind: case SemIR::FacetTypeAccess::Kind: + case SemIR::FloatLiteral::Kind: case SemIR::FieldDecl::Kind: case SemIR::FunctionDecl::Kind: case SemIR::ImplDecl::Kind: @@ -1055,6 +1056,7 @@ class TypeCompleter { case SemIR::AssociatedEntityType::Kind: case SemIR::BindSymbolicName::Kind: + case SemIR::FloatType::Kind: case SemIR::IntType::Kind: case SemIR::PointerType::Kind: case SemIR::UnboundElementType::Kind: diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 8073fb4f617b..c683fb1077b3 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -327,6 +327,7 @@ class Context { } auto ints() -> ValueStore& { return sem_ir().ints(); } auto reals() -> ValueStore& { return sem_ir().reals(); } + auto floats() -> ValueStore& { return sem_ir().floats(); } auto string_literal_values() -> StringStoreWrapper& { return sem_ir().string_literal_values(); } diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index eb5e93a8f6b2..26e0d469eeb0 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -91,6 +91,14 @@ static auto MakeIntResult(Context& context, SemIR::TypeId type_id, Phase::Template); } +// Converts an APFloat value into a ConstantId. +static auto MakeFloatResult(Context& context, SemIR::TypeId type_id, + llvm::APFloat value) -> SemIR::ConstantId { + auto result = context.floats().Add(std::move(value)); + return MakeConstantResult(context, SemIR::FloatLiteral{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. @@ -366,6 +374,18 @@ static auto ValidateFloatBitWidth(Context& context, SemIRLoc loc, return false; } +// Enforces that a float type has a valid bit width. +auto ValidateFloatType(Context& context, SemIRLoc loc, SemIR::FloatType result) + -> bool { + auto bit_width = + context.insts().TryGetAs(result.bit_width_id); + if (!bit_width) { + // Symbolic bit width. + return true; + } + return ValidateFloatBitWidth(context, loc, result.bit_width_id); +} + // Issues a diagnostic for a compile-time division by zero. static auto DiagnoseDivisionByZero(Context& context, SemIRLoc loc) -> void { CARBON_DIAGNOSTIC(CompileTimeDivisionByZero, Error, "Division by zero."); @@ -578,6 +598,58 @@ static auto PerformBuiltinIntComparison(Context& context, return MakeBoolResult(context, bool_type_id, result); } +// Performs a builtin unary float -> float operation. +static auto PerformBuiltinUnaryFloatOp(Context& context, + SemIR::BuiltinFunctionKind builtin_kind, + SemIR::InstId arg_id) + -> SemIR::ConstantId { + auto op = context.insts().GetAs(arg_id); + auto op_val = context.floats().Get(op.float_id); + + switch (builtin_kind) { + case SemIR::BuiltinFunctionKind::FloatNegate: + op_val.changeSign(); + break; + default: + CARBON_FATAL() << "Unexpected builtin kind"; + } + + return MakeFloatResult(context, op.type_id, std::move(op_val)); +} + +// Performs a builtin binary float -> float operation. +static auto PerformBuiltinBinaryFloatOp(Context& context, + SemIR::BuiltinFunctionKind builtin_kind, + SemIR::InstId lhs_id, + SemIR::InstId rhs_id) + -> SemIR::ConstantId { + auto lhs = context.insts().GetAs(lhs_id); + auto rhs = context.insts().GetAs(rhs_id); + auto lhs_val = context.floats().Get(lhs.float_id); + auto rhs_val = context.floats().Get(rhs.float_id); + + llvm::APFloat result_val(lhs_val.getSemantics()); + + switch (builtin_kind) { + case SemIR::BuiltinFunctionKind::FloatAdd: + result_val = lhs_val + rhs_val; + break; + case SemIR::BuiltinFunctionKind::FloatSub: + result_val = lhs_val - rhs_val; + break; + case SemIR::BuiltinFunctionKind::FloatMul: + result_val = lhs_val * rhs_val; + break; + case SemIR::BuiltinFunctionKind::FloatDiv: + result_val = lhs_val / rhs_val; + break; + default: + CARBON_FATAL() << "Unexpected operation kind."; + } + + return MakeFloatResult(context, lhs.type_id, std::move(result_val)); +} + static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, SemIR::BuiltinFunctionKind builtin_kind, llvm::ArrayRef arg_ids, @@ -661,6 +733,27 @@ static auto PerformBuiltinCall(Context& context, SemIRLoc loc, SemIR::Call call, return PerformBuiltinIntComparison(context, builtin_kind, arg_ids[0], arg_ids[1], call.type_id); } + + // Unary float -> float operations. + case SemIR::BuiltinFunctionKind::FloatNegate: { + if (phase != Phase::Template) { + break; + } + + return PerformBuiltinUnaryFloatOp(context, builtin_kind, arg_ids[0]); + } + + // Binary float -> float operations. + case SemIR::BuiltinFunctionKind::FloatAdd: + case SemIR::BuiltinFunctionKind::FloatSub: + case SemIR::BuiltinFunctionKind::FloatMul: + case SemIR::BuiltinFunctionKind::FloatDiv: { + if (phase != Phase::Template) { + break; + } + return PerformBuiltinBinaryFloatOp(context, builtin_kind, arg_ids[0], + arg_ids[1]); + } } return SemIR::ConstantId::NotConstant; @@ -767,6 +860,14 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) case SemIR::PointerType::Kind: return RebuildIfFieldsAreConstant(context, inst, &SemIR::PointerType::pointee_id); + case CARBON_KIND(SemIR::FloatType float_type): { + return RebuildAndValidateIfFieldsAreConstant( + context, inst, + [&](SemIR::FloatType result) { + return ValidateFloatType(context, float_type.bit_width_id, result); + }, + &SemIR::FloatType::bit_width_id); + } case SemIR::StructType::Kind: return RebuildIfFieldsAreConstant(context, inst, &SemIR::StructType::fields_id); @@ -839,6 +940,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) return SemIR::ConstantId::ForTemplateConstant(inst_id); case SemIR::BoolLiteral::Kind: + case SemIR::FloatLiteral::Kind: case SemIR::IntLiteral::Kind: case SemIR::RealLiteral::Kind: case SemIR::StringLiteral::Kind: diff --git a/toolchain/check/handle_literal.cpp b/toolchain/check/handle_literal.cpp index 0461214c4ad8..c84f80d848f2 100644 --- a/toolchain/check/handle_literal.cpp +++ b/toolchain/check/handle_literal.cpp @@ -58,11 +58,46 @@ auto HandleIntLiteral(Context& context, Parse::IntLiteralId node_id) -> bool { } auto HandleRealLiteral(Context& context, Parse::RealLiteralId node_id) -> bool { + // Convert the real literal to an llvm::APFloat and add it to the floats + // ValueStore. In the future this would use an arbitrary precision Rational + // type. + // + // TODO: Implement Carbon's actual implicit conversion rules for + // floating-point constants, as per the design + // docs/design/expressions/implicit_conversions.md + auto real_id = + context.tokens().GetRealLiteral(context.parse_tree().node_token(node_id)); + auto real_value = context.sem_ir().reals().Get(real_id); + + if (real_value.mantissa.getActiveBits() > 64) { + CARBON_DIAGNOSTIC(RealMantissaTooLargeForI64, Error, + "Real mantissa with value {0} does not fit in i64.", + llvm::APSInt); + context.emitter().Emit(node_id, RealMantissaTooLargeForI64, + llvm::APSInt(real_value.mantissa, true)); + context.node_stack().Push(node_id, SemIR::InstId::BuiltinError); + return true; + } + + if (real_value.exponent.getSignificantBits() > 64) { + CARBON_DIAGNOSTIC(RealExponentTooLargeForI64, Error, + "Real exponent with value {0} does not fit in i64.", + llvm::APSInt); + context.emitter().Emit(node_id, RealExponentTooLargeForI64, + llvm::APSInt(real_value.exponent, false)); + context.node_stack().Push(node_id, SemIR::InstId::BuiltinError); + return true; + } + + double double_val = real_value.mantissa.getZExtValue() * + std::pow((real_value.is_decimal ? 10 : 2), + real_value.exponent.getSExtValue()); + + auto float_id = context.sem_ir().floats().Add(llvm::APFloat(double_val)); context.AddInstAndPush( {node_id, - SemIR::RealLiteral{context.GetBuiltinType(SemIR::BuiltinKind::FloatType), - context.tokens().GetRealLiteral( - context.parse_tree().node_token(node_id))}}); + SemIR::FloatLiteral{ + context.GetBuiltinType(SemIR::BuiltinKind::FloatType), float_id}}); return true; } diff --git a/toolchain/check/testdata/array/base.carbon b/toolchain/check/testdata/array/base.carbon index 18e61d3c2d6e..d50119636257 100644 --- a/toolchain/check/testdata/array/base.carbon +++ b/toolchain/check/testdata/array/base.carbon @@ -20,8 +20,8 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.7: i32 = int_literal 2 [template] // CHECK:STDOUT: %.8: type = array_type %.7, f64 [template] // CHECK:STDOUT: %.9: type = ptr_type [f64; 2] [template] -// CHECK:STDOUT: %.10: f64 = real_literal 111e-1 [template] -// CHECK:STDOUT: %.11: f64 = real_literal 22e-1 [template] +// CHECK:STDOUT: %.10: f64 = float_literal 11.100000000000001 [template] +// CHECK:STDOUT: %.11: f64 = float_literal 2.2000000000000002 [template] // CHECK:STDOUT: %.12: type = tuple_type (f64, f64) [template] // CHECK:STDOUT: %.13: [f64; 2] = tuple_value (%.10, %.11) [template] // CHECK:STDOUT: %.14: type = tuple_type () [template] @@ -69,8 +69,8 @@ var c: [(); 5] = ((), (), (), (), (),); // CHECK:STDOUT: %.loc7_22.5: init [i32; 1] = array_init (%.loc7_22.4) to file.%a.var [template = constants.%.6] // CHECK:STDOUT: %.loc7_23: init [i32; 1] = converted %.loc7_22.1, %.loc7_22.5 [template = constants.%.6] // CHECK:STDOUT: assign file.%a.var, %.loc7_23 -// CHECK:STDOUT: %.loc8_20: f64 = real_literal 111e-1 [template = constants.%.10] -// CHECK:STDOUT: %.loc8_26: f64 = real_literal 22e-1 [template = constants.%.11] +// CHECK:STDOUT: %.loc8_20: f64 = float_literal 11.100000000000001 [template = constants.%.10] +// CHECK:STDOUT: %.loc8_26: f64 = float_literal 2.2000000000000002 [template = constants.%.11] // CHECK:STDOUT: %.loc8_30.1: (f64, f64) = tuple_literal (%.loc8_20, %.loc8_26) // CHECK:STDOUT: %.loc8_30.2: i32 = int_literal 0 [template = constants.%.5] // CHECK:STDOUT: %.loc8_30.3: ref f64 = array_index file.%b.var, %.loc8_30.2 diff --git a/toolchain/check/testdata/basics/builtin_types.carbon b/toolchain/check/testdata/basics/builtin_types.carbon index 6a593472d882..e492f7117418 100644 --- a/toolchain/check/testdata/basics/builtin_types.carbon +++ b/toolchain/check/testdata/basics/builtin_types.carbon @@ -13,7 +13,7 @@ var test_type: type = i32; // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: i32 = int_literal 0 [template] -// CHECK:STDOUT: %.2: f64 = real_literal 1e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 0.10000000000000001 [template] // CHECK:STDOUT: %.3: type = ptr_type String [template] // CHECK:STDOUT: %.4: String = string_literal "Test" [template] // CHECK:STDOUT: } @@ -40,7 +40,7 @@ var test_type: type = i32; // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc7: i32 = int_literal 0 [template = constants.%.1] // CHECK:STDOUT: assign file.%test_i32.var, %.loc7 -// CHECK:STDOUT: %.loc8: f64 = real_literal 1e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc8: f64 = float_literal 0.10000000000000001 [template = constants.%.2] // CHECK:STDOUT: assign file.%test_f64.var, %.loc8 // CHECK:STDOUT: assign file.%test_type.var, i32 // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/basics/fail_numeric_literal_overflow.carbon b/toolchain/check/testdata/basics/fail_numeric_literal_overflow.carbon index cf9735d1ef4c..09606a96a14c 100644 --- a/toolchain/check/testdata/basics/fail_numeric_literal_overflow.carbon +++ b/toolchain/check/testdata/basics/fail_numeric_literal_overflow.carbon @@ -16,11 +16,23 @@ let a: i32 = 39999999999999999993; // CHECK:STDERR: let b: i32 = 2_147_483_648; -// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+3]]:14: ERROR: Integer literal with value 2147483648 does not fit in i32. +// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+4]]:14: ERROR: Integer literal with value 2147483648 does not fit in i32. // CHECK:STDERR: let c: i32 = 0x8000_0000; // CHECK:STDERR: ^~~~~~~~~~~ +// CHECK:STDERR: let c: i32 = 0x8000_0000; +// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+4]]:14: ERROR: Real mantissa with value 399999999999999999930 does not fit in i64. +// CHECK:STDERR: let d: f64 = 39999999999999999993.0e3; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +let d: f64 = 39999999999999999993.0e3; + +// CHECK:STDERR: fail_numeric_literal_overflow.carbon:[[@LINE+3]]:14: ERROR: Real exponent with value 39999999999999999992 does not fit in i64. +// CHECK:STDERR: let e: f64 = 5.0e39999999999999999993; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ +let e: f64 = 5.0e39999999999999999993; + // CHECK:STDOUT: --- fail_numeric_literal_overflow.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -31,5 +43,7 @@ let c: i32 = 0x8000_0000; // CHECK:STDOUT: %a: i32 = bind_name a, // CHECK:STDOUT: %b: i32 = bind_name b, // CHECK:STDOUT: %c: i32 = bind_name c, +// CHECK:STDOUT: %d: f64 = bind_name d, +// CHECK:STDOUT: %e: f64 = bind_name e, // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/basics/numeric_literals.carbon b/toolchain/check/testdata/basics/numeric_literals.carbon index a42da1f54f57..109a45652e0b 100644 --- a/toolchain/check/testdata/basics/numeric_literals.carbon +++ b/toolchain/check/testdata/basics/numeric_literals.carbon @@ -15,14 +15,13 @@ fn F() { 2147483647, 0x7FFFFFFF, ); - var floats: [f64; 7] = ( + var floats: [f64; 6] = ( 0.9, 8.0, 80.0, 1.0e7, 1.0e8, - 1.0e-8, - 39999999999999999993.0e39999999999999999993, + 1.0e-8 ); } @@ -43,18 +42,16 @@ fn F() { // CHECK:STDOUT: %.12: i32 = int_literal 4 [template] // CHECK:STDOUT: %.13: i32 = int_literal 5 [template] // CHECK:STDOUT: %.14: [i32; 6] = tuple_value (%.4, %.5, %.4, %.4, %.6, %.6) [template] -// CHECK:STDOUT: %.15: i32 = int_literal 7 [template] -// CHECK:STDOUT: %.16: type = array_type %.15, f64 [template] -// CHECK:STDOUT: %.17: type = ptr_type [f64; 7] [template] -// CHECK:STDOUT: %.18: f64 = real_literal 9e-1 [template] -// CHECK:STDOUT: %.19: f64 = real_literal 80e-1 [template] -// CHECK:STDOUT: %.20: f64 = real_literal 800e-1 [template] -// CHECK:STDOUT: %.21: f64 = real_literal 10e6 [template] -// CHECK:STDOUT: %.22: f64 = real_literal 10e7 [template] -// CHECK:STDOUT: %.23: f64 = real_literal 10e-9 [template] -// CHECK:STDOUT: %.24: f64 = real_literal 399999999999999999930e39999999999999999992 [template] -// CHECK:STDOUT: %.25: type = tuple_type (f64, f64, f64, f64, f64, f64, f64) [template] -// CHECK:STDOUT: %.26: [f64; 7] = tuple_value (%.18, %.19, %.20, %.21, %.22, %.23, %.24) [template] +// CHECK:STDOUT: %.15: type = array_type %.1, f64 [template] +// CHECK:STDOUT: %.16: type = ptr_type [f64; 6] [template] +// CHECK:STDOUT: %.17: f64 = float_literal 0.90000000000000002 [template] +// CHECK:STDOUT: %.18: f64 = float_literal 8 [template] +// CHECK:STDOUT: %.19: f64 = float_literal 80 [template] +// CHECK:STDOUT: %.20: f64 = float_literal 1.0E+7 [template] +// CHECK:STDOUT: %.21: f64 = float_literal 1.0E+8 [template] +// CHECK:STDOUT: %.22: f64 = float_literal 1.0E-8 [template] +// CHECK:STDOUT: %.23: type = tuple_type (f64, f64, f64, f64, f64, f64) [template] +// CHECK:STDOUT: %.24: [f64; 6] = tuple_value (%.17, %.18, %.19, %.20, %.21, %.22) [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -100,42 +97,38 @@ fn F() { // CHECK:STDOUT: %.loc17_3.20: init [i32; 6] = array_init (%.loc17_3.4, %.loc17_3.7, %.loc17_3.10, %.loc17_3.13, %.loc17_3.16, %.loc17_3.19) to %ints.var [template = constants.%.14] // CHECK:STDOUT: %.loc17_4: init [i32; 6] = converted %.loc17_3.1, %.loc17_3.20 [template = constants.%.14] // CHECK:STDOUT: assign %ints.var, %.loc17_4 -// CHECK:STDOUT: %.loc18_21: i32 = int_literal 7 [template = constants.%.15] -// CHECK:STDOUT: %.loc18_22: type = array_type %.loc18_21, f64 [template = constants.%.16] -// CHECK:STDOUT: %floats.var: ref [f64; 7] = var floats -// CHECK:STDOUT: %floats: ref [f64; 7] = bind_name floats, %floats.var -// CHECK:STDOUT: %.loc19: f64 = real_literal 9e-1 [template = constants.%.18] -// CHECK:STDOUT: %.loc20: f64 = real_literal 80e-1 [template = constants.%.19] -// CHECK:STDOUT: %.loc21: f64 = real_literal 800e-1 [template = constants.%.20] -// CHECK:STDOUT: %.loc22: f64 = real_literal 10e6 [template = constants.%.21] -// CHECK:STDOUT: %.loc23: f64 = real_literal 10e7 [template = constants.%.22] -// CHECK:STDOUT: %.loc24: f64 = real_literal 10e-9 [template = constants.%.23] -// CHECK:STDOUT: %.loc25: f64 = real_literal 399999999999999999930e39999999999999999992 [template = constants.%.24] -// CHECK:STDOUT: %.loc26_3.1: (f64, f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24, %.loc25) -// CHECK:STDOUT: %.loc26_3.2: i32 = int_literal 0 [template = constants.%.8] -// CHECK:STDOUT: %.loc26_3.3: ref f64 = array_index %floats.var, %.loc26_3.2 -// CHECK:STDOUT: %.loc26_3.4: init f64 = initialize_from %.loc19 to %.loc26_3.3 [template = constants.%.18] -// CHECK:STDOUT: %.loc26_3.5: i32 = int_literal 1 [template = constants.%.9] -// CHECK:STDOUT: %.loc26_3.6: ref f64 = array_index %floats.var, %.loc26_3.5 -// CHECK:STDOUT: %.loc26_3.7: init f64 = initialize_from %.loc20 to %.loc26_3.6 [template = constants.%.19] -// CHECK:STDOUT: %.loc26_3.8: i32 = int_literal 2 [template = constants.%.10] -// CHECK:STDOUT: %.loc26_3.9: ref f64 = array_index %floats.var, %.loc26_3.8 -// CHECK:STDOUT: %.loc26_3.10: init f64 = initialize_from %.loc21 to %.loc26_3.9 [template = constants.%.20] -// CHECK:STDOUT: %.loc26_3.11: i32 = int_literal 3 [template = constants.%.11] -// CHECK:STDOUT: %.loc26_3.12: ref f64 = array_index %floats.var, %.loc26_3.11 -// CHECK:STDOUT: %.loc26_3.13: init f64 = initialize_from %.loc22 to %.loc26_3.12 [template = constants.%.21] -// CHECK:STDOUT: %.loc26_3.14: i32 = int_literal 4 [template = constants.%.12] -// CHECK:STDOUT: %.loc26_3.15: ref f64 = array_index %floats.var, %.loc26_3.14 -// CHECK:STDOUT: %.loc26_3.16: init f64 = initialize_from %.loc23 to %.loc26_3.15 [template = constants.%.22] -// CHECK:STDOUT: %.loc26_3.17: i32 = int_literal 5 [template = constants.%.13] -// CHECK:STDOUT: %.loc26_3.18: ref f64 = array_index %floats.var, %.loc26_3.17 -// CHECK:STDOUT: %.loc26_3.19: init f64 = initialize_from %.loc24 to %.loc26_3.18 [template = constants.%.23] -// CHECK:STDOUT: %.loc26_3.20: i32 = int_literal 6 [template = constants.%.1] -// CHECK:STDOUT: %.loc26_3.21: ref f64 = array_index %floats.var, %.loc26_3.20 -// CHECK:STDOUT: %.loc26_3.22: init f64 = initialize_from %.loc25 to %.loc26_3.21 [template = constants.%.24] -// CHECK:STDOUT: %.loc26_3.23: init [f64; 7] = array_init (%.loc26_3.4, %.loc26_3.7, %.loc26_3.10, %.loc26_3.13, %.loc26_3.16, %.loc26_3.19, %.loc26_3.22) to %floats.var [template = constants.%.26] -// CHECK:STDOUT: %.loc26_4: init [f64; 7] = converted %.loc26_3.1, %.loc26_3.23 [template = constants.%.26] -// CHECK:STDOUT: assign %floats.var, %.loc26_4 +// CHECK:STDOUT: %.loc18_21: i32 = int_literal 6 [template = constants.%.1] +// CHECK:STDOUT: %.loc18_22: type = array_type %.loc18_21, f64 [template = constants.%.15] +// CHECK:STDOUT: %floats.var: ref [f64; 6] = var floats +// CHECK:STDOUT: %floats: ref [f64; 6] = bind_name floats, %floats.var +// CHECK:STDOUT: %.loc19: f64 = float_literal 0.90000000000000002 [template = constants.%.17] +// CHECK:STDOUT: %.loc20: f64 = float_literal 8 [template = constants.%.18] +// CHECK:STDOUT: %.loc21: f64 = float_literal 80 [template = constants.%.19] +// CHECK:STDOUT: %.loc22: f64 = float_literal 1.0E+7 [template = constants.%.20] +// CHECK:STDOUT: %.loc23: f64 = float_literal 1.0E+8 [template = constants.%.21] +// CHECK:STDOUT: %.loc24: f64 = float_literal 1.0E-8 [template = constants.%.22] +// CHECK:STDOUT: %.loc25_3.1: (f64, f64, f64, f64, f64, f64) = tuple_literal (%.loc19, %.loc20, %.loc21, %.loc22, %.loc23, %.loc24) +// CHECK:STDOUT: %.loc25_3.2: i32 = int_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %.loc25_3.3: ref f64 = array_index %floats.var, %.loc25_3.2 +// CHECK:STDOUT: %.loc25_3.4: init f64 = initialize_from %.loc19 to %.loc25_3.3 [template = constants.%.17] +// CHECK:STDOUT: %.loc25_3.5: i32 = int_literal 1 [template = constants.%.9] +// CHECK:STDOUT: %.loc25_3.6: ref f64 = array_index %floats.var, %.loc25_3.5 +// CHECK:STDOUT: %.loc25_3.7: init f64 = initialize_from %.loc20 to %.loc25_3.6 [template = constants.%.18] +// CHECK:STDOUT: %.loc25_3.8: i32 = int_literal 2 [template = constants.%.10] +// CHECK:STDOUT: %.loc25_3.9: ref f64 = array_index %floats.var, %.loc25_3.8 +// CHECK:STDOUT: %.loc25_3.10: init f64 = initialize_from %.loc21 to %.loc25_3.9 [template = constants.%.19] +// CHECK:STDOUT: %.loc25_3.11: i32 = int_literal 3 [template = constants.%.11] +// CHECK:STDOUT: %.loc25_3.12: ref f64 = array_index %floats.var, %.loc25_3.11 +// CHECK:STDOUT: %.loc25_3.13: init f64 = initialize_from %.loc22 to %.loc25_3.12 [template = constants.%.20] +// CHECK:STDOUT: %.loc25_3.14: i32 = int_literal 4 [template = constants.%.12] +// CHECK:STDOUT: %.loc25_3.15: ref f64 = array_index %floats.var, %.loc25_3.14 +// CHECK:STDOUT: %.loc25_3.16: init f64 = initialize_from %.loc23 to %.loc25_3.15 [template = constants.%.21] +// CHECK:STDOUT: %.loc25_3.17: i32 = int_literal 5 [template = constants.%.13] +// CHECK:STDOUT: %.loc25_3.18: ref f64 = array_index %floats.var, %.loc25_3.17 +// CHECK:STDOUT: %.loc25_3.19: init f64 = initialize_from %.loc24 to %.loc25_3.18 [template = constants.%.22] +// CHECK:STDOUT: %.loc25_3.20: init [f64; 6] = array_init (%.loc25_3.4, %.loc25_3.7, %.loc25_3.10, %.loc25_3.13, %.loc25_3.16, %.loc25_3.19) to %floats.var [template = constants.%.24] +// CHECK:STDOUT: %.loc25_4: init [f64; 6] = converted %.loc25_3.1, %.loc25_3.20 [template = constants.%.24] +// CHECK:STDOUT: assign %floats.var, %.loc25_4 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/float/add.carbon b/toolchain/check/testdata/builtins/float/add.carbon new file mode 100644 index 000000000000..774fe16c7517 --- /dev/null +++ b/toolchain/check/testdata/builtins/float/add.carbon @@ -0,0 +1,211 @@ +// 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 + +// --- float_add.carbon + +fn Add(a: f64, b: f64) -> f64 = "float.add"; + +fn RuntimeCall(a: f64, b: f64) -> f64 { + return Add(a, b); +} + +var x: f64 = Add(2.2, 2.3); + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.add". +// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.add"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew(a: f64) -> f64 = "float.add"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.add". +// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.add"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.add"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.add". +// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.add"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +fn BadReturnType(a: f64, b: f64) -> bool = "float.add"; +fn JustRight(a: f64, b: f64) -> f64 = "float.add"; + +fn RuntimeCallTooFew(a: f64) -> f64 { + return TooFew(a); +} + +fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { + return BadReturnType(a, b); +} + +// CHECK:STDOUT: --- float_add.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: f64 = float_literal 2.2000000000000002 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 2.3000000000000003 [template] +// CHECK:STDOUT: %.3: f64 = float_literal 4.5 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Add = %Add +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: .x = %x +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Add: = fn_decl @Add [template] { +// CHECK:STDOUT: %a.loc2_8.1: f64 = param a +// CHECK:STDOUT: @Add.%a: f64 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: f64 = param b +// CHECK:STDOUT: @Add.%b: f64 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Add.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc4_16.1: f64 = param a +// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1 +// CHECK:STDOUT: %b.loc4_24.1: f64 = param b +// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref f64 = var x +// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Add(%a: f64, %b: f64) -> f64 = "float.add"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Add.ref: = name_ref Add, file.%Add [template = file.%Add] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %float.add: init f64 = call %Add.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.add +// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.add, %.loc5_19.1 +// CHECK:STDOUT: return %.loc5_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Add.ref: = name_ref Add, file.%Add [template = file.%Add] +// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2.2000000000000002 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_23: f64 = float_literal 2.3000000000000003 [template = constants.%.2] +// CHECK:STDOUT: %float.add: init f64 = call %Add.ref(%.loc8_18, %.loc8_23) [template = constants.%.3] +// CHECK:STDOUT: assign file.%x.var, %float.add +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: %a.loc8_11.1: f64 = param a +// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1 +// CHECK:STDOUT: @TooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: f64 = param a +// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: f64 = param b +// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %c.loc13_28.1: f64 = param c +// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1 +// CHECK:STDOUT: @TooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc17_18.1: f64 = param a +// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1 +// CHECK:STDOUT: %b.loc17_26.1: f64 = param b +// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc18_14.1: f64 = param a +// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1 +// CHECK:STDOUT: %b.loc18_22.1: f64 = param b +// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1 +// CHECK:STDOUT: @JustRight.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc20_22.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc24_23.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1 +// CHECK:STDOUT: %b.loc24_31.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1 +// CHECK:STDOUT: %c.loc24_39.1: f64 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc28_29.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1 +// CHECK:STDOUT: %b.loc28_37.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.add"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref) +// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call +// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1 +// CHECK:STDOUT: return %.loc21_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c +// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref) +// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call +// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1 +// CHECK:STDOUT: return %.loc25_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call +// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1 +// CHECK:STDOUT: return %.loc29_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/float/div.carbon b/toolchain/check/testdata/builtins/float/div.carbon new file mode 100644 index 000000000000..8baed86973ab --- /dev/null +++ b/toolchain/check/testdata/builtins/float/div.carbon @@ -0,0 +1,233 @@ +// 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 + +// --- float_div.carbon + +fn Div(a: f64, b: f64) -> f64 = "float.div"; + +fn RuntimeCall(a: f64, b: f64) -> f64 { + return Div(a, b); +} + +var a: f64 = Div(10.0, 2.5); +let b: f64 = Div(1.0, 0.0); +let c: f64 = Div(0.0, 0.0); + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.div". +// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.div"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew(a: f64) -> f64 = "float.div"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.div". +// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.div"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.div"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.div". +// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.div"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +fn BadReturnType(a: f64, b: f64) -> bool = "float.div"; +fn JustRight(a: f64, b: f64) -> f64 = "float.div"; + +fn RuntimeCallTooFew(a: f64) -> f64 { + return TooFew(a); +} + +fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { + return BadReturnType(a, b); +} + +// CHECK:STDOUT: --- float_div.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: f64 = float_literal 10 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 2.5 [template] +// CHECK:STDOUT: %.3: f64 = float_literal 4 [template] +// CHECK:STDOUT: %.4: f64 = float_literal 1 [template] +// CHECK:STDOUT: %.5: f64 = float_literal 0 [template] +// CHECK:STDOUT: %.6: f64 = float_literal +Inf [template] +// CHECK:STDOUT: %.7: f64 = float_literal 0 [template] +// CHECK:STDOUT: %.8: f64 = float_literal 0 [template] +// CHECK:STDOUT: %.9: f64 = float_literal NaN [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Div = %Div +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: .a = %a.loc8 +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Div: = fn_decl @Div [template] { +// CHECK:STDOUT: %a.loc2_8.1: f64 = param a +// CHECK:STDOUT: @Div.%a: f64 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: f64 = param b +// CHECK:STDOUT: @Div.%b: f64 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Div.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc4_16.1: f64 = param a +// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1 +// CHECK:STDOUT: %b.loc4_24.1: f64 = param b +// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %a.var: ref f64 = var a +// CHECK:STDOUT: %a.loc8: ref f64 = bind_name a, %a.var +// CHECK:STDOUT: %Div.ref.loc9: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %.loc9_18: f64 = float_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc9_23: f64 = float_literal 0 [template = constants.%.5] +// CHECK:STDOUT: %float.div.loc9: init f64 = call %Div.ref.loc9(%.loc9_18, %.loc9_23) [template = constants.%.6] +// CHECK:STDOUT: %.loc9_27.1: f64 = value_of_initializer %float.div.loc9 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_27.2: f64 = converted %float.div.loc9, %.loc9_27.1 [template = constants.%.6] +// CHECK:STDOUT: %b.loc9: f64 = bind_name b, %.loc9_27.2 +// CHECK:STDOUT: %Div.ref.loc10: = name_ref Div, %Div [template = %Div] +// CHECK:STDOUT: %.loc10_18: f64 = float_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc10_23: f64 = float_literal 0 [template = constants.%.8] +// CHECK:STDOUT: %float.div.loc10: init f64 = call %Div.ref.loc10(%.loc10_18, %.loc10_23) [template = constants.%.9] +// CHECK:STDOUT: %.loc10_27.1: f64 = value_of_initializer %float.div.loc10 [template = constants.%.9] +// CHECK:STDOUT: %.loc10_27.2: f64 = converted %float.div.loc10, %.loc10_27.1 [template = constants.%.9] +// CHECK:STDOUT: %c: f64 = bind_name c, %.loc10_27.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Div(%a: f64, %b: f64) -> f64 = "float.div"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Div.ref: = name_ref Div, file.%Div [template = file.%Div] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %float.div: init f64 = call %Div.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.div +// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.div, %.loc5_19.1 +// CHECK:STDOUT: return %.loc5_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Div.ref: = name_ref Div, file.%Div [template = file.%Div] +// CHECK:STDOUT: %.loc8_18: f64 = float_literal 10 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_24: f64 = float_literal 2.5 [template = constants.%.2] +// CHECK:STDOUT: %float.div: init f64 = call %Div.ref(%.loc8_18, %.loc8_24) [template = constants.%.3] +// CHECK:STDOUT: assign file.%a.var, %float.div +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: %a.loc8_11.1: f64 = param a +// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1 +// CHECK:STDOUT: @TooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: f64 = param a +// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: f64 = param b +// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %c.loc13_28.1: f64 = param c +// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1 +// CHECK:STDOUT: @TooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc17_18.1: f64 = param a +// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1 +// CHECK:STDOUT: %b.loc17_26.1: f64 = param b +// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc18_14.1: f64 = param a +// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1 +// CHECK:STDOUT: %b.loc18_22.1: f64 = param b +// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1 +// CHECK:STDOUT: @JustRight.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc20_22.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc24_23.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1 +// CHECK:STDOUT: %b.loc24_31.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1 +// CHECK:STDOUT: %c.loc24_39.1: f64 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc28_29.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1 +// CHECK:STDOUT: %b.loc28_37.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.div"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref) +// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call +// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1 +// CHECK:STDOUT: return %.loc21_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c +// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref) +// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call +// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1 +// CHECK:STDOUT: return %.loc25_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call +// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1 +// CHECK:STDOUT: return %.loc29_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/float/make_type.carbon b/toolchain/check/testdata/builtins/float/make_type.carbon index 8d6dc18e1b63..b4eefc534625 100644 --- a/toolchain/check/testdata/builtins/float/make_type.carbon +++ b/toolchain/check/testdata/builtins/float/make_type.carbon @@ -61,7 +61,7 @@ var dyn: Float(dyn_size); // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: i32 = int_literal 64 [template] -// CHECK:STDOUT: %.2: f64 = real_literal 0e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 0 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -101,7 +101,7 @@ var dyn: Float(dyn_size); // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc6: f64 = real_literal 0e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc6: f64 = float_literal 0 [template = constants.%.2] // CHECK:STDOUT: assign file.%f.var, %.loc6 // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/builtins/float/mul.carbon b/toolchain/check/testdata/builtins/float/mul.carbon new file mode 100644 index 000000000000..49c70db0b39c --- /dev/null +++ b/toolchain/check/testdata/builtins/float/mul.carbon @@ -0,0 +1,211 @@ +// 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 + +// --- mul_sub.carbon + +fn Mul(a: f64, b: f64) -> f64 = "float.mul"; + +fn RuntimeCall(a: f64, b: f64) -> f64 { + return Mul(a, b); +} + +var x: f64 = Mul(2.0, 0.5); + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.mul". +// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.mul"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew(a: f64) -> f64 = "float.mul"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.mul". +// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.mul"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.mul"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.mul". +// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.mul"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +fn BadReturnType(a: f64, b: f64) -> bool = "float.mul"; +fn JustRight(a: f64, b: f64) -> f64 = "float.mul"; + +fn RuntimeCallTooFew(a: f64) -> f64 { + return TooFew(a); +} + +fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { + return BadReturnType(a, b); +} + +// CHECK:STDOUT: --- mul_sub.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: f64 = float_literal 2 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 0.5 [template] +// CHECK:STDOUT: %.3: f64 = float_literal 1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Mul = %Mul +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: .x = %x +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Mul: = fn_decl @Mul [template] { +// CHECK:STDOUT: %a.loc2_8.1: f64 = param a +// CHECK:STDOUT: @Mul.%a: f64 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: f64 = param b +// CHECK:STDOUT: @Mul.%b: f64 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Mul.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc4_16.1: f64 = param a +// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1 +// CHECK:STDOUT: %b.loc4_24.1: f64 = param b +// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref f64 = var x +// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Mul(%a: f64, %b: f64) -> f64 = "float.mul"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Mul.ref: = name_ref Mul, file.%Mul [template = file.%Mul] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %float.mul: init f64 = call %Mul.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.mul +// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.mul, %.loc5_19.1 +// CHECK:STDOUT: return %.loc5_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Mul.ref: = name_ref Mul, file.%Mul [template = file.%Mul] +// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_23: f64 = float_literal 0.5 [template = constants.%.2] +// CHECK:STDOUT: %float.mul: init f64 = call %Mul.ref(%.loc8_18, %.loc8_23) [template = constants.%.3] +// CHECK:STDOUT: assign file.%x.var, %float.mul +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: %a.loc8_11.1: f64 = param a +// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1 +// CHECK:STDOUT: @TooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: f64 = param a +// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: f64 = param b +// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %c.loc13_28.1: f64 = param c +// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1 +// CHECK:STDOUT: @TooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc17_18.1: f64 = param a +// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1 +// CHECK:STDOUT: %b.loc17_26.1: f64 = param b +// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc18_14.1: f64 = param a +// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1 +// CHECK:STDOUT: %b.loc18_22.1: f64 = param b +// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1 +// CHECK:STDOUT: @JustRight.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc20_22.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc24_23.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1 +// CHECK:STDOUT: %b.loc24_31.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1 +// CHECK:STDOUT: %c.loc24_39.1: f64 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc28_29.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1 +// CHECK:STDOUT: %b.loc28_37.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.mul"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref) +// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call +// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1 +// CHECK:STDOUT: return %.loc21_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c +// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref) +// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call +// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1 +// CHECK:STDOUT: return %.loc25_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call +// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1 +// CHECK:STDOUT: return %.loc29_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/float/negate.carbon b/toolchain/check/testdata/builtins/float/negate.carbon new file mode 100644 index 000000000000..fffc2d29a083 --- /dev/null +++ b/toolchain/check/testdata/builtins/float/negate.carbon @@ -0,0 +1,213 @@ +// 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 + +// --- float_negate.carbon + +fn Negate(a: f64) -> f64 = "float.negate"; + +fn RuntimeCall(a: f64, b: f64) -> f64 { + return Negate(a); +} + +let a: f64 = Negate(1.5); + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate". +// CHECK:STDERR: fn TooFew() -> f64 = "float.negate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew() -> f64 = "float.negate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate". +// CHECK:STDERR: fn TooMany(a: f64, b: f64) -> f64 = "float.negate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: f64, b: f64) -> f64 = "float.negate"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.negate". +// CHECK:STDERR: fn BadReturnType(a: f64) -> bool = "float.negate"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn BadReturnType(a: f64) -> bool = "float.negate"; +fn JustRight(a: f64) -> f64 = "float.negate"; + +fn RuntimeCallTooFew(a: f64) -> f64 { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 1 argument(s) passed to function expecting 0 argument(s). + // CHECK:STDERR: return TooFew(a); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-17]]:1: Calling function declared here. + // CHECK:STDERR: fn TooFew() -> f64 = "float.negate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + return TooFew(a); +} + +fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+7]]:10: ERROR: 3 argument(s) passed to function expecting 2 argument(s). + // CHECK:STDERR: return TooMany(a, b, c); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-23]]:1: Calling function declared here. + // CHECK:STDERR: fn TooMany(a: f64, b: f64) -> f64 = "float.negate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+6]]:10: ERROR: 2 argument(s) passed to function expecting 1 argument(s). + // CHECK:STDERR: return BadReturnType(a, b); + // CHECK:STDERR: ^~~~~~~~~~~~~~ + // CHECK:STDERR: fail_bad_decl.carbon:[[@LINE-29]]:1: Calling function declared here. + // CHECK:STDERR: fn BadReturnType(a: f64) -> bool = "float.negate"; + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + return BadReturnType(a, b); +} + +// CHECK:STDOUT: --- float_negate.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: f64 = float_literal 1.5 [template] +// CHECK:STDOUT: %.2: f64 = float_literal -1.5 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Negate = %Negate +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Negate: = fn_decl @Negate [template] { +// CHECK:STDOUT: %a.loc2_11.1: f64 = param a +// CHECK:STDOUT: @Negate.%a: f64 = bind_name a, %a.loc2_11.1 +// CHECK:STDOUT: @Negate.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc4_16.1: f64 = param a +// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1 +// CHECK:STDOUT: %b.loc4_24.1: f64 = param b +// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %Negate.ref: = name_ref Negate, %Negate [template = %Negate] +// CHECK:STDOUT: %.loc8_21: f64 = float_literal 1.5 [template = constants.%.1] +// CHECK:STDOUT: %float.negate: init f64 = call %Negate.ref(%.loc8_21) [template = constants.%.2] +// CHECK:STDOUT: %.loc8_25.1: f64 = value_of_initializer %float.negate [template = constants.%.2] +// CHECK:STDOUT: %.loc8_25.2: f64 = converted %float.negate, %.loc8_25.1 [template = constants.%.2] +// CHECK:STDOUT: %a.loc8: f64 = bind_name a, %.loc8_25.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Negate(%a: f64) -> f64 = "float.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Negate.ref: = name_ref Negate, file.%Negate [template = file.%Negate] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %float.negate: init f64 = call %Negate.ref(%a.ref) +// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.negate +// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.negate, %.loc5_19.1 +// CHECK:STDOUT: return %.loc5_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: @TooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: f64 = param a +// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: f64 = param b +// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: @TooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc18_18.1: f64 = param a +// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc18_18.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc19_14.1: f64 = param a +// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc19_14.1 +// CHECK:STDOUT: @JustRight.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc21_22.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc21_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc32_23.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc32_23.1 +// CHECK:STDOUT: %b.loc32_31.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc32_31.1 +// CHECK:STDOUT: %c.loc32_39.1: f64 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc32_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc43_29.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc43_29.1 +// CHECK:STDOUT: %b.loc43_37.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc43_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew() -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: f64) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: f64) -> f64 = "float.negate"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref() [template = ] +// CHECK:STDOUT: %.loc29_19.1: f64 = value_of_initializer %TooFew.call [template = ] +// CHECK:STDOUT: %.loc29_19.2: f64 = converted %TooFew.call, %.loc29_19.1 [template = ] +// CHECK:STDOUT: return %.loc29_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c +// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref() [template = ] +// CHECK:STDOUT: %.loc40_26.1: f64 = value_of_initializer %TooMany.call [template = ] +// CHECK:STDOUT: %.loc40_26.2: f64 = converted %TooMany.call, %.loc40_26.1 [template = ] +// CHECK:STDOUT: return %.loc40_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref() [template = ] +// CHECK:STDOUT: %.loc50_29.1: bool = value_of_initializer %BadReturnType.call [template = ] +// CHECK:STDOUT: %.loc50_29.2: bool = converted %BadReturnType.call, %.loc50_29.1 [template = ] +// CHECK:STDOUT: return %.loc50_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/float/sub.carbon b/toolchain/check/testdata/builtins/float/sub.carbon new file mode 100644 index 000000000000..d10dd94947d1 --- /dev/null +++ b/toolchain/check/testdata/builtins/float/sub.carbon @@ -0,0 +1,211 @@ +// 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 + +// --- float_sub.carbon + +fn Sub(a: f64, b: f64) -> f64 = "float.sub"; + +fn RuntimeCall(a: f64, b: f64) -> f64 { + return Sub(a, b); +} + +var x: f64 = Sub(2.0, 0.5); + +// --- fail_bad_decl.carbon + +package FailBadDecl api; + +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.sub". +// CHECK:STDERR: fn TooFew(a: f64) -> f64 = "float.sub"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooFew(a: f64) -> f64 = "float.sub"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+4]]:1: ERROR: Invalid signature for builtin function "float.sub". +// CHECK:STDERR: fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.sub"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn TooMany(a: f64, b: f64, c: f64) -> f64 = "float.sub"; +// CHECK:STDERR: fail_bad_decl.carbon:[[@LINE+3]]:1: ERROR: Invalid signature for builtin function "float.sub". +// CHECK:STDERR: fn BadReturnType(a: f64, b: f64) -> bool = "float.sub"; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +fn BadReturnType(a: f64, b: f64) -> bool = "float.sub"; +fn JustRight(a: f64, b: f64) -> f64 = "float.sub"; + +fn RuntimeCallTooFew(a: f64) -> f64 { + return TooFew(a); +} + +fn RuntimeCallTooMany(a: f64, b: f64, c: f64) -> f64 { + return TooMany(a, b, c); +} + +fn RuntimeCallBadReturnType(a: f64, b: f64) -> bool { + return BadReturnType(a, b); +} + +// CHECK:STDOUT: --- float_sub.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: f64 = float_literal 2 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 0.5 [template] +// CHECK:STDOUT: %.3: f64 = float_literal 1.5 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Sub = %Sub +// CHECK:STDOUT: .RuntimeCall = %RuntimeCall +// CHECK:STDOUT: .x = %x +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Sub: = fn_decl @Sub [template] { +// CHECK:STDOUT: %a.loc2_8.1: f64 = param a +// CHECK:STDOUT: @Sub.%a: f64 = bind_name a, %a.loc2_8.1 +// CHECK:STDOUT: %b.loc2_16.1: f64 = param b +// CHECK:STDOUT: @Sub.%b: f64 = bind_name b, %b.loc2_16.1 +// CHECK:STDOUT: @Sub.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCall: = fn_decl @RuntimeCall [template] { +// CHECK:STDOUT: %a.loc4_16.1: f64 = param a +// CHECK:STDOUT: @RuntimeCall.%a: f64 = bind_name a, %a.loc4_16.1 +// CHECK:STDOUT: %b.loc4_24.1: f64 = param b +// CHECK:STDOUT: @RuntimeCall.%b: f64 = bind_name b, %b.loc4_24.1 +// CHECK:STDOUT: @RuntimeCall.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref f64 = var x +// CHECK:STDOUT: %x: ref f64 = bind_name x, %x.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Sub(%a: f64, %b: f64) -> f64 = "float.sub"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCall(%a: f64, %b: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Sub.ref: = name_ref Sub, file.%Sub [template = file.%Sub] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %float.sub: init f64 = call %Sub.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc5_19.1: f64 = value_of_initializer %float.sub +// CHECK:STDOUT: %.loc5_19.2: f64 = converted %float.sub, %.loc5_19.1 +// CHECK:STDOUT: return %.loc5_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Sub.ref: = name_ref Sub, file.%Sub [template = file.%Sub] +// CHECK:STDOUT: %.loc8_18: f64 = float_literal 2 [template = constants.%.1] +// CHECK:STDOUT: %.loc8_23: f64 = float_literal 0.5 [template = constants.%.2] +// CHECK:STDOUT: %float.sub: init f64 = call %Sub.ref(%.loc8_18, %.loc8_23) [template = constants.%.3] +// CHECK:STDOUT: assign file.%x.var, %float.sub +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_bad_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .TooFew = %TooFew +// CHECK:STDOUT: .TooMany = %TooMany +// CHECK:STDOUT: .BadReturnType = %BadReturnType +// CHECK:STDOUT: .JustRight = %JustRight +// CHECK:STDOUT: .RuntimeCallTooFew = %RuntimeCallTooFew +// CHECK:STDOUT: .RuntimeCallTooMany = %RuntimeCallTooMany +// CHECK:STDOUT: .RuntimeCallBadReturnType = %RuntimeCallBadReturnType +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %TooFew: = fn_decl @TooFew [template] { +// CHECK:STDOUT: %a.loc8_11.1: f64 = param a +// CHECK:STDOUT: @TooFew.%a: f64 = bind_name a, %a.loc8_11.1 +// CHECK:STDOUT: @TooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %TooMany: = fn_decl @TooMany [template] { +// CHECK:STDOUT: %a.loc13_12.1: f64 = param a +// CHECK:STDOUT: @TooMany.%a: f64 = bind_name a, %a.loc13_12.1 +// CHECK:STDOUT: %b.loc13_20.1: f64 = param b +// CHECK:STDOUT: @TooMany.%b: f64 = bind_name b, %b.loc13_20.1 +// CHECK:STDOUT: %c.loc13_28.1: f64 = param c +// CHECK:STDOUT: @TooMany.%c: f64 = bind_name c, %c.loc13_28.1 +// CHECK:STDOUT: @TooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %BadReturnType: = fn_decl @BadReturnType [template] { +// CHECK:STDOUT: %a.loc17_18.1: f64 = param a +// CHECK:STDOUT: @BadReturnType.%a: f64 = bind_name a, %a.loc17_18.1 +// CHECK:STDOUT: %b.loc17_26.1: f64 = param b +// CHECK:STDOUT: @BadReturnType.%b: f64 = bind_name b, %b.loc17_26.1 +// CHECK:STDOUT: @BadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %JustRight: = fn_decl @JustRight [template] { +// CHECK:STDOUT: %a.loc18_14.1: f64 = param a +// CHECK:STDOUT: @JustRight.%a: f64 = bind_name a, %a.loc18_14.1 +// CHECK:STDOUT: %b.loc18_22.1: f64 = param b +// CHECK:STDOUT: @JustRight.%b: f64 = bind_name b, %b.loc18_22.1 +// CHECK:STDOUT: @JustRight.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooFew: = fn_decl @RuntimeCallTooFew [template] { +// CHECK:STDOUT: %a.loc20_22.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooFew.%a: f64 = bind_name a, %a.loc20_22.1 +// CHECK:STDOUT: @RuntimeCallTooFew.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallTooMany: = fn_decl @RuntimeCallTooMany [template] { +// CHECK:STDOUT: %a.loc24_23.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallTooMany.%a: f64 = bind_name a, %a.loc24_23.1 +// CHECK:STDOUT: %b.loc24_31.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallTooMany.%b: f64 = bind_name b, %b.loc24_31.1 +// CHECK:STDOUT: %c.loc24_39.1: f64 = param c +// CHECK:STDOUT: @RuntimeCallTooMany.%c: f64 = bind_name c, %c.loc24_39.1 +// CHECK:STDOUT: @RuntimeCallTooMany.%return: ref f64 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %RuntimeCallBadReturnType: = fn_decl @RuntimeCallBadReturnType [template] { +// CHECK:STDOUT: %a.loc28_29.1: f64 = param a +// CHECK:STDOUT: @RuntimeCallBadReturnType.%a: f64 = bind_name a, %a.loc28_29.1 +// CHECK:STDOUT: %b.loc28_37.1: f64 = param b +// CHECK:STDOUT: @RuntimeCallBadReturnType.%b: f64 = bind_name b, %b.loc28_37.1 +// CHECK:STDOUT: @RuntimeCallBadReturnType.%return: ref bool = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(%a: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(%a: f64, %b: f64, %c: f64) -> f64; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @BadReturnType(%a: f64, %b: f64) -> bool; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @JustRight(%a: f64, %b: f64) -> f64 = "float.sub"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooFew(%a: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooFew.ref: = name_ref TooFew, file.%TooFew [template = file.%TooFew] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %TooFew.call: init f64 = call %TooFew.ref(%a.ref) +// CHECK:STDOUT: %.loc21_19.1: f64 = value_of_initializer %TooFew.call +// CHECK:STDOUT: %.loc21_19.2: f64 = converted %TooFew.call, %.loc21_19.1 +// CHECK:STDOUT: return %.loc21_19.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallTooMany(%a: f64, %b: f64, %c: f64) -> f64 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %TooMany.ref: = name_ref TooMany, file.%TooMany [template = file.%TooMany] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %c.ref: f64 = name_ref c, %c +// CHECK:STDOUT: %TooMany.call: init f64 = call %TooMany.ref(%a.ref, %b.ref, %c.ref) +// CHECK:STDOUT: %.loc25_26.1: f64 = value_of_initializer %TooMany.call +// CHECK:STDOUT: %.loc25_26.2: f64 = converted %TooMany.call, %.loc25_26.1 +// CHECK:STDOUT: return %.loc25_26.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @RuntimeCallBadReturnType(%a: f64, %b: f64) -> bool { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %BadReturnType.ref: = name_ref BadReturnType, file.%BadReturnType [template = file.%BadReturnType] +// CHECK:STDOUT: %a.ref: f64 = name_ref a, %a +// CHECK:STDOUT: %b.ref: f64 = name_ref b, %b +// CHECK:STDOUT: %BadReturnType.call: init bool = call %BadReturnType.ref(%a.ref, %b.ref) +// CHECK:STDOUT: %.loc29_29.1: bool = value_of_initializer %BadReturnType.call +// CHECK:STDOUT: %.loc29_29.2: bool = converted %BadReturnType.call, %.loc29_29.1 +// CHECK:STDOUT: return %.loc29_29.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/call/fail_param_type.carbon b/toolchain/check/testdata/function/call/fail_param_type.carbon index e87095e60c9b..d0fb9c4d601d 100644 --- a/toolchain/check/testdata/function/call/fail_param_type.carbon +++ b/toolchain/check/testdata/function/call/fail_param_type.carbon @@ -19,7 +19,7 @@ fn F() { // CHECK:STDOUT: --- fail_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.1: f64 = float_literal 1 [template] // CHECK:STDOUT: %.2: type = tuple_type () [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -45,7 +45,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %G.ref: = name_ref G, file.%G [template = file.%G] -// CHECK:STDOUT: %.loc16: f64 = real_literal 10e-1 [template = constants.%.1] +// CHECK:STDOUT: %.loc16: f64 = float_literal 1 [template = constants.%.1] // CHECK:STDOUT: %G.call: init () = call %G.ref() [template = ] // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/function/call/fail_return_type_mismatch.carbon b/toolchain/check/testdata/function/call/fail_return_type_mismatch.carbon index e9cfdb18e1ac..16a1c3d9c7af 100644 --- a/toolchain/check/testdata/function/call/fail_return_type_mismatch.carbon +++ b/toolchain/check/testdata/function/call/fail_return_type_mismatch.carbon @@ -16,7 +16,7 @@ fn Run() { // CHECK:STDOUT: --- fail_return_type_mismatch.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.1: f64 = float_literal 1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -34,7 +34,7 @@ fn Run() { // CHECK:STDOUT: // CHECK:STDOUT: fn @Foo() -> f64 { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc7: f64 = real_literal 10e-1 [template = constants.%.1] +// CHECK:STDOUT: %.loc7: f64 = float_literal 1 [template = constants.%.1] // CHECK:STDOUT: return %.loc7 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon b/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon index 51ac2ecb517c..dd37daf4027d 100644 --- a/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_array_non_int_indexing.carbon @@ -20,7 +20,7 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: %.5: type = tuple_type (i32) [template] // CHECK:STDOUT: %.6: i32 = int_literal 0 [template] // CHECK:STDOUT: %.7: [i32; 1] = tuple_value (%.4) [template] -// CHECK:STDOUT: %.8: f64 = real_literal 26e-1 [template] +// CHECK:STDOUT: %.8: f64 = float_literal 2.6000000000000001 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -49,7 +49,7 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: %.loc7_24: init [i32; 1] = converted %.loc7_23.1, %.loc7_23.5 [template = constants.%.7] // CHECK:STDOUT: assign file.%a.var, %.loc7_24 // CHECK:STDOUT: %a.ref: ref [i32; 1] = name_ref a, file.%a -// CHECK:STDOUT: %.loc11_16: f64 = real_literal 26e-1 [template = constants.%.8] +// CHECK:STDOUT: %.loc11_16: f64 = float_literal 2.6000000000000001 [template = constants.%.8] // CHECK:STDOUT: %.loc11_19.1: ref i32 = array_index %a.ref, // CHECK:STDOUT: %.loc11_19.2: i32 = bind_value %.loc11_19.1 // CHECK:STDOUT: assign file.%b.var, %.loc11_19.2 diff --git a/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon b/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon index 7f85fd6c11fc..c4a35137e148 100644 --- a/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon +++ b/toolchain/check/testdata/index/fail_tuple_non_int_indexing.carbon @@ -19,7 +19,7 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: %.4: i32 = int_literal 12 [template] // CHECK:STDOUT: %.5: i32 = int_literal 6 [template] // CHECK:STDOUT: %.6: (i32, i32) = tuple_value (%.4, %.5) [template] -// CHECK:STDOUT: %.7: f64 = real_literal 26e-1 [template] +// CHECK:STDOUT: %.7: f64 = float_literal 2.6000000000000001 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -50,7 +50,7 @@ var b: i32 = a[2.6]; // CHECK:STDOUT: %.loc7_28: init (i32, i32) = converted %.loc7_27.1, %.loc7_27.6 [template = constants.%.6] // CHECK:STDOUT: assign file.%a.var, %.loc7_28 // CHECK:STDOUT: %a.ref: ref (i32, i32) = name_ref a, file.%a -// CHECK:STDOUT: %.loc11_16: f64 = real_literal 26e-1 [template = constants.%.7] +// CHECK:STDOUT: %.loc11_16: f64 = float_literal 2.6000000000000001 [template = constants.%.7] // CHECK:STDOUT: %.loc11_19: ref = tuple_index %a.ref, // CHECK:STDOUT: assign file.%b.var, // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon index 06ab78c0178d..6f42868544f4 100644 --- a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_assignment.carbon @@ -16,7 +16,7 @@ fn Main() { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: i32 = int_literal 3 [template] -// CHECK:STDOUT: %.2: f64 = real_literal 56e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 5.6000000000000005 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -35,7 +35,7 @@ fn Main() { // CHECK:STDOUT: %.loc8: i32 = int_literal 3 [template = constants.%.1] // CHECK:STDOUT: assign %a.var, %.loc8 // CHECK:STDOUT: %a.ref: ref i32 = name_ref a, %a -// CHECK:STDOUT: %.loc12: f64 = real_literal 56e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc12: f64 = float_literal 5.6000000000000005 [template = constants.%.2] // CHECK:STDOUT: assign %a.ref, // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon index 7ebe68f9aac4..b2bb5e94a901 100644 --- a/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon +++ b/toolchain/check/testdata/operators/builtin/fail_type_mismatch_once.carbon @@ -29,7 +29,7 @@ fn Main() -> i32 { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: i32 = int_literal 12 [template] -// CHECK:STDOUT: %.2: f64 = real_literal 34e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 3.4000000000000004 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -46,7 +46,7 @@ fn Main() -> i32 { // CHECK:STDOUT: fn @Main() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc25_10: i32 = int_literal 12 [template = constants.%.1] -// CHECK:STDOUT: %.loc25_15: f64 = real_literal 34e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc25_15: f64 = float_literal 3.4000000000000004 [template = constants.%.2] // CHECK:STDOUT: %.loc25_21: i32 = int_literal 12 [template = constants.%.1] // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/pointer/fail_address_of_value.carbon b/toolchain/check/testdata/pointer/fail_address_of_value.carbon index 45a815a5e977..08777424cee2 100644 --- a/toolchain/check/testdata/pointer/fail_address_of_value.carbon +++ b/toolchain/check/testdata/pointer/fail_address_of_value.carbon @@ -103,7 +103,7 @@ fn AddressOfParam(param: i32) { // CHECK:STDOUT: %.3: type = ptr_type i32 [template] // CHECK:STDOUT: %.4: bool = bool_literal true [template] // CHECK:STDOUT: %.5: type = ptr_type bool [template] -// CHECK:STDOUT: %.6: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.6: f64 = float_literal 1 [template] // CHECK:STDOUT: %.7: type = ptr_type f64 [template] // CHECK:STDOUT: %.8: type = ptr_type String [template] // CHECK:STDOUT: %.9: String = string_literal "Hello" [template] @@ -161,7 +161,7 @@ fn AddressOfParam(param: i32) { // CHECK:STDOUT: %.loc16_3: i32* = addr_of [template = ] // CHECK:STDOUT: %.loc21_4: bool = bool_literal true [template = constants.%.4] // CHECK:STDOUT: %.loc21_3: bool* = addr_of [template = ] -// CHECK:STDOUT: %.loc26_4: f64 = real_literal 10e-1 [template = constants.%.6] +// CHECK:STDOUT: %.loc26_4: f64 = float_literal 1 [template = constants.%.6] // CHECK:STDOUT: %.loc26_3: f64* = addr_of [template = ] // CHECK:STDOUT: %.loc31_4: String = string_literal "Hello" [template = constants.%.9] // CHECK:STDOUT: %.loc31_3: String* = addr_of [template = ] diff --git a/toolchain/check/testdata/return/fail_returned_var_type.carbon b/toolchain/check/testdata/return/fail_returned_var_type.carbon index 64a9fce075df..bc2399354ee0 100644 --- a/toolchain/check/testdata/return/fail_returned_var_type.carbon +++ b/toolchain/check/testdata/return/fail_returned_var_type.carbon @@ -18,7 +18,7 @@ fn Mismatch() -> i32 { // CHECK:STDOUT: --- fail_returned_var_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: f64 = real_literal 0e-1 [template] +// CHECK:STDOUT: %.1: f64 = float_literal 0 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -35,7 +35,7 @@ fn Mismatch() -> i32 { // CHECK:STDOUT: fn @Mismatch() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %v: f64 = bind_name v, -// CHECK:STDOUT: %.loc14: f64 = real_literal 0e-1 [template = constants.%.1] +// CHECK:STDOUT: %.loc14: f64 = float_literal 0 [template = constants.%.1] // CHECK:STDOUT: assign , // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/return/fail_type_mismatch.carbon b/toolchain/check/testdata/return/fail_type_mismatch.carbon index 93aef97fc7f3..67ef19669b8a 100644 --- a/toolchain/check/testdata/return/fail_type_mismatch.carbon +++ b/toolchain/check/testdata/return/fail_type_mismatch.carbon @@ -14,7 +14,7 @@ fn Main() -> i32 { // CHECK:STDOUT: --- fail_type_mismatch.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.1: f64 = float_literal 1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -30,7 +30,7 @@ fn Main() -> i32 { // CHECK:STDOUT: // CHECK:STDOUT: fn @Main() -> i32 { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc11: f64 = real_literal 10e-1 [template = constants.%.1] +// CHECK:STDOUT: %.loc11: f64 = float_literal 1 [template = constants.%.1] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/struct/fail_field_type_mismatch.carbon b/toolchain/check/testdata/struct/fail_field_type_mismatch.carbon index 0b44662d0060..5e5f1e6279af 100644 --- a/toolchain/check/testdata/struct/fail_field_type_mismatch.carbon +++ b/toolchain/check/testdata/struct/fail_field_type_mismatch.carbon @@ -13,7 +13,7 @@ var x: {.a: i32} = {.b = 1.0}; // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: type = struct_type {.a: i32} [template] -// CHECK:STDOUT: %.2: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 1 [template] // CHECK:STDOUT: %.3: type = struct_type {.b: f64} [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -30,7 +30,7 @@ var x: {.a: i32} = {.b = 1.0}; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc10_26: f64 = real_literal 10e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_26: f64 = float_literal 1 [template = constants.%.2] // CHECK:STDOUT: %.loc10_29: {.b: f64} = struct_literal (%.loc10_26) // CHECK:STDOUT: assign file.%x.var, // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/struct/fail_member_access_type.carbon b/toolchain/check/testdata/struct/fail_member_access_type.carbon index 38577e768477..8c83fac613ec 100644 --- a/toolchain/check/testdata/struct/fail_member_access_type.carbon +++ b/toolchain/check/testdata/struct/fail_member_access_type.carbon @@ -14,7 +14,7 @@ var y: i32 = x.b; // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: type = struct_type {.a: f64} [template] -// CHECK:STDOUT: %.2: f64 = real_literal 40e-1 [template] +// CHECK:STDOUT: %.2: f64 = float_literal 4 [template] // CHECK:STDOUT: %.3: {.a: f64} = struct_value (%.2) [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -34,7 +34,7 @@ var y: i32 = x.b; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc7_26: f64 = real_literal 40e-1 [template = constants.%.2] +// CHECK:STDOUT: %.loc7_26: f64 = float_literal 4 [template = constants.%.2] // CHECK:STDOUT: %.loc7_29.1: {.a: f64} = struct_literal (%.loc7_26) // CHECK:STDOUT: %.loc7_29.2: init {.a: f64} = struct_init (%.loc7_26) to file.%x.var [template = constants.%.3] // CHECK:STDOUT: %.loc7_30: init {.a: f64} = converted %.loc7_29.1, %.loc7_29.2 [template = constants.%.3] diff --git a/toolchain/check/testdata/struct/member_access.carbon b/toolchain/check/testdata/struct/member_access.carbon index 7e50a2f91cd6..ee19edeb0ed6 100644 --- a/toolchain/check/testdata/struct/member_access.carbon +++ b/toolchain/check/testdata/struct/member_access.carbon @@ -13,7 +13,7 @@ var z: i32 = y; // CHECK:STDOUT: constants { // CHECK:STDOUT: %.1: type = struct_type {.a: f64, .b: i32} [template] // CHECK:STDOUT: %.2: type = ptr_type {.a: f64, .b: i32} [template] -// CHECK:STDOUT: %.3: f64 = real_literal 0e-1 [template] +// CHECK:STDOUT: %.3: f64 = float_literal 0 [template] // CHECK:STDOUT: %.4: i32 = int_literal 1 [template] // CHECK:STDOUT: %.5: {.a: f64, .b: i32} = struct_value (%.3, %.4) [template] // CHECK:STDOUT: } @@ -37,7 +37,7 @@ var z: i32 = y; // CHECK:STDOUT: // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc7_35: f64 = real_literal 0e-1 [template = constants.%.3] +// CHECK:STDOUT: %.loc7_35: f64 = float_literal 0 [template = constants.%.3] // CHECK:STDOUT: %.loc7_45: i32 = int_literal 1 [template = constants.%.4] // CHECK:STDOUT: %.loc7_46.1: {.a: f64, .b: i32} = struct_literal (%.loc7_35, %.loc7_45) // CHECK:STDOUT: %.loc7_46.2: ref f64 = struct_access file.%x.var, element0 diff --git a/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon b/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon index de1d8ade2966..c4b8e49ddf47 100644 --- a/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon +++ b/toolchain/check/testdata/tuples/fail_element_type_mismatch.carbon @@ -16,7 +16,7 @@ var x: (i32, i32) = (2, 65.89); // CHECK:STDOUT: %.2: type = tuple_type (i32, i32) [template] // CHECK:STDOUT: %.3: type = ptr_type (i32, i32) [template] // CHECK:STDOUT: %.4: i32 = int_literal 2 [template] -// CHECK:STDOUT: %.5: f64 = real_literal 6589e-2 [template] +// CHECK:STDOUT: %.5: f64 = float_literal 65.890000000000001 [template] // CHECK:STDOUT: %.6: type = tuple_type (i32, f64) [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -35,7 +35,7 @@ var x: (i32, i32) = (2, 65.89); // CHECK:STDOUT: fn @__global_init() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %.loc10_22: i32 = int_literal 2 [template = constants.%.4] -// CHECK:STDOUT: %.loc10_25: f64 = real_literal 6589e-2 [template = constants.%.5] +// CHECK:STDOUT: %.loc10_25: f64 = float_literal 65.890000000000001 [template = constants.%.5] // CHECK:STDOUT: %.loc10_30.1: (i32, f64) = tuple_literal (%.loc10_22, %.loc10_25) // CHECK:STDOUT: %.loc10_30.2: ref i32 = tuple_access file.%x.var, element0 // CHECK:STDOUT: %.loc10_30.3: init i32 = initialize_from %.loc10_22 to %.loc10_30.2 [template = constants.%.4] diff --git a/toolchain/check/testdata/var/fail_init_type_mismatch.carbon b/toolchain/check/testdata/var/fail_init_type_mismatch.carbon index c2a0e98365d7..12eaf131589d 100644 --- a/toolchain/check/testdata/var/fail_init_type_mismatch.carbon +++ b/toolchain/check/testdata/var/fail_init_type_mismatch.carbon @@ -14,7 +14,7 @@ fn Main() { // CHECK:STDOUT: --- fail_init_type_mismatch.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: f64 = real_literal 10e-1 [template] +// CHECK:STDOUT: %.1: f64 = float_literal 1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -30,7 +30,7 @@ fn Main() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x.var: ref i32 = var x // CHECK:STDOUT: %x: ref i32 = bind_name x, %x.var -// CHECK:STDOUT: %.loc11: f64 = real_literal 10e-1 [template = constants.%.1] +// CHECK:STDOUT: %.loc11: f64 = float_literal 1 [template = constants.%.1] // CHECK:STDOUT: assign %x.var, // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index ff4d22e39cf8..bad0c5cdd0a7 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -258,6 +258,8 @@ CARBON_DIAGNOSTIC_KIND(DerefOfNonPointer) CARBON_DIAGNOSTIC_KIND(DerefOfType) CARBON_DIAGNOSTIC_KIND(CompileTimeBindingInVarDecl) CARBON_DIAGNOSTIC_KIND(CompoundMemberAccessDoesNotUseBase) +CARBON_DIAGNOSTIC_KIND(RealMantissaTooLargeForI64) +CARBON_DIAGNOSTIC_KIND(RealExponentTooLargeForI64) CARBON_DIAGNOSTIC_KIND(NameAmbiguousDueToExtend) CARBON_DIAGNOSTIC_KIND(NameNotFound) CARBON_DIAGNOSTIC_KIND(NameDeclDuplicate) diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index ee962cfdd267..0088094d6f48 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -371,6 +371,35 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, context.GetValue(arg_ids[0]), context.GetValue(arg_ids[1]))); return; } + case SemIR::BuiltinFunctionKind::FloatNegate: { + context.SetLocal(inst_id, context.builder().CreateFNeg( + context.GetValue(arg_ids[0]), "fneg")); + return; + } + case SemIR::BuiltinFunctionKind::FloatAdd: { + context.SetLocal(inst_id, context.builder().CreateFAdd( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "fadd")); + return; + } + case SemIR::BuiltinFunctionKind::FloatSub: { + context.SetLocal(inst_id, context.builder().CreateFSub( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "fsub")); + return; + } + case SemIR::BuiltinFunctionKind::FloatMul: { + context.SetLocal(inst_id, context.builder().CreateFMul( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "fmul")); + return; + } + case SemIR::BuiltinFunctionKind::FloatDiv: { + context.SetLocal(inst_id, context.builder().CreateFDiv( + context.GetValue(arg_ids[0]), + context.GetValue(arg_ids[1]), "fdiv")); + return; + } } CARBON_FATAL() << "Unsupported builtin call."; @@ -421,6 +450,13 @@ auto HandleDeref(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.pointer_id)); } +auto HandleFloatLiteral(FunctionContext& context, SemIR::InstId inst_id, + SemIR::FloatLiteral inst) -> void { + const llvm::APFloat& value = context.sem_ir().floats().Get(inst.float_id); + context.SetLocal( + inst_id, llvm::ConstantFP::get(context.builder().getDoubleTy(), value)); +} + auto HandleFunctionDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::FunctionDecl inst) -> void { FatalErrorIfEncountered(inst); diff --git a/toolchain/lower/handle_type.cpp b/toolchain/lower/handle_type.cpp index 0a10f7155bed..0cdbc547e3f2 100644 --- a/toolchain/lower/handle_type.cpp +++ b/toolchain/lower/handle_type.cpp @@ -32,6 +32,11 @@ auto HandleFacetTypeAccess(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetTypeAsValue()); } +auto HandleFloatType(FunctionContext& context, SemIR::InstId inst_id, + SemIR::FloatType /*inst*/) -> void { + context.SetLocal(inst_id, context.GetTypeAsValue()); +} + auto HandleInterfaceType(FunctionContext& context, SemIR::InstId inst_id, SemIR::InterfaceType /*inst*/) -> void { context.SetLocal(inst_id, context.GetTypeAsValue()); diff --git a/toolchain/lower/testdata/builtins/float.carbon b/toolchain/lower/testdata/builtins/float.carbon new file mode 100644 index 000000000000..6f55065a5a39 --- /dev/null +++ b/toolchain/lower/testdata/builtins/float.carbon @@ -0,0 +1,53 @@ +// 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 + +fn Negate(a: f64) -> f64 = "float.negate"; +fn TestNegate(a: f64) -> f64 { return Negate(a); } + +fn Add(a: f64, b: f64) -> f64 = "float.add"; +fn TestAdd(a: f64, b: f64) -> f64 { return Add(a, b); } + +fn Sub(a: f64, b: f64) -> f64 = "float.sub"; +fn TestSub(a: f64, b: f64) -> f64 { return Sub(a, b); } + +fn Mul(a: f64, b: f64) -> f64 = "float.mul"; +fn TestMul(a: f64, b: f64) -> f64 { return Mul(a, b); } + +fn Div(a: f64, b: f64) -> f64 = "float.div"; +fn TestDiv(a: f64, b: f64) -> f64 { return Div(a, b); } + +// CHECK:STDOUT: ; ModuleID = 'float.carbon' +// CHECK:STDOUT: source_filename = "float.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define double @TestNegate(double %a) { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %float.negate.fneg = fneg double %a +// CHECK:STDOUT: ret double %float.negate.fneg +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define double @TestAdd(double %a, double %b) { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %float.add.fadd = fadd double %a, %b +// CHECK:STDOUT: ret double %float.add.fadd +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define double @TestSub(double %a, double %b) { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %float.sub.fsub = fsub double %a, %b +// CHECK:STDOUT: ret double %float.sub.fsub +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define double @TestMul(double %a, double %b) { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %float.mul.fmul = fmul double %a, %b +// CHECK:STDOUT: ret double %float.mul.fmul +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define double @TestDiv(double %a, double %b) { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %float.div.fdiv = fdiv double %a, %b +// CHECK:STDOUT: ret double %float.div.fdiv +// CHECK:STDOUT: } diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index dff83260d99e..39e3bd1a951a 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -75,6 +75,17 @@ struct AnyInt { } }; +// Constraint that requires the type to be a float type. +struct AnyFloat { + static auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) + -> bool { + if (BuiltinType::Check(sem_ir, state, type_id)) { + return true; + } + return sem_ir.types().Is(type_id); + } +}; + // Constraint that requires the type to be the type type. using Type = BuiltinType; @@ -139,6 +150,10 @@ using IntT = TypeParam<0, AnyInt>; // generic type parameter that is constrained to be an integer type. using IntU = TypeParam<1, AnyInt>; +// Convenience name used in the builtin type signatures below for a first +// generic type parameter that is constrained to be an float type. +using FloatT = TypeParam<0, AnyFloat>; + // Not a builtin function. constexpr BuiltinInfo None = {"", nullptr}; @@ -260,6 +275,26 @@ constexpr BuiltinInfo IntGreater = {"int.greater", constexpr BuiltinInfo IntGreaterEq = { "int.greater_eq", ValidateSignatureBool>}; +// "float.negate": float negation. +constexpr BuiltinInfo FloatNegate = {"float.negate", + ValidateSignatureFloatT>}; + +// "float.add": float addition. +constexpr BuiltinInfo FloatAdd = { + "float.add", ValidateSignatureFloatT>}; + +// "float.sub": float subtraction. +constexpr BuiltinInfo FloatSub = { + "float.sub", ValidateSignatureFloatT>}; + +// "float.mul": float multiplication. +constexpr BuiltinInfo FloatMul = { + "float.mul", ValidateSignatureFloatT>}; + +// "float.div": float division. +constexpr BuiltinInfo FloatDiv = { + "float.div", ValidateSignatureFloatT>}; + } // 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 d3e32b8eb1cf..a538fb8f3f8d 100644 --- a/toolchain/sem_ir/builtin_function_kind.def +++ b/toolchain/sem_ir/builtin_function_kind.def @@ -55,4 +55,11 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntLessEq) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreater) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntGreaterEq) +// Float arithmetic. +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatNegate) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatAdd) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatSub) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatMul) +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatDiv) + #undef CARBON_SEM_IR_BUILTIN_FUNCTION_KIND diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index d2d6e9ac0bc3..c57f3feda217 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -207,6 +207,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case Builtin::Kind: case ClassType::Kind: case FacetTypeAccess::Kind: + case FloatType::Kind: case ImportRefLoaded::Kind: case ImportRefUsed::Kind: case InterfaceType::Kind: @@ -246,6 +247,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case Converted::Kind: case Deref::Kind: case FieldDecl::Kind: + case FloatLiteral::Kind: case FunctionDecl::Kind: case ImplDecl::Kind: case ImportRefUnloaded::Kind: @@ -382,6 +384,21 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir, push_inst_id(inst.facet_id); break; } + case CARBON_KIND(FloatType inst): { + // TODO: Is this okay? + if (step.index == 1) { + out << ")"; + } else if (auto width_value = + sem_ir.insts().TryGetAs(inst.bit_width_id)) { + out << "f"; + sem_ir.ints().Get(width_value->int_id).print(out, /*isSigned=*/false); + } else { + out << "Core.Float("; + steps.push_back(step.Next()); + push_inst_id(inst.bit_width_id); + } + break; + } case ImportRefLoaded::Kind: case ImportRefUsed::Kind: { auto import_ir_inst = sem_ir.import_ir_insts().Get( @@ -505,6 +522,7 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir, case Converted::Kind: case Deref::Kind: case FieldDecl::Kind: + case FloatLiteral::Kind: case FunctionDecl::Kind: case ImplDecl::Kind: case ImportRefUnloaded::Kind: @@ -623,6 +641,8 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case ClassType::Kind: case ConstType::Kind: case FacetTypeAccess::Kind: + case FloatLiteral::Kind: + case FloatType::Kind: case InterfaceDecl::Kind: case InterfaceType::Kind: case InterfaceWitness::Kind: diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 267245f1d1cb..6dcc11dba492 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -115,6 +115,10 @@ class File : public Printable { auto reals() const -> const ValueStore& { return value_stores_->reals(); } + auto floats() -> ValueStore& { return value_stores_->floats(); } + auto floats() const -> const ValueStore& { + return value_stores_->floats(); + } auto string_literal_values() -> StringStoreWrapper& { return value_stores_->string_literal_values(); } diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index f1090d6f1398..f82222579750 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -614,6 +614,12 @@ class Formatter { .print(out_, sem_ir_.types().IsSignedInt(inst.type_id)); } + auto FormatInstructionRHS(FloatLiteral inst) -> void { + llvm::SmallVector buffer; + sem_ir_.floats().Get(inst.float_id).toString(buffer); + out_ << " " << buffer; + } + auto FormatInstructionRHS(ImportRefUnloaded inst) -> void { FormatArgs(inst.import_ir_inst_id); out_ << ", unloaded"; @@ -675,6 +681,8 @@ class Formatter { auto FormatArg(IntKind k) -> void { k.Print(out_); } + auto FormatArg(FloatKind k) -> void { k.Print(out_); } + auto FormatArg(ImplId id) -> void { FormatImplName(id); } auto FormatArg(ImportIRId id) -> void { out_ << id; } diff --git a/toolchain/sem_ir/id_kind.h b/toolchain/sem_ir/id_kind.h index 201d4248395e..0b1c55b8d8ff 100644 --- a/toolchain/sem_ir/id_kind.h +++ b/toolchain/sem_ir/id_kind.h @@ -118,11 +118,11 @@ using IdKind = TypeEnum< // From sem_ir/builtin_kind.h. BuiltinKind, // From base/value_store.h. - IntId, RealId, StringLiteralValueId, + IntId, RealId, FloatId, StringLiteralValueId, // From sem_ir/id.h. InstId, ConstantId, BindNameId, FunctionId, ClassId, InterfaceId, ImplId, ImportIRId, ImportIRInstId, LocId, BoolValue, IntKind, NameId, NameScopeId, - InstBlockId, TypeId, TypeBlockId, ElementIndex>; + InstBlockId, TypeId, TypeBlockId, ElementIndex, FloatKind>; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 93553aad073e..5811494becb9 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -332,6 +332,13 @@ struct IntKind : public IdBase, public Printable { constexpr IntKind IntKind::Unsigned = IntKind(0); constexpr IntKind IntKind::Signed = IntKind(1); +// A float kind value +struct FloatKind : public IdBase, public Printable { + using IdBase::IdBase; + + auto Print(llvm::raw_ostream& out) const -> void { out << "float"; } +}; + // The ID of a name. A name is either a string or a special name such as // `self`, `Self`, or `base`. struct NameId : public IdBase, public Printable { diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 7e855cb2cfd1..46a86f2de52b 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -49,6 +49,8 @@ CARBON_SEM_IR_INST_KIND(ConstType) CARBON_SEM_IR_INST_KIND(Converted) CARBON_SEM_IR_INST_KIND(Deref) CARBON_SEM_IR_INST_KIND(FacetTypeAccess) +CARBON_SEM_IR_INST_KIND(FloatLiteral) +CARBON_SEM_IR_INST_KIND(FloatType) CARBON_SEM_IR_INST_KIND(FieldDecl) CARBON_SEM_IR_INST_KIND(FunctionDecl) CARBON_SEM_IR_INST_KIND(ImplDecl) diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index 0b627d9dcddb..563cc5f616fe 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -444,6 +444,24 @@ struct FacetTypeAccess { InstId facet_id; }; +struct FloatLiteral { + static constexpr auto Kind = + InstKind::FloatLiteral.Define("float_literal"); + + TypeId type_id; + FloatId float_id; +}; + +struct FloatType { + static constexpr auto Kind = + InstKind::FloatType.Define("float_type"); + + TypeId type_id; + // TODO: Consider adding a more compact way of representing either a small + // float bit width or an inst_id. + InstId bit_width_id; +}; + // A field in a class, of the form `var field: field_type;`. The type of the // `FieldDecl` instruction is an `UnboundElementType`. struct FieldDecl {