From 88c191146d2b0f1704cad4e5878588ab1b6e4bb0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 3 Jun 2026 17:33:33 -0700 Subject: [PATCH] Support for float <-> float conversions. (#7279) Implement support for floating-point <-> floating-point type conversions as described in https://github.com/carbon-language/carbon-lang/pull/820 and https://github.com/carbon-language/carbon-lang/pull/845. Value-preserving conversions are implicit; narrowing conversions require explicit `as`. Assisted-by: Gemini via Antigravity --- core/prelude/operators/as.carbon | 1 + core/prelude/types/float.carbon | 41 +- toolchain/check/core_identifier.def | 1 + toolchain/check/cpp/impl_lookup.cpp | 3 +- toolchain/check/custom_witness.cpp | 75 ++ toolchain/check/eval.cpp | 23 +- .../testdata/builtins/float/convert.carbon | 657 ++++++++++++++++++ .../impl/custom_witness/float_fits_in.carbon | 61 ++ .../impl/custom_witness/int_fits_in.carbon | 5 + .../primitives/float_conversions.carbon | 31 + toolchain/lower/handle_call.cpp | 7 + .../testdata/builtins/float_to_float.carbon | 75 ++ toolchain/sem_ir/builtin_function_kind.cpp | 5 + toolchain/sem_ir/builtin_function_kind.def | 1 + toolchain/sem_ir/core_interface_kind.def | 1 + 15 files changed, 976 insertions(+), 11 deletions(-) create mode 100644 toolchain/check/testdata/builtins/float/convert.carbon create mode 100644 toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon create mode 100644 toolchain/lower/testdata/builtins/float_to_float.carbon diff --git a/core/prelude/operators/as.carbon b/core/prelude/operators/as.carbon index 2f13b4f133ff..1e3a90f4ec95 100644 --- a/core/prelude/operators/as.carbon +++ b/core/prelude/operators/as.carbon @@ -74,3 +74,4 @@ impl FloatLiteral() as UnsafeAs(IntLiteral()) { } interface IntFitsIn(Dest:! type) {} +interface FloatFitsIn(Src:! type) {} diff --git a/core/prelude/types/float.carbon b/core/prelude/types/float.carbon index 1d72fb4b7146..b8c3a199f846 100644 --- a/core/prelude/types/float.carbon +++ b/core/prelude/types/float.carbon @@ -27,8 +27,8 @@ impl forall [N:! IntLiteral()] Float(N) as Copy { fn Op[self: Self]() -> Self = "primitive_copy"; } -// Conversions between floating-point types. -// TODO: Support mixed-size conversions. +// Conversions between floating-point types. Implicit if all the source values +// can be represented exactly in the target type, otherwise explicit. impl forall [N:! IntLiteral()] FloatLiteral() as ImplicitAs(Float(N)) { fn Convert[self: Self]() -> Float(N) = "float.convert_checked"; } @@ -38,6 +38,43 @@ impl forall [N:! IntLiteral()] FloatLiteral() as As(Float(N)) { fn Convert[self: Self]() -> Float(N) = "float.convert_checked"; } +final impl forall [From:! IntLiteral(), To:! IntLiteral()] + Float(From) as As(Float(To)) { + fn Convert[self: Self]() -> Float(To) = "float.convert"; +} + +// AnyFloat exists to work around the inability to apply constraints to an impl +// that is only parameterized by integers. +// TODO: Remove these once possible. +private interface AnyFloat { + let Width:! IntLiteral(); + fn AsFloat[self: Self]() -> Float(Width); + fn Make(src: Float(Width)) -> Self; +} + +impl forall [N:! IntLiteral()] Float(N) as AnyFloat where .Width = N { + fn AsFloat[self: Self]() -> Self { return self; } + fn Make(src: Self) -> Self { return src; } +} + +// Use `Float(?) as ImplicitAs(?)` to avoid a collision with the +// `? as ImplicitAs(Float(?))` type structure used by int -> float conversion. +// TODO: Use `match_first` to resolve this instead once it is available. +impl forall [From:! IntLiteral(), To:! AnyFloat where Float(From) impls FloatFitsIn(.Self)] + Float(From) as ImplicitAs(To) { + fn Convert[self: Self]() -> To { + fn Impl(src: Float(From)) -> Float(To.Width) = "float.convert"; + return To.Make(Impl(self)); + } +} + +// Desired workaround-free version of the above: +// impl forall [From:! IntLiteral(), To:! IntLiteral() +// where Float(From) impls FloatFitsIn(Float(To))] +// Float(From) as ImplicitAs(Float(To)) { +// fn Convert[self: Self]() -> Float(To) = "float.convert"; +// } + // Conversions from floating-point to integer type. Always unsafe: not all // source values fit in the target type. final impl forall [From:! IntLiteral(), To:! IntLiteral()] diff --git a/toolchain/check/core_identifier.def b/toolchain/check/core_identifier.def index 2d1e4374b735..a6da18564238 100644 --- a/toolchain/check/core_identifier.def +++ b/toolchain/check/core_identifier.def @@ -44,6 +44,7 @@ CARBON_CORE_IDENTIFIER(DivWith) CARBON_CORE_IDENTIFIER(EqWith) CARBON_CORE_IDENTIFIER(Equal) CARBON_CORE_IDENTIFIER(Float) +CARBON_CORE_IDENTIFIER(FloatFitsIn) CARBON_CORE_IDENTIFIER(Get) CARBON_CORE_IDENTIFIER(Greater) CARBON_CORE_IDENTIFIER(GreaterOrEquivalent) diff --git a/toolchain/check/cpp/impl_lookup.cpp b/toolchain/check/cpp/impl_lookup.cpp index d5215db3de56..9886e73d0c5d 100644 --- a/toolchain/check/cpp/impl_lookup.cpp +++ b/toolchain/check/cpp/impl_lookup.cpp @@ -606,8 +606,9 @@ auto LookupCppImpl(Context& context, SemIR::LocId loc_id, return BuildCppRangeForIterateWitness( context, loc_id, query_self_const_id, query_specific_interface_id); - // IntFitsIn is for Carbon integer types only. + // *FitsIn are implemented only by Carbon primitive types. case SemIR::CoreInterface::IntFitsIn: + case SemIR::CoreInterface::FloatFitsIn: return SemIR::InstId::None; case SemIR::CoreInterface::Unknown: diff --git a/toolchain/check/custom_witness.cpp b/toolchain/check/custom_witness.cpp index 3c8b90c0aef6..823a86c8dd50 100644 --- a/toolchain/check/custom_witness.cpp +++ b/toolchain/check/custom_witness.cpp @@ -740,6 +740,78 @@ static auto MakeIntFitsInWitness( query_specific_interface_id, {}); } +static auto MakeFloatFitsInWitness( + Context& context, SemIR::LocId loc_id, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterfaceId query_specific_interface_id, bool build_witness) + -> std::optional { + auto query_specific_interface = + context.specific_interfaces().Get(query_specific_interface_id); + + auto args_id = query_specific_interface.specific_id; + if (!args_id.has_value()) { + return std::nullopt; + } + auto args_block_id = context.specifics().Get(args_id).args_id; + auto args_block = context.inst_blocks().Get(args_block_id); + if (args_block.size() != 1) { + return std::nullopt; + } + + auto dest_const_id = context.constant_values().Get(args_block[0]); + if (!dest_const_id.is_constant()) { + return std::nullopt; + } + + auto src_type_id = GetFacetAsType(context, query_self_const_id); + auto dest_type_id = GetFacetAsType(context, dest_const_id); + + auto context_fn = [](DiagnosticContextBuilder& /*builder*/) -> void {}; + if (!RequireCompleteType(context, src_type_id, loc_id, context_fn) || + !RequireCompleteType(context, dest_type_id, loc_id, context_fn)) { + return std::nullopt; + } + + // Ensure both are actually floating-point types. + auto src_object_rep_id = context.types().GetObjectRepr(src_type_id); + auto src_float_type = + context.types().TryGetAs(src_object_rep_id); + if (!src_float_type) { + return std::nullopt; + } + + auto dest_object_rep_id = context.types().GetObjectRepr(dest_type_id); + auto dest_float_type = + context.types().TryGetAs(dest_object_rep_id); + if (!dest_float_type) { + return std::nullopt; + } + + // Get their bit widths. + auto src_width_opt = + context.sem_ir().GetZExtIntValue(src_float_type->bit_width_id); + auto dest_width_opt = + context.sem_ir().GetZExtIntValue(dest_float_type->bit_width_id); + + if (!src_width_opt || !dest_width_opt) { + // If the bit width is unknown (e.g. symbolic), we can't decide yet. + return std::nullopt; + } + + const auto& src_semantics = src_float_type->float_kind.Semantics(); + const auto& dest_semantics = dest_float_type->float_kind.Semantics(); + if (!llvm::APFloat::isRepresentableBy(src_semantics, dest_semantics)) { + return std::nullopt; + } + + if (!build_witness) { + return SemIR::InstId::None; + } + + return BuildCustomWitness(context, loc_id, query_self_const_id, + query_specific_interface_id, {}); +} + auto LookupCustomWitness(Context& context, SemIR::LocId loc_id, SemIR::CoreInterface core_interface, SemIR::ConstantId query_self_const_id, @@ -749,6 +821,9 @@ auto LookupCustomWitness(Context& context, SemIR::LocId loc_id, case SemIR::CoreInterface::Destroy: return LookupDestroyWitness(context, loc_id, query_self_const_id, query_specific_interface_id, build_witness); + case SemIR::CoreInterface::FloatFitsIn: + return MakeFloatFitsInWitness(context, loc_id, query_self_const_id, + query_specific_interface_id, build_witness); case SemIR::CoreInterface::IntFitsIn: return MakeIntFitsInWitness(context, loc_id, query_self_const_id, query_specific_interface_id, build_witness); diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 129632c04649..b96eaa8252e5 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -1282,10 +1282,10 @@ static auto RealToAPFloat(Context& context, RealId real_id, } // Performs a conversion between floating-point types, diagnosing if the value -// doesn't fit in the destination type. -static auto PerformCheckedFloatConvert(Context& context, SemIR::LocId loc_id, - SemIR::InstId arg_id, - SemIR::TypeId dest_type_id) +// doesn't fit in the destination type when check_overflow is true. +static auto PerformFloatConvert(Context& context, SemIR::LocId loc_id, + SemIR::InstId arg_id, + SemIR::TypeId dest_type_id, bool check_overflow) -> SemIR::ConstantId { auto dest_type_object_rep_id = context.types().GetObjectRepr(dest_type_id); CARBON_CHECK(dest_type_object_rep_id.has_value(), @@ -1316,7 +1316,7 @@ static auto PerformCheckedFloatConvert(Context& context, SemIR::LocId loc_id, llvm::APFloat result = RealToAPFloat(context, literal->real_id, dest_float_type->float_kind.Semantics(), &status); - if (status & llvm::APFloat::opOverflow) { + if (check_overflow && (status & llvm::APFloat::opOverflow)) { CARBON_DIAGNOSTIC(FloatLiteralTooLargeForType, Error, "value {0} too large for floating-point type {1}", RealId, SemIR::TypeId); @@ -1338,7 +1338,7 @@ static auto PerformCheckedFloatConvert(Context& context, SemIR::LocId loc_id, bool loses_info; auto status = result.convert(dest_float_type->float_kind.Semantics(), llvm::APFloat::rmNearestTiesToEven, &loses_info); - if (status & llvm::APFloat::opOverflow) { + if (check_overflow && (status & llvm::APFloat::opOverflow)) { CARBON_DIAGNOSTIC(FloatTooLargeForType, Error, "value {0} too large for floating-point type {1}", llvm::APFloat, SemIR::TypeId); @@ -2390,12 +2390,19 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, } // Floating-point conversions. + case SemIR::BuiltinFunctionKind::FloatConvert: { + if (phase != Phase::Concrete) { + return MakeConstantResult(context, call, phase); + } + return PerformFloatConvert(context, loc_id, arg_ids[0], call.type_id, + /*check_overflow=*/false); + } case SemIR::BuiltinFunctionKind::FloatConvertChecked: { if (phase != Phase::Concrete) { return MakeConstantResult(context, call, phase); } - return PerformCheckedFloatConvert(context, loc_id, arg_ids[0], - call.type_id); + return PerformFloatConvert(context, loc_id, arg_ids[0], call.type_id, + /*check_overflow=*/true); } case SemIR::BuiltinFunctionKind::FloatConvertInt: { if (phase != Phase::Concrete) { diff --git a/toolchain/check/testdata/builtins/float/convert.carbon b/toolchain/check/testdata/builtins/float/convert.carbon new file mode 100644 index 000000000000..cfc1ecbff741 --- /dev/null +++ b/toolchain/check/testdata/builtins/float/convert.carbon @@ -0,0 +1,657 @@ +// 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 +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/float/convert.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/float/convert.carbon + +// --- literal.carbon + +library "literal"; + +fn FloatLiteral() -> type = "float_literal.make_type"; + +fn FloatLiteralToFloatLiteral(a: FloatLiteral()) -> FloatLiteral() = + "float.convert"; + +// --- identity_literal.carbon + +library "identity_literal"; +import library "literal"; + +//@dump-sem-ir-begin +let f: FloatLiteral() = FloatLiteralToFloatLiteral(1.0); +//@dump-sem-ir-end + +// --- f64.carbon + +library "f64"; +export import library "literal"; + +fn Float64ToFloat64(a: f64) -> f64 = "float.convert"; +fn FloatLiteralToFloat64(a: FloatLiteral()) -> f64 = "float.convert"; + +// --- f32.carbon + +library "f32"; +export import library "literal"; + +fn Float32ToFloat32(a: f32) -> f32 = "float.convert"; +fn FloatLiteralToFloat32(a: FloatLiteral()) -> f32 = "float.convert"; + +fn Float32ToFloat64(a: f32) -> f64 = "float.convert"; +fn Float64ToFloat32(a: f64) -> f32 = "float.convert"; + +// --- literal_f64.carbon + +library "literal_f64"; +import library "f64"; + +//@dump-sem-ir-begin +let a: f64 = FloatLiteralToFloat64(0.0); +let b: f64 = FloatLiteralToFloat64(1.0); +let c: f64 = FloatLiteralToFloat64(1.0e308); +// Large value that overflows is allowed in unchecked convert (rounds to infinity) +let d: f64 = FloatLiteralToFloat64(1.0e309); +//@dump-sem-ir-end + +// --- literal_f32.carbon + +library "literal_f32"; +import library "f32"; + +//@dump-sem-ir-begin +let a: f32 = FloatLiteralToFloat32(0.0); +let b: f32 = FloatLiteralToFloat32(1.0); +let c: f32 = FloatLiteralToFloat32(1.0e38); +// Large value that overflows is allowed in unchecked convert (rounds to infinity) +let d: f32 = FloatLiteralToFloat32(1.0e39); +//@dump-sem-ir-end + +// --- identity_f64.carbon + +library "identity_f64"; +import library "f64"; + +//@dump-sem-ir-begin +let a: f64 = Float64ToFloat64(0.0); +let b: f64 = Float64ToFloat64(1.0); +let c: f64 = Float64ToFloat64(1.0e308); +//@dump-sem-ir-end + +// --- identity_f32.carbon + +library "identity_f32"; +import library "f32"; + +//@dump-sem-ir-begin +let a: f32 = Float32ToFloat32(0.0); +let b: f32 = Float32ToFloat32(1.0); +let c: f32 = Float32ToFloat32(1.0e38); +//@dump-sem-ir-end + +// --- truncate.carbon + +library "truncate"; +import library "f32"; +import library "f64"; + +//@dump-sem-ir-begin +let a: f32 = Float64ToFloat32(1.0); +// Narrowing with overflow is allowed in unchecked convert (rounds to infinity) +let b: f32 = Float64ToFloat32(1.0e39); +//@dump-sem-ir-end + +// --- extend.carbon + +library "extend"; +import library "f32"; +import library "f64"; + +//@dump-sem-ir-begin +let a: f64 = Float32ToFloat64(1.0); +let b: f64 = Float32ToFloat64(1.0e30); +//@dump-sem-ir-end + +// CHECK:STDOUT: --- identity_literal.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %FloatLiteral.type: type = fn_type @FloatLiteral [concrete] +// CHECK:STDOUT: %FloatLiteral: %FloatLiteral.type = struct_value () [concrete] +// CHECK:STDOUT: %pattern_type.dab: type = pattern_type Core.FloatLiteral [concrete] +// CHECK:STDOUT: %FloatLiteralToFloatLiteral.type: type = fn_type @FloatLiteralToFloatLiteral [concrete] +// CHECK:STDOUT: %FloatLiteralToFloatLiteral: %FloatLiteralToFloatLiteral.type = struct_value () [concrete] +// CHECK:STDOUT: %float: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.FloatLiteral: %FloatLiteral.type = import_ref Main//literal, FloatLiteral, loaded [concrete = constants.%FloatLiteral] +// CHECK:STDOUT: %Main.FloatLiteralToFloatLiteral: %FloatLiteralToFloatLiteral.type = import_ref Main//literal, FloatLiteralToFloatLiteral, loaded [concrete = constants.%FloatLiteralToFloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %f.patt: %pattern_type.dab = value_binding_pattern f [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc6_21.1: type = splice_block %.loc6_21.3 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %FloatLiteral.ref: %FloatLiteral.type = name_ref FloatLiteral, imports.%Main.FloatLiteral [concrete = constants.%FloatLiteral] +// CHECK:STDOUT: %FloatLiteral.call: init type = call %FloatLiteral.ref() [concrete = Core.FloatLiteral] +// CHECK:STDOUT: %.loc6_21.2: type = value_of_initializer %FloatLiteral.call [concrete = Core.FloatLiteral] +// CHECK:STDOUT: %.loc6_21.3: type = converted %FloatLiteral.call, %.loc6_21.2 [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc6_55.1: Core.FloatLiteral = value_of_initializer @__global_init.%FloatLiteralToFloatLiteral.call [concrete = constants.%float] +// CHECK:STDOUT: %.loc6_55.2: Core.FloatLiteral = converted @__global_init.%FloatLiteralToFloatLiteral.call, %.loc6_55.1 [concrete = constants.%float] +// CHECK:STDOUT: %f: Core.FloatLiteral = value_binding f, %.loc6_55.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %FloatLiteralToFloatLiteral.ref: %FloatLiteralToFloatLiteral.type = name_ref FloatLiteralToFloatLiteral, imports.%Main.FloatLiteralToFloatLiteral [concrete = constants.%FloatLiteralToFloatLiteral] +// CHECK:STDOUT: %float: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float] +// CHECK:STDOUT: %FloatLiteralToFloatLiteral.call: init Core.FloatLiteral = call %FloatLiteralToFloatLiteral.ref(%float) [concrete = constants.%float] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- literal_f64.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] +// CHECK:STDOUT: %f64.b55: type = class_type @Float, @Float(%int_64) [concrete] +// CHECK:STDOUT: %pattern_type.f3c: type = pattern_type %f64.b55 [concrete] +// CHECK:STDOUT: %FloatLiteralToFloat64.type: type = fn_type @FloatLiteralToFloat64 [concrete] +// CHECK:STDOUT: %FloatLiteralToFloat64: %FloatLiteralToFloat64.type = struct_value () [concrete] +// CHECK:STDOUT: %float.1f7: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %float.1af: %f64.b55 = float_value 0 [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %float.642: %f64.b55 = float_value 1 [concrete] +// CHECK:STDOUT: %float.12a: Core.FloatLiteral = float_literal_value 10e307 [concrete] +// CHECK:STDOUT: %float.3b9: %f64.b55 = float_value 1.0E+308 [concrete] +// CHECK:STDOUT: %float.82f: Core.FloatLiteral = float_literal_value 10e308 [concrete] +// CHECK:STDOUT: %float.f70: %f64.b55 = float_value +Inf [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.FloatLiteralToFloat64: %FloatLiteralToFloat64.type = import_ref Main//f64, FloatLiteralToFloat64, loaded [concrete = constants.%FloatLiteralToFloat64] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3c = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc6: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc6_39.1: %f64.b55 = value_of_initializer @__global_init.%FloatLiteralToFloat64.call.loc6 [concrete = constants.%float.1af] +// CHECK:STDOUT: %.loc6_39.2: %f64.b55 = converted @__global_init.%FloatLiteralToFloat64.call.loc6, %.loc6_39.1 [concrete = constants.%float.1af] +// CHECK:STDOUT: %a: %f64.b55 = value_binding a, %.loc6_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3c = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc7: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc7_39.1: %f64.b55 = value_of_initializer @__global_init.%FloatLiteralToFloat64.call.loc7 [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_39.2: %f64.b55 = converted @__global_init.%FloatLiteralToFloat64.call.loc7, %.loc7_39.1 [concrete = constants.%float.642] +// CHECK:STDOUT: %b: %f64.b55 = value_binding b, %.loc7_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.f3c = value_binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc8: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc8_43.1: %f64.b55 = value_of_initializer @__global_init.%FloatLiteralToFloat64.call.loc8 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %.loc8_43.2: %f64.b55 = converted @__global_init.%FloatLiteralToFloat64.call.loc8, %.loc8_43.1 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %c: %f64.b55 = value_binding c, %.loc8_43.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %d.patt: %pattern_type.f3c = value_binding_pattern d [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc10: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc10_43.1: %f64.b55 = value_of_initializer @__global_init.%FloatLiteralToFloat64.call.loc10 [concrete = constants.%float.f70] +// CHECK:STDOUT: %.loc10_43.2: %f64.b55 = converted @__global_init.%FloatLiteralToFloat64.call.loc10, %.loc10_43.1 [concrete = constants.%float.f70] +// CHECK:STDOUT: %d: %f64.b55 = value_binding d, %.loc10_43.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %FloatLiteralToFloat64.ref.loc6: %FloatLiteralToFloat64.type = name_ref FloatLiteralToFloat64, imports.%Main.FloatLiteralToFloat64 [concrete = constants.%FloatLiteralToFloat64] +// CHECK:STDOUT: %float.loc6: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f7] +// CHECK:STDOUT: %FloatLiteralToFloat64.call.loc6: init %f64.b55 = call %FloatLiteralToFloat64.ref.loc6(%float.loc6) [concrete = constants.%float.1af] +// CHECK:STDOUT: %FloatLiteralToFloat64.ref.loc7: %FloatLiteralToFloat64.type = name_ref FloatLiteralToFloat64, imports.%Main.FloatLiteralToFloat64 [concrete = constants.%FloatLiteralToFloat64] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %FloatLiteralToFloat64.call.loc7: init %f64.b55 = call %FloatLiteralToFloat64.ref.loc7(%float.loc7) [concrete = constants.%float.642] +// CHECK:STDOUT: %FloatLiteralToFloat64.ref.loc8: %FloatLiteralToFloat64.type = name_ref FloatLiteralToFloat64, imports.%Main.FloatLiteralToFloat64 [concrete = constants.%FloatLiteralToFloat64] +// CHECK:STDOUT: %float.loc8: Core.FloatLiteral = float_literal_value 10e307 [concrete = constants.%float.12a] +// CHECK:STDOUT: %FloatLiteralToFloat64.call.loc8: init %f64.b55 = call %FloatLiteralToFloat64.ref.loc8(%float.loc8) [concrete = constants.%float.3b9] +// CHECK:STDOUT: %FloatLiteralToFloat64.ref.loc10: %FloatLiteralToFloat64.type = name_ref FloatLiteralToFloat64, imports.%Main.FloatLiteralToFloat64 [concrete = constants.%FloatLiteralToFloat64] +// CHECK:STDOUT: %float.loc10: Core.FloatLiteral = float_literal_value 10e308 [concrete = constants.%float.82f] +// CHECK:STDOUT: %FloatLiteralToFloat64.call.loc10: init %f64.b55 = call %FloatLiteralToFloat64.ref.loc10(%float.loc10) [concrete = constants.%float.f70] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- literal_f32.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %f32.a26: type = class_type @Float, @Float(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.f3b: type = pattern_type %f32.a26 [concrete] +// CHECK:STDOUT: %FloatLiteralToFloat32.type: type = fn_type @FloatLiteralToFloat32 [concrete] +// CHECK:STDOUT: %FloatLiteralToFloat32: %FloatLiteralToFloat32.type = struct_value () [concrete] +// CHECK:STDOUT: %float.1f7: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %float.e89: %f32.a26 = float_value 0 [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %float.2ec: %f32.a26 = float_value 1 [concrete] +// CHECK:STDOUT: %float.8d2: Core.FloatLiteral = float_literal_value 10e37 [concrete] +// CHECK:STDOUT: %float.16a: %f32.a26 = float_value 9.99999968E+37 [concrete] +// CHECK:STDOUT: %float.cfc: Core.FloatLiteral = float_literal_value 10e38 [concrete] +// CHECK:STDOUT: %float.81c: %f32.a26 = float_value +Inf [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.FloatLiteralToFloat32: %FloatLiteralToFloat32.type = import_ref Main//f32, FloatLiteralToFloat32, loaded [concrete = constants.%FloatLiteralToFloat32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3b = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc6: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc6_39.1: %f32.a26 = value_of_initializer @__global_init.%FloatLiteralToFloat32.call.loc6 [concrete = constants.%float.e89] +// CHECK:STDOUT: %.loc6_39.2: %f32.a26 = converted @__global_init.%FloatLiteralToFloat32.call.loc6, %.loc6_39.1 [concrete = constants.%float.e89] +// CHECK:STDOUT: %a: %f32.a26 = value_binding a, %.loc6_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3b = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc7: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc7_39.1: %f32.a26 = value_of_initializer @__global_init.%FloatLiteralToFloat32.call.loc7 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_39.2: %f32.a26 = converted @__global_init.%FloatLiteralToFloat32.call.loc7, %.loc7_39.1 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %b: %f32.a26 = value_binding b, %.loc7_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.f3b = value_binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc8: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc8_42.1: %f32.a26 = value_of_initializer @__global_init.%FloatLiteralToFloat32.call.loc8 [concrete = constants.%float.16a] +// CHECK:STDOUT: %.loc8_42.2: %f32.a26 = converted @__global_init.%FloatLiteralToFloat32.call.loc8, %.loc8_42.1 [concrete = constants.%float.16a] +// CHECK:STDOUT: %c: %f32.a26 = value_binding c, %.loc8_42.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %d.patt: %pattern_type.f3b = value_binding_pattern d [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc10: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc10_42.1: %f32.a26 = value_of_initializer @__global_init.%FloatLiteralToFloat32.call.loc10 [concrete = constants.%float.81c] +// CHECK:STDOUT: %.loc10_42.2: %f32.a26 = converted @__global_init.%FloatLiteralToFloat32.call.loc10, %.loc10_42.1 [concrete = constants.%float.81c] +// CHECK:STDOUT: %d: %f32.a26 = value_binding d, %.loc10_42.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %FloatLiteralToFloat32.ref.loc6: %FloatLiteralToFloat32.type = name_ref FloatLiteralToFloat32, imports.%Main.FloatLiteralToFloat32 [concrete = constants.%FloatLiteralToFloat32] +// CHECK:STDOUT: %float.loc6: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f7] +// CHECK:STDOUT: %FloatLiteralToFloat32.call.loc6: init %f32.a26 = call %FloatLiteralToFloat32.ref.loc6(%float.loc6) [concrete = constants.%float.e89] +// CHECK:STDOUT: %FloatLiteralToFloat32.ref.loc7: %FloatLiteralToFloat32.type = name_ref FloatLiteralToFloat32, imports.%Main.FloatLiteralToFloat32 [concrete = constants.%FloatLiteralToFloat32] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %FloatLiteralToFloat32.call.loc7: init %f32.a26 = call %FloatLiteralToFloat32.ref.loc7(%float.loc7) [concrete = constants.%float.2ec] +// CHECK:STDOUT: %FloatLiteralToFloat32.ref.loc8: %FloatLiteralToFloat32.type = name_ref FloatLiteralToFloat32, imports.%Main.FloatLiteralToFloat32 [concrete = constants.%FloatLiteralToFloat32] +// CHECK:STDOUT: %float.loc8: Core.FloatLiteral = float_literal_value 10e37 [concrete = constants.%float.8d2] +// CHECK:STDOUT: %FloatLiteralToFloat32.call.loc8: init %f32.a26 = call %FloatLiteralToFloat32.ref.loc8(%float.loc8) [concrete = constants.%float.16a] +// CHECK:STDOUT: %FloatLiteralToFloat32.ref.loc10: %FloatLiteralToFloat32.type = name_ref FloatLiteralToFloat32, imports.%Main.FloatLiteralToFloat32 [concrete = constants.%FloatLiteralToFloat32] +// CHECK:STDOUT: %float.loc10: Core.FloatLiteral = float_literal_value 10e38 [concrete = constants.%float.cfc] +// CHECK:STDOUT: %FloatLiteralToFloat32.call.loc10: init %f32.a26 = call %FloatLiteralToFloat32.ref.loc10(%float.loc10) [concrete = constants.%float.81c] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- identity_f64.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] +// CHECK:STDOUT: %f64.b55: type = class_type @Float, @Float(%int_64) [concrete] +// CHECK:STDOUT: %pattern_type.f3c: type = pattern_type %f64.b55 [concrete] +// CHECK:STDOUT: %Float64ToFloat64.type: type = fn_type @Float64ToFloat64 [concrete] +// CHECK:STDOUT: %Float64ToFloat64: %Float64ToFloat64.type = struct_value () [concrete] +// CHECK:STDOUT: %float.1f7: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.857: type = facet_type <@ImplicitAs, @ImplicitAs(%f64.b55)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.539: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.83f: = impl_witness imports.%ImplicitAs.impl_witness_table, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5c5: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5c5 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.857 = facet_value Core.FloatLiteral, (%ImplicitAs.impl_witness.83f) [concrete] +// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.096: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%f64.b55, %ImplicitAs.facet) [concrete] +// CHECK:STDOUT: %.119: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.096, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.4d4: = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(%int_64) [concrete] +// CHECK:STDOUT: %bound_method.a29: = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.1af: %f64.b55 = float_value 0 [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.bef: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881 [concrete] +// CHECK:STDOUT: %bound_method.c5a: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.642: %f64.b55 = float_value 1 [concrete] +// CHECK:STDOUT: %float.12a: Core.FloatLiteral = float_literal_value 10e307 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.72f: = bound_method %float.12a, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881 [concrete] +// CHECK:STDOUT: %bound_method.b4f: = bound_method %float.12a, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.3b9: %f64.b55 = float_value 1.0E+308 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.Float64ToFloat64: %Float64ToFloat64.type = import_ref Main//f64, Float64ToFloat64, loaded [concrete = constants.%Float64ToFloat64] +// CHECK:STDOUT: %Core.import_ref.63c: @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type (%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6) = import_ref Core//prelude/parts/float, loc{{\d+_\d+}}, loaded [symbolic = @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert (constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.539)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table = impl_witness_table (%Core.import_ref.63c), @Core.FloatLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3c = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc6: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc6_34.1: %f64.b55 = value_of_initializer @__global_init.%Float64ToFloat64.call.loc6 [concrete = constants.%float.1af] +// CHECK:STDOUT: %.loc6_34.2: %f64.b55 = converted @__global_init.%Float64ToFloat64.call.loc6, %.loc6_34.1 [concrete = constants.%float.1af] +// CHECK:STDOUT: %a: %f64.b55 = value_binding a, %.loc6_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3c = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc7: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc7_34.1: %f64.b55 = value_of_initializer @__global_init.%Float64ToFloat64.call.loc7 [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_34.2: %f64.b55 = converted @__global_init.%Float64ToFloat64.call.loc7, %.loc7_34.1 [concrete = constants.%float.642] +// CHECK:STDOUT: %b: %f64.b55 = value_binding b, %.loc7_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.f3c = value_binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc8: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc8_38.1: %f64.b55 = value_of_initializer @__global_init.%Float64ToFloat64.call.loc8 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %.loc8_38.2: %f64.b55 = converted @__global_init.%Float64ToFloat64.call.loc8, %.loc8_38.1 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %c: %f64.b55 = value_binding c, %.loc8_38.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Float64ToFloat64.ref.loc6: %Float64ToFloat64.type = name_ref Float64ToFloat64, imports.%Main.Float64ToFloat64 [concrete = constants.%Float64ToFloat64] +// CHECK:STDOUT: %float.loc6: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f7] +// CHECK:STDOUT: %impl.elem0.loc6: %.119 = impl_witness_access constants.%ImplicitAs.impl_witness.83f, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.881] +// CHECK:STDOUT: %bound_method.loc6_31.1: = bound_method %float.loc6, %impl.elem0.loc6 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.4d4] +// CHECK:STDOUT: %specific_fn.loc6: = specific_function %impl.elem0.loc6, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc6_31.2: = bound_method %float.loc6, %specific_fn.loc6 [concrete = constants.%bound_method.a29] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc6: init %f64.b55 = call %bound_method.loc6_31.2(%float.loc6) [concrete = constants.%float.1af] +// CHECK:STDOUT: %.loc6_31.1: %f64.b55 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc6 [concrete = constants.%float.1af] +// CHECK:STDOUT: %.loc6_31.2: %f64.b55 = converted %float.loc6, %.loc6_31.1 [concrete = constants.%float.1af] +// CHECK:STDOUT: %Float64ToFloat64.call.loc6: init %f64.b55 = call %Float64ToFloat64.ref.loc6(%.loc6_31.2) [concrete = constants.%float.1af] +// CHECK:STDOUT: %Float64ToFloat64.ref.loc7: %Float64ToFloat64.type = name_ref Float64ToFloat64, imports.%Main.Float64ToFloat64 [concrete = constants.%Float64ToFloat64] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %impl.elem0.loc7: %.119 = impl_witness_access constants.%ImplicitAs.impl_witness.83f, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.881] +// CHECK:STDOUT: %bound_method.loc7_31.1: = bound_method %float.loc7, %impl.elem0.loc7 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.bef] +// CHECK:STDOUT: %specific_fn.loc7: = specific_function %impl.elem0.loc7, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_31.2: = bound_method %float.loc7, %specific_fn.loc7 [concrete = constants.%bound_method.c5a] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7: init %f64.b55 = call %bound_method.loc7_31.2(%float.loc7) [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_31.1: %f64.b55 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7 [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_31.2: %f64.b55 = converted %float.loc7, %.loc7_31.1 [concrete = constants.%float.642] +// CHECK:STDOUT: %Float64ToFloat64.call.loc7: init %f64.b55 = call %Float64ToFloat64.ref.loc7(%.loc7_31.2) [concrete = constants.%float.642] +// CHECK:STDOUT: %Float64ToFloat64.ref.loc8: %Float64ToFloat64.type = name_ref Float64ToFloat64, imports.%Main.Float64ToFloat64 [concrete = constants.%Float64ToFloat64] +// CHECK:STDOUT: %float.loc8: Core.FloatLiteral = float_literal_value 10e307 [concrete = constants.%float.12a] +// CHECK:STDOUT: %impl.elem0.loc8: %.119 = impl_witness_access constants.%ImplicitAs.impl_witness.83f, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.881] +// CHECK:STDOUT: %bound_method.loc8_31.1: = bound_method %float.loc8, %impl.elem0.loc8 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.72f] +// CHECK:STDOUT: %specific_fn.loc8: = specific_function %impl.elem0.loc8, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_31.2: = bound_method %float.loc8, %specific_fn.loc8 [concrete = constants.%bound_method.b4f] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8: init %f64.b55 = call %bound_method.loc8_31.2(%float.loc8) [concrete = constants.%float.3b9] +// CHECK:STDOUT: %.loc8_31.1: %f64.b55 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %.loc8_31.2: %f64.b55 = converted %float.loc8, %.loc8_31.1 [concrete = constants.%float.3b9] +// CHECK:STDOUT: %Float64ToFloat64.call.loc8: init %f64.b55 = call %Float64ToFloat64.ref.loc8(%.loc8_31.2) [concrete = constants.%float.3b9] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- identity_f32.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %f32.a26: type = class_type @Float, @Float(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.f3b: type = pattern_type %f32.a26 [concrete] +// CHECK:STDOUT: %Float32ToFloat32.type: type = fn_type @Float32ToFloat32 [concrete] +// CHECK:STDOUT: %Float32ToFloat32: %Float32ToFloat32.type = struct_value () [concrete] +// CHECK:STDOUT: %float.1f7: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.d0d: type = facet_type <@ImplicitAs, @ImplicitAs(%f32.a26)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.539: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.65d: = impl_witness imports.%ImplicitAs.impl_witness_table, @Core.FloatLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.f03: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.f03 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.d0d = facet_value Core.FloatLiteral, (%ImplicitAs.impl_witness.65d) [concrete] +// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.c87: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%f32.a26, %ImplicitAs.facet) [concrete] +// CHECK:STDOUT: %.3a8: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.c87, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.3a0: = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.7ae: = bound_method %float.1f7, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.e89: %f32.a26 = float_value 0 [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1ac: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd [concrete] +// CHECK:STDOUT: %bound_method.aaa: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.2ec: %f32.a26 = float_value 1 [concrete] +// CHECK:STDOUT: %float.8d2: Core.FloatLiteral = float_literal_value 10e37 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.f18: = bound_method %float.8d2, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd [concrete] +// CHECK:STDOUT: %bound_method.137: = bound_method %float.8d2, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.16a: %f32.a26 = float_value 9.99999968E+37 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.Float32ToFloat32: %Float32ToFloat32.type = import_ref Main//f32, Float32ToFloat32, loaded [concrete = constants.%Float32ToFloat32] +// CHECK:STDOUT: %Core.import_ref.63c: @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type (%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6) = import_ref Core//prelude/parts/float, loc{{\d+_\d+}}, loaded [symbolic = @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert (constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.539)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table = impl_witness_table (%Core.import_ref.63c), @Core.FloatLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3b = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc6: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc6_34.1: %f32.a26 = value_of_initializer @__global_init.%Float32ToFloat32.call.loc6 [concrete = constants.%float.e89] +// CHECK:STDOUT: %.loc6_34.2: %f32.a26 = converted @__global_init.%Float32ToFloat32.call.loc6, %.loc6_34.1 [concrete = constants.%float.e89] +// CHECK:STDOUT: %a: %f32.a26 = value_binding a, %.loc6_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3b = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc7: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc7_34.1: %f32.a26 = value_of_initializer @__global_init.%Float32ToFloat32.call.loc7 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_34.2: %f32.a26 = converted @__global_init.%Float32ToFloat32.call.loc7, %.loc7_34.1 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %b: %f32.a26 = value_binding b, %.loc7_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.f3b = value_binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc8: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc8_37.1: %f32.a26 = value_of_initializer @__global_init.%Float32ToFloat32.call.loc8 [concrete = constants.%float.16a] +// CHECK:STDOUT: %.loc8_37.2: %f32.a26 = converted @__global_init.%Float32ToFloat32.call.loc8, %.loc8_37.1 [concrete = constants.%float.16a] +// CHECK:STDOUT: %c: %f32.a26 = value_binding c, %.loc8_37.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Float32ToFloat32.ref.loc6: %Float32ToFloat32.type = name_ref Float32ToFloat32, imports.%Main.Float32ToFloat32 [concrete = constants.%Float32ToFloat32] +// CHECK:STDOUT: %float.loc6: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f7] +// CHECK:STDOUT: %impl.elem0.loc6: %.3a8 = impl_witness_access constants.%ImplicitAs.impl_witness.65d, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd] +// CHECK:STDOUT: %bound_method.loc6_31.1: = bound_method %float.loc6, %impl.elem0.loc6 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.3a0] +// CHECK:STDOUT: %specific_fn.loc6: = specific_function %impl.elem0.loc6, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc6_31.2: = bound_method %float.loc6, %specific_fn.loc6 [concrete = constants.%bound_method.7ae] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc6: init %f32.a26 = call %bound_method.loc6_31.2(%float.loc6) [concrete = constants.%float.e89] +// CHECK:STDOUT: %.loc6_31.1: %f32.a26 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc6 [concrete = constants.%float.e89] +// CHECK:STDOUT: %.loc6_31.2: %f32.a26 = converted %float.loc6, %.loc6_31.1 [concrete = constants.%float.e89] +// CHECK:STDOUT: %Float32ToFloat32.call.loc6: init %f32.a26 = call %Float32ToFloat32.ref.loc6(%.loc6_31.2) [concrete = constants.%float.e89] +// CHECK:STDOUT: %Float32ToFloat32.ref.loc7: %Float32ToFloat32.type = name_ref Float32ToFloat32, imports.%Main.Float32ToFloat32 [concrete = constants.%Float32ToFloat32] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %impl.elem0.loc7: %.3a8 = impl_witness_access constants.%ImplicitAs.impl_witness.65d, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd] +// CHECK:STDOUT: %bound_method.loc7_31.1: = bound_method %float.loc7, %impl.elem0.loc7 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1ac] +// CHECK:STDOUT: %specific_fn.loc7: = specific_function %impl.elem0.loc7, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_31.2: = bound_method %float.loc7, %specific_fn.loc7 [concrete = constants.%bound_method.aaa] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7: init %f32.a26 = call %bound_method.loc7_31.2(%float.loc7) [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_31.1: %f32.a26 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_31.2: %f32.a26 = converted %float.loc7, %.loc7_31.1 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %Float32ToFloat32.call.loc7: init %f32.a26 = call %Float32ToFloat32.ref.loc7(%.loc7_31.2) [concrete = constants.%float.2ec] +// CHECK:STDOUT: %Float32ToFloat32.ref.loc8: %Float32ToFloat32.type = name_ref Float32ToFloat32, imports.%Main.Float32ToFloat32 [concrete = constants.%Float32ToFloat32] +// CHECK:STDOUT: %float.loc8: Core.FloatLiteral = float_literal_value 10e37 [concrete = constants.%float.8d2] +// CHECK:STDOUT: %impl.elem0.loc8: %.3a8 = impl_witness_access constants.%ImplicitAs.impl_witness.65d, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd] +// CHECK:STDOUT: %bound_method.loc8_31.1: = bound_method %float.loc8, %impl.elem0.loc8 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.f18] +// CHECK:STDOUT: %specific_fn.loc8: = specific_function %impl.elem0.loc8, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_31.2: = bound_method %float.loc8, %specific_fn.loc8 [concrete = constants.%bound_method.137] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8: init %f32.a26 = call %bound_method.loc8_31.2(%float.loc8) [concrete = constants.%float.16a] +// CHECK:STDOUT: %.loc8_31.1: %f32.a26 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8 [concrete = constants.%float.16a] +// CHECK:STDOUT: %.loc8_31.2: %f32.a26 = converted %float.loc8, %.loc8_31.1 [concrete = constants.%float.16a] +// CHECK:STDOUT: %Float32ToFloat32.call.loc8: init %f32.a26 = call %Float32ToFloat32.ref.loc8(%.loc8_31.2) [concrete = constants.%float.16a] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- truncate.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %f32.a26: type = class_type @Float, @Float(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.f3b: type = pattern_type %f32.a26 [concrete] +// CHECK:STDOUT: %Float64ToFloat32.type: type = fn_type @Float64ToFloat32 [concrete] +// CHECK:STDOUT: %Float64ToFloat32: %Float64ToFloat32.type = struct_value () [concrete] +// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] +// CHECK:STDOUT: %f64.b55: type = class_type @Float, @Float(%int_64) [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.857: type = facet_type <@ImplicitAs, @ImplicitAs(%f64.b55)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.539: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.83f: = impl_witness imports.%ImplicitAs.impl_witness_table, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5c5: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5c5 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.857 = facet_value Core.FloatLiteral, (%ImplicitAs.impl_witness.83f) [concrete] +// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.096: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%f64.b55, %ImplicitAs.facet) [concrete] +// CHECK:STDOUT: %.119: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.096, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.bef: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(%int_64) [concrete] +// CHECK:STDOUT: %bound_method.c5a: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.642: %f64.b55 = float_value 1 [concrete] +// CHECK:STDOUT: %float.2ec: %f32.a26 = float_value 1 [concrete] +// CHECK:STDOUT: %float.cfc: Core.FloatLiteral = float_literal_value 10e38 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.af3: = bound_method %float.cfc, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.881 [concrete] +// CHECK:STDOUT: %bound_method.8d2: = bound_method %float.cfc, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.dae: %f64.b55 = float_value 9.9999999999999994E+38 [concrete] +// CHECK:STDOUT: %float.81c: %f32.a26 = float_value +Inf [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.Float64ToFloat32: %Float64ToFloat32.type = import_ref Main//f32, Float64ToFloat32, loaded [concrete = constants.%Float64ToFloat32] +// CHECK:STDOUT: %Core.import_ref.63c: @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type (%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6) = import_ref Core//prelude/parts/float, loc{{\d+_\d+}}, loaded [symbolic = @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert (constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.539)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table = impl_witness_table (%Core.import_ref.63c), @Core.FloatLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3b = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc7: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc7_34.1: %f32.a26 = value_of_initializer @__global_init.%Float64ToFloat32.call.loc7 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_34.2: %f32.a26 = converted @__global_init.%Float64ToFloat32.call.loc7, %.loc7_34.1 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %a: %f32.a26 = value_binding a, %.loc7_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3b = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f32.loc9: type = type_literal constants.%f32.a26 [concrete = constants.%f32.a26] +// CHECK:STDOUT: %.loc9_37.1: %f32.a26 = value_of_initializer @__global_init.%Float64ToFloat32.call.loc9 [concrete = constants.%float.81c] +// CHECK:STDOUT: %.loc9_37.2: %f32.a26 = converted @__global_init.%Float64ToFloat32.call.loc9, %.loc9_37.1 [concrete = constants.%float.81c] +// CHECK:STDOUT: %b: %f32.a26 = value_binding b, %.loc9_37.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Float64ToFloat32.ref.loc7: %Float64ToFloat32.type = name_ref Float64ToFloat32, imports.%Main.Float64ToFloat32 [concrete = constants.%Float64ToFloat32] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %impl.elem0.loc7: %.119 = impl_witness_access constants.%ImplicitAs.impl_witness.83f, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.881] +// CHECK:STDOUT: %bound_method.loc7_31.1: = bound_method %float.loc7, %impl.elem0.loc7 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.bef] +// CHECK:STDOUT: %specific_fn.loc7: = specific_function %impl.elem0.loc7, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_31.2: = bound_method %float.loc7, %specific_fn.loc7 [concrete = constants.%bound_method.c5a] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7: init %f64.b55 = call %bound_method.loc7_31.2(%float.loc7) [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_31.1: %f64.b55 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7 [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_31.2: %f64.b55 = converted %float.loc7, %.loc7_31.1 [concrete = constants.%float.642] +// CHECK:STDOUT: %Float64ToFloat32.call.loc7: init %f32.a26 = call %Float64ToFloat32.ref.loc7(%.loc7_31.2) [concrete = constants.%float.2ec] +// CHECK:STDOUT: %Float64ToFloat32.ref.loc9: %Float64ToFloat32.type = name_ref Float64ToFloat32, imports.%Main.Float64ToFloat32 [concrete = constants.%Float64ToFloat32] +// CHECK:STDOUT: %float.loc9: Core.FloatLiteral = float_literal_value 10e38 [concrete = constants.%float.cfc] +// CHECK:STDOUT: %impl.elem0.loc9: %.119 = impl_witness_access constants.%ImplicitAs.impl_witness.83f, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.881] +// CHECK:STDOUT: %bound_method.loc9_31.1: = bound_method %float.loc9, %impl.elem0.loc9 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.af3] +// CHECK:STDOUT: %specific_fn.loc9: = specific_function %impl.elem0.loc9, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc9_31.2: = bound_method %float.loc9, %specific_fn.loc9 [concrete = constants.%bound_method.8d2] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc9: init %f64.b55 = call %bound_method.loc9_31.2(%float.loc9) [concrete = constants.%float.dae] +// CHECK:STDOUT: %.loc9_31.1: %f64.b55 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc9 [concrete = constants.%float.dae] +// CHECK:STDOUT: %.loc9_31.2: %f64.b55 = converted %float.loc9, %.loc9_31.1 [concrete = constants.%float.dae] +// CHECK:STDOUT: %Float64ToFloat32.call.loc9: init %f32.a26 = call %Float64ToFloat32.ref.loc9(%.loc9_31.2) [concrete = constants.%float.81c] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- extend.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] +// CHECK:STDOUT: %f64.b55: type = class_type @Float, @Float(%int_64) [concrete] +// CHECK:STDOUT: %pattern_type.f3c: type = pattern_type %f64.b55 [concrete] +// CHECK:STDOUT: %Float32ToFloat64.type: type = fn_type @Float32ToFloat64 [concrete] +// CHECK:STDOUT: %Float32ToFloat64: %Float32ToFloat64.type = struct_value () [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %f32.a26: type = class_type @Float, @Float(%int_32) [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.d0d: type = facet_type <@ImplicitAs, @ImplicitAs(%f32.a26)> [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.539: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.65d: = impl_witness imports.%ImplicitAs.impl_witness_table, @Core.FloatLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.f03: type = fn_type @Core.FloatLiteral.as.ImplicitAs.impl.Convert, @Core.FloatLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.f03 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.d0d = facet_value Core.FloatLiteral, (%ImplicitAs.impl_witness.65d) [concrete] +// CHECK:STDOUT: %ImplicitAs.WithSelf.Convert.type.c87: type = fn_type @ImplicitAs.WithSelf.Convert, @ImplicitAs.WithSelf(%f32.a26, %ImplicitAs.facet) [concrete] +// CHECK:STDOUT: %.3a8: type = fn_type_with_self_type %ImplicitAs.WithSelf.Convert.type.c87, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1ac: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.aaa: = bound_method %float.6da, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.2ec: %f32.a26 = float_value 1 [concrete] +// CHECK:STDOUT: %float.642: %f64.b55 = float_value 1 [concrete] +// CHECK:STDOUT: %float.c02: Core.FloatLiteral = float_literal_value 10e29 [concrete] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1c5: = bound_method %float.c02, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd [concrete] +// CHECK:STDOUT: %bound_method.dc8: = bound_method %float.c02, %Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %float.419: %f32.a26 = float_value 1.00000002E+30 [concrete] +// CHECK:STDOUT: %float.e6a: %f64.b55 = float_value 1.0000000150474662E+30 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.Float32ToFloat64: %Float32ToFloat64.type = import_ref Main//f32, Float32ToFloat64, loaded [concrete = constants.%Float32ToFloat64] +// CHECK:STDOUT: %Core.import_ref.63c: @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type (%Core.FloatLiteral.as.ImplicitAs.impl.Convert.type.5e6) = import_ref Core//prelude/parts/float, loc{{\d+_\d+}}, loaded [symbolic = @Core.FloatLiteral.as.ImplicitAs.impl.%Core.FloatLiteral.as.ImplicitAs.impl.Convert (constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.539)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table = impl_witness_table (%Core.import_ref.63c), @Core.FloatLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %a.patt: %pattern_type.f3c = value_binding_pattern a [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc7: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc7_34.1: %f64.b55 = value_of_initializer @__global_init.%Float32ToFloat64.call.loc7 [concrete = constants.%float.642] +// CHECK:STDOUT: %.loc7_34.2: %f64.b55 = converted @__global_init.%Float32ToFloat64.call.loc7, %.loc7_34.1 [concrete = constants.%float.642] +// CHECK:STDOUT: %a: %f64.b55 = value_binding a, %.loc7_34.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %b.patt: %pattern_type.f3c = value_binding_pattern b [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %f64.loc8: type = type_literal constants.%f64.b55 [concrete = constants.%f64.b55] +// CHECK:STDOUT: %.loc8_37.1: %f64.b55 = value_of_initializer @__global_init.%Float32ToFloat64.call.loc8 [concrete = constants.%float.e6a] +// CHECK:STDOUT: %.loc8_37.2: %f64.b55 = converted @__global_init.%Float32ToFloat64.call.loc8, %.loc8_37.1 [concrete = constants.%float.e6a] +// CHECK:STDOUT: %b: %f64.b55 = value_binding b, %.loc8_37.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Float32ToFloat64.ref.loc7: %Float32ToFloat64.type = name_ref Float32ToFloat64, imports.%Main.Float32ToFloat64 [concrete = constants.%Float32ToFloat64] +// CHECK:STDOUT: %float.loc7: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %impl.elem0.loc7: %.3a8 = impl_witness_access constants.%ImplicitAs.impl_witness.65d, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd] +// CHECK:STDOUT: %bound_method.loc7_31.1: = bound_method %float.loc7, %impl.elem0.loc7 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1ac] +// CHECK:STDOUT: %specific_fn.loc7: = specific_function %impl.elem0.loc7, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc7_31.2: = bound_method %float.loc7, %specific_fn.loc7 [concrete = constants.%bound_method.aaa] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7: init %f32.a26 = call %bound_method.loc7_31.2(%float.loc7) [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_31.1: %f32.a26 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc7 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %.loc7_31.2: %f32.a26 = converted %float.loc7, %.loc7_31.1 [concrete = constants.%float.2ec] +// CHECK:STDOUT: %Float32ToFloat64.call.loc7: init %f64.b55 = call %Float32ToFloat64.ref.loc7(%.loc7_31.2) [concrete = constants.%float.642] +// CHECK:STDOUT: %Float32ToFloat64.ref.loc8: %Float32ToFloat64.type = name_ref Float32ToFloat64, imports.%Main.Float32ToFloat64 [concrete = constants.%Float32ToFloat64] +// CHECK:STDOUT: %float.loc8: Core.FloatLiteral = float_literal_value 10e29 [concrete = constants.%float.c02] +// CHECK:STDOUT: %impl.elem0.loc8: %.3a8 = impl_witness_access constants.%ImplicitAs.impl_witness.65d, element0 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.2cd] +// CHECK:STDOUT: %bound_method.loc8_31.1: = bound_method %float.loc8, %impl.elem0.loc8 [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.bound.1c5] +// CHECK:STDOUT: %specific_fn.loc8: = specific_function %impl.elem0.loc8, @Core.FloatLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.FloatLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_31.2: = bound_method %float.loc8, %specific_fn.loc8 [concrete = constants.%bound_method.dc8] +// CHECK:STDOUT: %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8: init %f32.a26 = call %bound_method.loc8_31.2(%float.loc8) [concrete = constants.%float.419] +// CHECK:STDOUT: %.loc8_31.1: %f32.a26 = value_of_initializer %Core.FloatLiteral.as.ImplicitAs.impl.Convert.call.loc8 [concrete = constants.%float.419] +// CHECK:STDOUT: %.loc8_31.2: %f32.a26 = converted %float.loc8, %.loc8_31.1 [concrete = constants.%float.419] +// CHECK:STDOUT: %Float32ToFloat64.call.loc8: init %f64.b55 = call %Float32ToFloat64.ref.loc8(%.loc8_31.2) [concrete = constants.%float.e6a] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon b/toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon new file mode 100644 index 000000000000..cb3e365b467b --- /dev/null +++ b/toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon @@ -0,0 +1,61 @@ +// 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 +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/custom_witness/float_fits_in.carbon + +// --- core.carbon + +package Core; + +interface FloatFitsIn(Dest:! type) {} + +fn CheckFitsIn[U:! type, T:! FloatFitsIn(U)](unused t: T, unused u: U) {} + +// --- valid.carbon + +library "[[@TEST_NAME]]"; + +import Core; + +fn CheckSameSize() { + Core.CheckFitsIn(1.0 as f32, 2.0 as f32); + Core.CheckFitsIn(1.0 as f64, 2.0 as f64); +} + +fn CheckOk() { + Core.CheckFitsIn(1.0 as f16, 2.0 as f32); + Core.CheckFitsIn(1.0 as f16, 2.0 as f64); + Core.CheckFitsIn(1.0 as f32, 2.0 as f64); +} + +// --- fail_narrowing.carbon + +library "[[@TEST_NAME]]"; + +import Core; + +fn CheckFail() { + // CHECK:STDERR: fail_narrowing.carbon:[[@LINE+7]]:3: error: cannot convert type `f64` into type implementing `Core.FloatFitsIn(f32)` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Core.CheckFitsIn(1.0 as f64, 2.0 as f32); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: core.carbon:6:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn CheckFitsIn[U:! type, T:! FloatFitsIn(U)](unused t: T, unused u: U) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Core.CheckFitsIn(1.0 as f64, 2.0 as f32); + // CHECK:STDERR: fail_narrowing.carbon:[[@LINE+7]]:3: error: cannot convert type `f32` into type implementing `Core.FloatFitsIn(f16)` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Core.CheckFitsIn(1.0 as f32, 2.0 as f16); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: core.carbon:6:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn CheckFitsIn[U:! type, T:! FloatFitsIn(U)](unused t: T, unused u: U) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Core.CheckFitsIn(1.0 as f32, 2.0 as f16); +} diff --git a/toolchain/check/testdata/impl/custom_witness/int_fits_in.carbon b/toolchain/check/testdata/impl/custom_witness/int_fits_in.carbon index 5e4fd3d973ca..92614ea7d624 100644 --- a/toolchain/check/testdata/impl/custom_witness/int_fits_in.carbon +++ b/toolchain/check/testdata/impl/custom_witness/int_fits_in.carbon @@ -24,6 +24,11 @@ library "[[@TEST_NAME]]"; import Core; +fn CheckSameSize() { + Core.CheckFitsIn(1 as i32, 2 as i32); + Core.CheckFitsIn(1 as u32, 2 as u32); +} + fn CheckOk() { Core.CheckFitsIn(1 as i32, 2 as i64); Core.CheckFitsIn(1 as u32, 2 as u64); diff --git a/toolchain/check/testdata/primitives/float_conversions.carbon b/toolchain/check/testdata/primitives/float_conversions.carbon index aa9aa0080ff2..6493c4904377 100644 --- a/toolchain/check/testdata/primitives/float_conversions.carbon +++ b/toolchain/check/testdata/primitives/float_conversions.carbon @@ -111,3 +111,34 @@ fn F(f: f32) { // CHECK:STDERR: let _: i32 = f as i32; } + +// --- float_to_float.carbon +library "[[@TEST_NAME]]"; + +import library "test_helpers"; + +fn F(x: f32) { + // Implicit conversion (widening f32 -> f64) + let y: f64 = x; + + // Explicit conversion (widening f32 -> f64) + let _: f64 = x as f64; + + // Explicit conversion (narrowing f64 -> f32) + let _: f32 = y as f32; +} + +// --- fail_float_to_float_narrowing.carbon +library "[[@TEST_NAME]]"; + +fn F(x: f64) { + // Implicit narrowing conversion (f64 -> f32) is not permitted. + // CHECK:STDERR: fail_float_to_float_narrowing.carbon:[[@LINE+7]]:16: error: cannot implicitly convert expression of type `f64` to `f32` [ConversionFailure] + // CHECK:STDERR: let _: f32 = x; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_float_to_float_narrowing.carbon:[[@LINE+4]]:16: note: type `f64` does not implement interface `Core.ImplicitAs(f32)` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: let _: f32 = x; + // CHECK:STDERR: ^ + // CHECK:STDERR: + let _: f32 = x; +} diff --git a/toolchain/lower/handle_call.cpp b/toolchain/lower/handle_call.cpp index f5fd2255cb1a..e00178dac509 100644 --- a/toolchain/lower/handle_call.cpp +++ b/toolchain/lower/handle_call.cpp @@ -441,6 +441,13 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, : context.builder().CreateUIToFP(operand, dest_type)); return; } + case SemIR::BuiltinFunctionKind::FloatConvert: { + auto* operand = context.GetValue(arg_ids[0]); + auto* dest_type = context.GetTypeOfInst(inst_id); + context.SetLocal(inst_id, + context.builder().CreateFPCast(operand, dest_type)); + return; + } case SemIR::BuiltinFunctionKind::FloatConvertInt: { auto* operand = context.GetValue(arg_ids[0]); auto* dest_type = context.GetTypeOfInst(inst_id); diff --git a/toolchain/lower/testdata/builtins/float_to_float.carbon b/toolchain/lower/testdata/builtins/float_to_float.carbon new file mode 100644 index 000000000000..2b8814e1ce58 --- /dev/null +++ b/toolchain/lower/testdata/builtins/float_to_float.carbon @@ -0,0 +1,75 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/builtins/float_to_float.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/builtins/float_to_float.carbon + +// --- float_to_float.carbon +library "[[@TEST_NAME]]"; + +fn ConvertF32ToF64(a: f32) -> f64 = "float.convert"; +fn TestConvertF32ToF64(a: f32) -> f64 { return ConvertF32ToF64(a); } + +fn ConvertF64ToF32(a: f64) -> f32 = "float.convert"; +fn TestConvertF64ToF32(a: f64) -> f32 { return ConvertF64ToF32(a); } + +fn ConvertF16ToF128(a: f16) -> f128 = "float.convert"; +fn TestConvertF16ToF128(a: f16) -> f128 { return ConvertF16ToF128(a); } + +// CHECK:STDOUT: ; ModuleID = 'float_to_float.carbon' +// CHECK:STDOUT: source_filename = "float_to_float.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define double @_CTestConvertF32ToF64.Main(float %a) #0 !dbg !4 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %ConvertF32ToF64.call = fpext float %a to double, !dbg !10 +// CHECK:STDOUT: ret double %ConvertF32ToF64.call, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define float @_CTestConvertF64ToF32.Main(double %a) #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %ConvertF64ToF32.call = fptrunc double %a to float, !dbg !15 +// CHECK:STDOUT: ret float %ConvertF64ToF32.call, !dbg !16 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define fp128 @_CTestConvertF16ToF128.Main(half %a) #0 !dbg !17 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %ConvertF16ToF128.call = fpext half %a to fp128, !dbg !20 +// CHECK:STDOUT: ret fp128 %ConvertF16ToF128.call, !dbg !21 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} +// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !3 = !DIFile(filename: "float_to_float.carbon", directory: "") +// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "TestConvertF32ToF64", linkageName: "_CTestConvertF32ToF64.Main", scope: null, file: !3, line: 4, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !8) +// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !6 = !{!7, !7} +// CHECK:STDOUT: !7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !8 = !{!9} +// CHECK:STDOUT: !9 = !DILocalVariable(arg: 1, scope: !4, type: !7) +// CHECK:STDOUT: !10 = !DILocation(line: 4, column: 48, scope: !4) +// CHECK:STDOUT: !11 = !DILocation(line: 4, column: 41, scope: !4) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "TestConvertF64ToF32", linkageName: "_CTestConvertF64ToF32.Main", scope: null, file: !3, line: 7, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !13) +// CHECK:STDOUT: !13 = !{!14} +// CHECK:STDOUT: !14 = !DILocalVariable(arg: 1, scope: !12, type: !7) +// CHECK:STDOUT: !15 = !DILocation(line: 7, column: 48, scope: !12) +// CHECK:STDOUT: !16 = !DILocation(line: 7, column: 41, scope: !12) +// CHECK:STDOUT: !17 = distinct !DISubprogram(name: "TestConvertF16ToF128", linkageName: "_CTestConvertF16ToF128.Main", scope: null, file: !3, line: 10, type: !5, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18) +// CHECK:STDOUT: !18 = !{!19} +// CHECK:STDOUT: !19 = !DILocalVariable(arg: 1, scope: !17, type: !7) +// CHECK:STDOUT: !20 = !DILocation(line: 10, column: 50, scope: !17) +// CHECK:STDOUT: !21 = !DILocation(line: 10, column: 43, scope: !17) diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index e641b8213b6c..b1bd7979d756 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -702,6 +702,10 @@ constexpr BuiltinInfo FloatDivAssign = { "float.div_assign", ValidateSignature, SizedFloatT)->NoReturn>}; +// Converts between floating-point types, without checking. +constexpr BuiltinInfo FloatConvert = {"float.convert", + ValidateSignatureFloatU>}; + // Converts between floating-point types, with a diagnostic if the value doesn't // fit. constexpr BuiltinInfo FloatConvertChecked = { @@ -859,6 +863,7 @@ auto BuiltinFunctionKind::IsCompTimeOnly(const File& sem_ir, // Checked conversions are compile-time only. return true; + case FloatConvert: case FloatConvertInt: case IntConvert: case IntConvertChar: diff --git a/toolchain/sem_ir/builtin_function_kind.def b/toolchain/sem_ir/builtin_function_kind.def index 01dfc0487e37..4ff7fd588ff9 100644 --- a/toolchain/sem_ir/builtin_function_kind.def +++ b/toolchain/sem_ir/builtin_function_kind.def @@ -117,6 +117,7 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatMulAssign) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatDivAssign) // Float conversion. +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatConvert) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatConvertChecked) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatConvertInt) diff --git a/toolchain/sem_ir/core_interface_kind.def b/toolchain/sem_ir/core_interface_kind.def index 64ea86a03717..71d91898e610 100644 --- a/toolchain/sem_ir/core_interface_kind.def +++ b/toolchain/sem_ir/core_interface_kind.def @@ -24,6 +24,7 @@ CARBON_SEM_IR_CORE_INTERFACE_KIND(CppUnsafeDeref) CARBON_SEM_IR_CORE_INTERFACE_KIND(Dec) CARBON_SEM_IR_CORE_INTERFACE_KIND(Default) CARBON_SEM_IR_CORE_INTERFACE_KIND(Destroy) +CARBON_SEM_IR_CORE_INTERFACE_KIND(FloatFitsIn) CARBON_SEM_IR_CORE_INTERFACE_KIND(DivAssignWith) CARBON_SEM_IR_CORE_INTERFACE_KIND(DivWith) CARBON_SEM_IR_CORE_INTERFACE_KIND(EqWith)