diff --git a/core/prelude/operators/arithmetic.carbon b/core/prelude/operators/arithmetic.carbon index b3f2d93cc1ae..2e07af4cb2e6 100644 --- a/core/prelude/operators/arithmetic.carbon +++ b/core/prelude/operators/arithmetic.carbon @@ -6,6 +6,7 @@ package Core library "prelude/operators/arithmetic"; import library "prelude/types/char_literal"; import library "prelude/types/int_literal"; +import library "prelude/types/float_literal"; // TODO: Per the design, the associated type `Result` in each of these // interfaces should have a default value of `Self`: @@ -120,7 +121,6 @@ impl IntLiteral as SubWith(Self) where .Result = Self { // Operations for CharLiteral. These need to be here because CharLiteral has no // associated library of its own. - impl CharLiteral as AddWith(IntLiteral) where .Result = CharLiteral { fn Op(self, other: IntLiteral) -> CharLiteral = "char_literal.add"; } @@ -136,3 +136,10 @@ impl CharLiteral as SubWith(IntLiteral) where .Result = CharLiteral { impl CharLiteral as SubWith(Self) where .Result = IntLiteral { fn Op(self, other: Self) -> IntLiteral = "char_literal.sub_char"; } + + +// Operations for FloatLiteral. These need to be here because FloatLiteral has no +// associated library of its own. +impl FloatLiteral as Negate where .Result = Self { + fn Op(self) -> Self = "float.negate"; +} diff --git a/toolchain/base/value_ids.h b/toolchain/base/value_ids.h index 37369218cf16..38338f7ff7d7 100644 --- a/toolchain/base/value_ids.h +++ b/toolchain/base/value_ids.h @@ -25,11 +25,11 @@ namespace Carbon { // TODO: Address this by using a different representation in SemIR. struct Real : public Printable { auto Print(llvm::raw_ostream& output_stream) const -> void { - mantissa.print(output_stream, /*isSigned=*/false); + mantissa.print(output_stream, /*isSigned=*/true); output_stream << "*" << (is_decimal ? "10" : "2") << "^" << exponent; } - // The mantissa, represented as an unsigned integer. + // The mantissa, represented as a signed integer. llvm::APInt mantissa; // The exponent, represented as a signed integer. diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 566d08059c21..9919ccbbcba9 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -431,6 +431,19 @@ static auto MakeIntResult(Context& context, SemIR::TypeId type_id, return MakeIntResult(context, type_id, result); } +// Converts a Real into a ConstantId. +static auto MakeFloatLiteralResult(Context& context, Real real) + -> SemIR::ConstantId { + auto real_id = context.reals().Add(real); + return MakeConstantResult( + context, + SemIR::FloatLiteralValue{ + .type_id = + GetSingletonType(context, SemIR::FloatLiteralType::TypeInstId), + .real_id = real_id}, + Phase::Concrete); +} + // Converts an APFloat value into a ConstantId. static auto MakeFloatResult(Context& context, SemIR::TypeId type_id, llvm::APFloat value) -> SemIR::ConstantId { @@ -1438,7 +1451,7 @@ static auto RealToAPFloat(Context& context, RealId real_id, // Convert the real value to a string. llvm::SmallString<64> str; real_value.mantissa.toString(str, real_value.is_decimal ? 10 : 16, - /*signed=*/false, /*formatAsCLiteral=*/true); + /*signed=*/true, /*formatAsCLiteral=*/true); str += real_value.is_decimal ? "e" : "p"; real_value.exponent.toStringSigned(str); @@ -1550,20 +1563,10 @@ static auto PerformIntToFloatConvert(Context& context, SemIR::LocId loc_id, if (!dest_float_type) { // Target is Core.FloatLiteral, which is always exact. llvm::APInt mantissa = op_val; - if (src_is_signed && op_val.isNegative()) { - // FloatLiteral can only represent positive real values. Negative - // literals are parsed as Negate(FloatLiteralValue). - context.TODO(loc_id, "negative float literal conversion"); - return SemIR::ErrorInst::ConstantId; - } - auto real_id = context.reals().Add( - Real{.mantissa = mantissa, - .exponent = llvm::APInt(32, 0, /*isSigned=*/true), - .is_decimal = true}); - return MakeConstantResult( - context, - SemIR::FloatLiteralValue{.type_id = dest_type_id, .real_id = real_id}, - Phase::Concrete); + return MakeFloatLiteralResult( + context, Real{.mantissa = mantissa, + .exponent = llvm::APInt(32, 0, /*isSigned=*/true), + .is_decimal = true}); } llvm::APFloat ap_float(dest_float_type->float_kind.Semantics()); @@ -1702,19 +1705,19 @@ static auto ConvertRealLiteralToInt(Context& context, SemIR::LocId loc_id, // If the exponent is positive, base^exponent cannot be larger than the result // size. If it's negative, base^exponent can't be *much* larger than the // mantissa or we'd have computed a lower bound of 0 bits and bailed out. - CARBON_CHECK( - exponent_upper_bound <= - std::max(mantissa.getActiveBits() * 2, bounds.upper_bound)); + CARBON_CHECK(exponent_upper_bound <= + std::max(mantissa.getSignificantBits() * 2, + bounds.upper_bound)); // Compute a bit-width in which we can safely compute the result. We need // enough space to store the mantissa, base^exponent, the result and a sign // bit, and the number 10 (4 bits). unsigned calc_width = - std::max({mantissa.getActiveBits(), exponent_upper_bound, + std::max({mantissa.getSignificantBits(), exponent_upper_bound, static_cast(bounds.upper_bound + 1), 4U}); // Compute the integer result. - llvm::APInt integer_val = mantissa.zextOrTrunc(calc_width); + llvm::APInt integer_val = mantissa.sextOrTrunc(calc_width); if (!real_val.is_decimal) { // Binary exponent (mantissa * 2^exponent). if (!exponent.isNegative()) { @@ -2178,16 +2181,27 @@ static auto PerformBuiltinUnaryFloatOp(Context& context, SemIR::BuiltinFunctionKind builtin_kind, SemIR::InstId arg_id) -> SemIR::ConstantId { + CARBON_CHECK(builtin_kind == SemIR::BuiltinFunctionKind::FloatNegate, + "Unexpected builtin kind"); + + if (auto literal = + context.insts().TryGetAs(arg_id)) { + auto real_val = context.reals().Get(literal->real_id); + + // Check if negation would overflow. + if (real_val.mantissa.isMinSignedValue()) { + real_val.mantissa = + real_val.mantissa.sext(real_val.mantissa.getBitWidth() + 1); + } + real_val.mantissa.negate(); + + return MakeFloatLiteralResult(context, std::move(real_val)); + } + 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"); - } + op_val.changeSign(); return MakeFloatResult(context, op.type_id, std::move(op_val)); } diff --git a/toolchain/check/testdata/builtins/float_literal/negate.carbon b/toolchain/check/testdata/builtins/float_literal/negate.carbon new file mode 100644 index 000000000000..0dcde48eda3f --- /dev/null +++ b/toolchain/check/testdata/builtins/float_literal/negate.carbon @@ -0,0 +1,166 @@ +// 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_literal/negate.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/float_literal/negate.carbon + +library "[[@TEST_NAME]]"; + +fn Negate(a: Core.FloatLiteral) -> Core.FloatLiteral = "float.negate"; + +//@dump-sem-ir-begin +// Positive values become negative +let v1: Core.FloatLiteral = Negate(1.0); +let v2: Core.FloatLiteral = Negate(1.8e9); + +// Negative values become positive +let v3: Core.FloatLiteral = Negate(Negate(87.87)); +let v4: Core.FloatLiteral = Negate(Negate(0x1.8p1)); + +// Zero is still zero +let v5: Core.FloatLiteral = Negate(0.0); +let v6: Core.FloatLiteral = Negate(Negate(0.0)); +//@dump-sem-ir-end + +// CHECK:STDOUT: --- negate.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %pattern_type: type = pattern_type Core.FloatLiteral [concrete] +// CHECK:STDOUT: %Negate.type: type = fn_type @Negate [concrete] +// CHECK:STDOUT: %Negate: %Negate.type = struct_value () [concrete] +// CHECK:STDOUT: %v1.patt: %pattern_type = value_binding_pattern v1 [concrete] +// CHECK:STDOUT: %float.6da: Core.FloatLiteral = float_literal_value 10e-1 [concrete] +// CHECK:STDOUT: %float.84a: Core.FloatLiteral = float_literal_value -10e-1 [concrete] +// CHECK:STDOUT: %v2.patt: %pattern_type = value_binding_pattern v2 [concrete] +// CHECK:STDOUT: %float.c59: Core.FloatLiteral = float_literal_value 18e8 [concrete] +// CHECK:STDOUT: %float.838: Core.FloatLiteral = float_literal_value -18e8 [concrete] +// CHECK:STDOUT: %v3.patt: %pattern_type = value_binding_pattern v3 [concrete] +// CHECK:STDOUT: %float.b21268.1: Core.FloatLiteral = float_literal_value 8787e-2 [concrete] +// CHECK:STDOUT: %float.923: Core.FloatLiteral = float_literal_value -8787e-2 [concrete] +// CHECK:STDOUT: %float.b21268.2: Core.FloatLiteral = float_literal_value 8787e-2 [concrete] +// CHECK:STDOUT: %v4.patt: %pattern_type = value_binding_pattern v4 [concrete] +// CHECK:STDOUT: %float.eda197.1: Core.FloatLiteral = float_literal_value 24p-3 [concrete] +// CHECK:STDOUT: %float.0b3: Core.FloatLiteral = float_literal_value -24p-3 [concrete] +// CHECK:STDOUT: %float.eda197.2: Core.FloatLiteral = float_literal_value 24p-3 [concrete] +// CHECK:STDOUT: %v5.patt: %pattern_type = value_binding_pattern v5 [concrete] +// CHECK:STDOUT: %float.1f75e4.1: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %float.1f75e4.2: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %v6.patt: %pattern_type = value_binding_pattern v6 [concrete] +// CHECK:STDOUT: %float.1f75e4.3: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %float.1f75e4.4: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: %float.1f75e4.5: Core.FloatLiteral = float_literal_value 0e-1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .FloatLiteral = %Core.FloatLiteral +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.FloatLiteral: type = import_ref Core//prelude/parts/float_literal, FloatLiteral, loaded [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %.loc19_39.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc19 [concrete = constants.%float.84a] +// CHECK:STDOUT: %.loc19_39.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc19, %.loc19_39.1 [concrete = constants.%float.84a] +// CHECK:STDOUT: %.loc19_13: type = splice_block %FloatLiteral.ref.loc19 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc19: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc19: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v1: Core.FloatLiteral = wrapper_binding v1, %.loc19_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v1.patt: %pattern_type = value_binding_pattern v1 [concrete = constants.%v1.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc20_41.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc20 [concrete = constants.%float.838] +// CHECK:STDOUT: %.loc20_41.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc20, %.loc20_41.1 [concrete = constants.%float.838] +// CHECK:STDOUT: %.loc20_13: type = splice_block %FloatLiteral.ref.loc20 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc20: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc20: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v2: Core.FloatLiteral = wrapper_binding v2, %.loc20_41.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v2.patt: %pattern_type = value_binding_pattern v2 [concrete = constants.%v2.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc23_49.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc23_49 [concrete = constants.%float.b21268.2] +// CHECK:STDOUT: %.loc23_49.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc23_49, %.loc23_49.1 [concrete = constants.%float.b21268.2] +// CHECK:STDOUT: %.loc23_13: type = splice_block %FloatLiteral.ref.loc23 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc23: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc23: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v3: Core.FloatLiteral = wrapper_binding v3, %.loc23_49.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v3.patt: %pattern_type = value_binding_pattern v3 [concrete = constants.%v3.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc24_51.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc24_51 [concrete = constants.%float.eda197.2] +// CHECK:STDOUT: %.loc24_51.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc24_51, %.loc24_51.1 [concrete = constants.%float.eda197.2] +// CHECK:STDOUT: %.loc24_13: type = splice_block %FloatLiteral.ref.loc24 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc24: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc24: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v4: Core.FloatLiteral = wrapper_binding v4, %.loc24_51.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v4.patt: %pattern_type = value_binding_pattern v4 [concrete = constants.%v4.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc27_39.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc27 [concrete = constants.%float.1f75e4.2] +// CHECK:STDOUT: %.loc27_39.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc27, %.loc27_39.1 [concrete = constants.%float.1f75e4.2] +// CHECK:STDOUT: %.loc27_13: type = splice_block %FloatLiteral.ref.loc27 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc27: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc27: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v5: Core.FloatLiteral = wrapper_binding v5, %.loc27_39.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v5.patt: %pattern_type = value_binding_pattern v5 [concrete = constants.%v5.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc28_47.1: Core.FloatLiteral = value_of_initializer @__global_init.%Negate.call.loc28_47 [concrete = constants.%float.1f75e4.5] +// CHECK:STDOUT: %.loc28_47.2: Core.FloatLiteral = converted @__global_init.%Negate.call.loc28_47, %.loc28_47.1 [concrete = constants.%float.1f75e4.5] +// CHECK:STDOUT: %.loc28_13: type = splice_block %FloatLiteral.ref.loc28 [concrete = Core.FloatLiteral] { +// CHECK:STDOUT: %Core.ref.loc28: = name_ref Core, imports.%Core [concrete = imports.%Core] +// CHECK:STDOUT: %FloatLiteral.ref.loc28: type = name_ref FloatLiteral, imports.%Core.FloatLiteral [concrete = Core.FloatLiteral] +// CHECK:STDOUT: } +// CHECK:STDOUT: %v6: Core.FloatLiteral = wrapper_binding v6, %.loc28_47.2 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %v6.patt: %pattern_type = value_binding_pattern v6 [concrete = constants.%v6.patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Negate.ref.loc19: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc19: Core.FloatLiteral = float_literal_value 10e-1 [concrete = constants.%float.6da] +// CHECK:STDOUT: %Negate.call.loc19: init Core.FloatLiteral = call %Negate.ref.loc19(%float.loc19) [concrete = constants.%float.84a] +// CHECK:STDOUT: %Negate.ref.loc20: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc20: Core.FloatLiteral = float_literal_value 18e8 [concrete = constants.%float.c59] +// CHECK:STDOUT: %Negate.call.loc20: init Core.FloatLiteral = call %Negate.ref.loc20(%float.loc20) [concrete = constants.%float.838] +// CHECK:STDOUT: %Negate.ref.loc23_29: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %Negate.ref.loc23_36: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc23: Core.FloatLiteral = float_literal_value 8787e-2 [concrete = constants.%float.b21268.1] +// CHECK:STDOUT: %Negate.call.loc23_48: init Core.FloatLiteral = call %Negate.ref.loc23_36(%float.loc23) [concrete = constants.%float.923] +// CHECK:STDOUT: %.loc23_48.1: Core.FloatLiteral = value_of_initializer %Negate.call.loc23_48 [concrete = constants.%float.923] +// CHECK:STDOUT: %.loc23_48.2: Core.FloatLiteral = converted %Negate.call.loc23_48, %.loc23_48.1 [concrete = constants.%float.923] +// CHECK:STDOUT: %Negate.call.loc23_49: init Core.FloatLiteral = call %Negate.ref.loc23_29(%.loc23_48.2) [concrete = constants.%float.b21268.2] +// CHECK:STDOUT: %Negate.ref.loc24_29: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %Negate.ref.loc24_36: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc24: Core.FloatLiteral = float_literal_value 24p-3 [concrete = constants.%float.eda197.1] +// CHECK:STDOUT: %Negate.call.loc24_50: init Core.FloatLiteral = call %Negate.ref.loc24_36(%float.loc24) [concrete = constants.%float.0b3] +// CHECK:STDOUT: %.loc24_50.1: Core.FloatLiteral = value_of_initializer %Negate.call.loc24_50 [concrete = constants.%float.0b3] +// CHECK:STDOUT: %.loc24_50.2: Core.FloatLiteral = converted %Negate.call.loc24_50, %.loc24_50.1 [concrete = constants.%float.0b3] +// CHECK:STDOUT: %Negate.call.loc24_51: init Core.FloatLiteral = call %Negate.ref.loc24_29(%.loc24_50.2) [concrete = constants.%float.eda197.2] +// CHECK:STDOUT: %Negate.ref.loc27: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc27: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f75e4.1] +// CHECK:STDOUT: %Negate.call.loc27: init Core.FloatLiteral = call %Negate.ref.loc27(%float.loc27) [concrete = constants.%float.1f75e4.2] +// CHECK:STDOUT: %Negate.ref.loc28_29: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %Negate.ref.loc28_36: %Negate.type = name_ref Negate, file.%Negate.decl [concrete = constants.%Negate] +// CHECK:STDOUT: %float.loc28: Core.FloatLiteral = float_literal_value 0e-1 [concrete = constants.%float.1f75e4.3] +// CHECK:STDOUT: %Negate.call.loc28_46: init Core.FloatLiteral = call %Negate.ref.loc28_36(%float.loc28) [concrete = constants.%float.1f75e4.4] +// CHECK:STDOUT: %.loc28_46.1: Core.FloatLiteral = value_of_initializer %Negate.call.loc28_46 [concrete = constants.%float.1f75e4.4] +// CHECK:STDOUT: %.loc28_46.2: Core.FloatLiteral = converted %Negate.call.loc28_46, %.loc28_46.1 [concrete = constants.%float.1f75e4.4] +// CHECK:STDOUT: %Negate.call.loc28_47: init Core.FloatLiteral = call %Negate.ref.loc28_29(%.loc28_46.2) [concrete = constants.%float.1f75e4.5] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/convert_float.carbon b/toolchain/check/testdata/builtins/int/convert_float.carbon index 6f812f76cb9c..88a53b12f655 100644 --- a/toolchain/check/testdata/builtins/int/convert_float.carbon +++ b/toolchain/check/testdata/builtins/int/convert_float.carbon @@ -55,18 +55,6 @@ import library "int_to_float"; let overflow: f64 = ConvertIntLiteralToF64(1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); //@dump-sem-ir-end -// --- fail_todo_negative_literal.carbon -library "[[@TEST_NAME]]"; -import library "int_to_float"; - -//@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_negative_literal.carbon:[[@LINE+4]]:20: error: semantics TODO: `negative float literal conversion` [SemanticsTodo] -// CHECK:STDERR: let invalid: f64 = ConvertIntLiteralToFloatLiteral(-1) as f64; -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -let invalid: f64 = ConvertIntLiteralToFloatLiteral(-1) as f64; -//@dump-sem-ir-end - // CHECK:STDOUT: --- fail_overflow.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -101,75 +89,3 @@ let invalid: f64 = ConvertIntLiteralToFloatLiteral(-1) as f64; // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_negative_literal.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] -// CHECK:STDOUT: %f64.dc1: type = class_type @Float, @Float(%int_64) [concrete] -// CHECK:STDOUT: %pattern_type.fb7: type = pattern_type %f64.dc1 [concrete] -// CHECK:STDOUT: %invalid.patt: %pattern_type.fb7 = value_binding_pattern invalid [concrete] -// CHECK:STDOUT: %ConvertIntLiteralToFloatLiteral.type: type = fn_type @ConvertIntLiteralToFloatLiteral [concrete] -// CHECK:STDOUT: %ConvertIntLiteralToFloatLiteral: %ConvertIntLiteralToFloatLiteral.type = struct_value () [concrete] -// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete] -// CHECK:STDOUT: %Negate.type: type = facet_type <@Negate> [concrete] -// CHECK:STDOUT: %Negate.impl_witness: = impl_witness imports.%Negate.impl_witness_table [concrete] -// CHECK:STDOUT: %Negate.facet: %Negate.type = facet_value Core.IntLiteral, (%Negate.impl_witness) [concrete] -// CHECK:STDOUT: %Negate.WithSelf.Op.type.e85: type = fn_type @Negate.WithSelf.Op, @Negate.WithSelf(%Negate.facet) [concrete] -// CHECK:STDOUT: %.758: type = fn_type_with_self_type %Negate.WithSelf.Op.type.e85, %Negate.facet [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.Negate.impl.Op.type: type = fn_type @Core.IntLiteral.as.Negate.impl.Op [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.Negate.impl.Op: %Core.IntLiteral.as.Negate.impl.Op.type = struct_value () [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.Negate.impl.Op.bound: = bound_method %int_1, %Core.IntLiteral.as.Negate.impl.Op [concrete] -// CHECK:STDOUT: %int_-1: Core.IntLiteral = int_value -1 [concrete] -// CHECK:STDOUT: %As.type.0e0: type = facet_type <@As, @As(%f64.dc1)> [concrete] -// CHECK:STDOUT: %To: Core.IntLiteral = symbolic_binding To, 0 [symbolic] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.type.69a: type = fn_type @Core.FloatLiteral.as.As.impl.Convert, @Core.FloatLiteral.as.As.impl(%To) [symbolic] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.829: %Core.FloatLiteral.as.As.impl.Convert.type.69a = struct_value () [symbolic] -// CHECK:STDOUT: %As.impl_witness.355: = impl_witness imports.%As.impl_witness_table, @Core.FloatLiteral.as.As.impl(%int_64) [concrete] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.type.0cf: type = fn_type @Core.FloatLiteral.as.As.impl.Convert, @Core.FloatLiteral.as.As.impl(%int_64) [concrete] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.20d: %Core.FloatLiteral.as.As.impl.Convert.type.0cf = struct_value () [concrete] -// CHECK:STDOUT: %As.facet: %As.type.0e0 = facet_value Core.FloatLiteral, (%As.impl_witness.355) [concrete] -// CHECK:STDOUT: %As.WithSelf.Convert.type.a43: type = fn_type @As.WithSelf.Convert, @As.WithSelf(%f64.dc1, %As.facet) [concrete] -// CHECK:STDOUT: %.a08: type = fn_type_with_self_type %As.WithSelf.Convert.type.a43, %As.facet [concrete] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.FloatLiteral.as.As.impl.Convert.20d, @Core.FloatLiteral.as.As.impl.Convert(%int_64) [concrete] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Main.ConvertIntLiteralToFloatLiteral: %ConvertIntLiteralToFloatLiteral.type = import_ref Main//int_to_float, ConvertIntLiteralToFloatLiteral, loaded [concrete = constants.%ConvertIntLiteralToFloatLiteral] -// CHECK:STDOUT: %Core.import_ref.abd = import_ref Core//prelude/parts/int_literal, loc{{\d+_\d+}}, unloaded -// CHECK:STDOUT: %Core.import_ref.9c3: %Core.IntLiteral.as.Negate.impl.Op.type = import_ref Core//prelude/parts/int_literal, loc{{\d+_\d+}}, loaded [concrete = constants.%Core.IntLiteral.as.Negate.impl.Op] -// CHECK:STDOUT: %Negate.impl_witness_table = impl_witness_table (%Core.import_ref.abd, %Core.import_ref.9c3), @Core.IntLiteral.as.Negate.impl [concrete] -// CHECK:STDOUT: %Core.import_ref.c06: @Core.FloatLiteral.as.As.impl.%Core.FloatLiteral.as.As.impl.Convert.type (%Core.FloatLiteral.as.As.impl.Convert.type.69a) = import_ref Core//prelude/parts/float, loc{{\d+_\d+}}, loaded [symbolic = @Core.FloatLiteral.as.As.impl.%Core.FloatLiteral.as.As.impl.Convert (constants.%Core.FloatLiteral.as.As.impl.Convert.829)] -// CHECK:STDOUT: %As.impl_witness_table = impl_witness_table (%Core.import_ref.c06), @Core.FloatLiteral.as.As.impl [concrete] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: %f64: type = type_literal constants.%f64.dc1 [concrete = constants.%f64.dc1] -// CHECK:STDOUT: %invalid: %f64.dc1 = wrapper_binding invalid, @__global_init.%.loc9_56.2 [concrete = ] -// CHECK:STDOUT: name_binding_decl { -// CHECK:STDOUT: %invalid.patt: %pattern_type.fb7 = value_binding_pattern invalid [concrete = constants.%invalid.patt] -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @__global_init() { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %ConvertIntLiteralToFloatLiteral.ref: %ConvertIntLiteralToFloatLiteral.type = name_ref ConvertIntLiteralToFloatLiteral, imports.%Main.ConvertIntLiteralToFloatLiteral [concrete = constants.%ConvertIntLiteralToFloatLiteral] -// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1] -// CHECK:STDOUT: %impl.elem1: %.758 = impl_witness_access constants.%Negate.impl_witness, element1 [concrete = constants.%Core.IntLiteral.as.Negate.impl.Op] -// CHECK:STDOUT: %bound_method.loc9_52: = bound_method %int_1, %impl.elem1 [concrete = constants.%Core.IntLiteral.as.Negate.impl.Op.bound] -// CHECK:STDOUT: %Core.IntLiteral.as.Negate.impl.Op.call: init Core.IntLiteral = call %bound_method.loc9_52(%int_1) [concrete = constants.%int_-1] -// CHECK:STDOUT: %.loc9_52.1: Core.IntLiteral = value_of_initializer %Core.IntLiteral.as.Negate.impl.Op.call [concrete = constants.%int_-1] -// CHECK:STDOUT: %.loc9_52.2: Core.IntLiteral = converted %Core.IntLiteral.as.Negate.impl.Op.call, %.loc9_52.1 [concrete = constants.%int_-1] -// CHECK:STDOUT: %ConvertIntLiteralToFloatLiteral.call: init Core.FloatLiteral = call %ConvertIntLiteralToFloatLiteral.ref(%.loc9_52.2) [concrete = ] -// CHECK:STDOUT: %f64: type = type_literal constants.%f64.dc1 [concrete = constants.%f64.dc1] -// CHECK:STDOUT: %impl.elem0: %.a08 = impl_witness_access constants.%As.impl_witness.355, element0 [concrete = constants.%Core.FloatLiteral.as.As.impl.Convert.20d] -// CHECK:STDOUT: %bound_method.loc9_56.1: = bound_method %ConvertIntLiteralToFloatLiteral.call, %impl.elem0 [concrete = ] -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.FloatLiteral.as.As.impl.Convert(constants.%int_64) [concrete = constants.%Core.FloatLiteral.as.As.impl.Convert.specific_fn] -// CHECK:STDOUT: %bound_method.loc9_56.2: = bound_method %ConvertIntLiteralToFloatLiteral.call, %specific_fn [concrete = ] -// CHECK:STDOUT: %.loc9_54.1: Core.FloatLiteral = value_of_initializer %ConvertIntLiteralToFloatLiteral.call [concrete = ] -// CHECK:STDOUT: %.loc9_54.2: Core.FloatLiteral = converted %ConvertIntLiteralToFloatLiteral.call, %.loc9_54.1 [concrete = ] -// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.call: init %f64.dc1 = call %bound_method.loc9_56.2(%.loc9_54.2) [concrete = ] -// CHECK:STDOUT: %.loc9_56.1: %f64.dc1 = value_of_initializer %Core.FloatLiteral.as.As.impl.Convert.call [concrete = ] -// CHECK:STDOUT: %.loc9_56.2: %f64.dc1 = converted %ConvertIntLiteralToFloatLiteral.call, %.loc9_56.1 [concrete = ] -// CHECK:STDOUT: -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/lex/numeric_literal.cpp b/toolchain/lex/numeric_literal.cpp index 53ef331a951f..089c7ac390b8 100644 --- a/toolchain/lex/numeric_literal.cpp +++ b/toolchain/lex/numeric_literal.cpp @@ -325,7 +325,7 @@ auto NumericLiteral::Parser::GetMantissa() -> llvm::APInt { const char* end = IsInt() ? int_part_.end() : fract_part_.end(); llvm::StringRef digits(int_part_.begin(), end - int_part_.begin()); return ParseInt(digits, radix_, mantissa_needs_cleaning_, - /*is_signed=*/false); + /*is_signed=*/true); } auto NumericLiteral::Parser::GetExponent() -> llvm::APInt { diff --git a/toolchain/lex/tokenized_buffer_test.cpp b/toolchain/lex/tokenized_buffer_test.cpp index 75fc1c8da239..d15efead89a2 100644 --- a/toolchain/lex/tokenized_buffer_test.cpp +++ b/toolchain/lex/tokenized_buffer_test.cpp @@ -253,7 +253,7 @@ TEST_F(LexerTest, HandlesNumericLiteral) { auto token_1_5e9 = token_1_234_567 + 1; auto value_1_5e9 = value_stores.reals().Get(buffer.GetRealLiteral(*token_1_5e9)); - EXPECT_EQ(value_1_5e9.mantissa.getZExtValue(), 15); + EXPECT_EQ(value_1_5e9.mantissa.getSExtValue(), 15); EXPECT_EQ(value_1_5e9.exponent.getSExtValue(), 8); EXPECT_EQ(value_1_5e9.is_decimal, true); } diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index 79e62a63f16b..eddbb614e739 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -724,8 +724,8 @@ constexpr BuiltinInfo IntGreaterEq = { "int.greater_eq", ValidateSignatureBool>}; // "float.negate": float negation. -constexpr BuiltinInfo FloatNegate = { - "float.negate", ValidateSignatureSizedFloatT>}; +constexpr BuiltinInfo FloatNegate = {"float.negate", + ValidateSignatureFloatT>}; // "float.add": float addition. constexpr BuiltinInfo FloatAdd = { diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 7a4151eb0732..cb3cea8186fc 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -1705,7 +1705,7 @@ auto Formatter::FormatArg(ExprRegionId id) -> void { auto Formatter::FormatArg(RealId id) -> void { // TODO: Format with a `.` when the exponent is near zero. const auto& real = sem_ir_->reals().Get(id); - real.mantissa.print(out(), /*isSigned=*/false); + real.mantissa.print(out(), /*isSigned=*/true); out() << (real.is_decimal ? 'e' : 'p') << real.exponent; }