mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:40:10 +01:00
Implement Core.Negate for float literals (#7616)
Addresses part of issue raised in #7159 by implementing float.negate builtin for FloatLiteralValues The following code now compiles: ``` let a: f64 = -1.0; ``` To achieve this I switch the mantissa from being unsigned to signed. Lexed literals within source file will still always be unsigned, however it is now possible to create negative FloatLiteralValue constants. Main non-local changes this causes is: - All llvm::APInt parsing / printing calls flipped isSigned param - Zero extension replaced with sign extension - getActiveBits() replaced with getSignificantBits() for min bit width calculation
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ namespace Carbon {
|
||||
// TODO: Address this by using a different representation in SemIR.
|
||||
struct Real : public Printable<Real> {
|
||||
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.
|
||||
|
||||
+41
-27
@@ -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<unsigned>(mantissa.getActiveBits() * 2, bounds.upper_bound));
|
||||
CARBON_CHECK(exponent_upper_bound <=
|
||||
std::max<unsigned>(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<unsigned>(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<SemIR::FloatLiteralValue>(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<SemIR::FloatValue>(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));
|
||||
}
|
||||
|
||||
@@ -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> = 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: <namespace> = 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: <namespace> = 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: <namespace> = 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: <namespace> = 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: <namespace> = 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: <namespace> = 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: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -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: <elided>
|
||||
// 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: <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> = 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: <witness> = 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> = 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 = <error>]
|
||||
// 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> = 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 = <error>]
|
||||
// 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> = bound_method %ConvertIntLiteralToFloatLiteral.call, %impl.elem0 [concrete = <error>]
|
||||
// CHECK:STDOUT: %specific_fn: <specific function> = 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> = bound_method %ConvertIntLiteralToFloatLiteral.call, %specific_fn [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc9_54.1: Core.FloatLiteral = value_of_initializer %ConvertIntLiteralToFloatLiteral.call [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc9_54.2: Core.FloatLiteral = converted %ConvertIntLiteralToFloatLiteral.call, %.loc9_54.1 [concrete = <error>]
|
||||
// CHECK:STDOUT: %Core.FloatLiteral.as.As.impl.Convert.call: init %f64.dc1 = call %bound_method.loc9_56.2(%.loc9_54.2) [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc9_56.1: %f64.dc1 = value_of_initializer %Core.FloatLiteral.as.As.impl.Convert.call [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc9_56.2: %f64.dc1 = converted %ConvertIntLiteralToFloatLiteral.call, %.loc9_56.1 [concrete = <error>]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -724,8 +724,8 @@ constexpr BuiltinInfo IntGreaterEq = {
|
||||
"int.greater_eq", ValidateSignature<auto(IntT, IntU)->Bool>};
|
||||
|
||||
// "float.negate": float negation.
|
||||
constexpr BuiltinInfo FloatNegate = {
|
||||
"float.negate", ValidateSignature<auto(SizedFloatT)->SizedFloatT>};
|
||||
constexpr BuiltinInfo FloatNegate = {"float.negate",
|
||||
ValidateSignature<auto(FloatT)->FloatT>};
|
||||
|
||||
// "float.add": float addition.
|
||||
constexpr BuiltinInfo FloatAdd = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user