mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 13:41:04 +01:00
The first change here is to canonicalize away bit width when tracking integers in our shared value store. This lets us have a more definitive model of "what is the mathematical value". It also frees us to use more efficient bit widths when available, such as bits inside the ID itself. For canonicalizing, we try to minimize the width adjustments and maximize the use of the SSO in APInt, and so we never shrink belowe 64-bits and grow in multiples of the word bit width in the implementation. We also canonicalize to the signed 2s compliment representation so we can represent negative numbers in an intuitive way. The canonicalizing requires getting the bit width out of the type and adjusting to it within the toolchain when doing any kind of math, and this PR updates various places to do that, as well as adding some convenience APIs to assist. Then we take advantage of the canonical form and embed small integers into the ID itself rather than allocating storage for them and referencing them with an index. This is especially helpful for the pervasive small integers such as the sizes of types, arrays, etc. Those no longer require indirection at all. Various short-cut APIs to take advantage of this have also been added. This PR improves lexing by about 5% when there are lots of `i32` types. --------- Co-authored-by: Dana Jansens <danakj@orodu.net> Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com> Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
101 lines
3.1 KiB
C++
101 lines
3.1 KiB
C++
// 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
|
|
|
|
#ifndef CARBON_TOOLCHAIN_BASE_VALUE_IDS_H_
|
|
#define CARBON_TOOLCHAIN_BASE_VALUE_IDS_H_
|
|
|
|
#include "common/ostream.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/YAMLParser.h"
|
|
#include "toolchain/base/index_base.h"
|
|
|
|
namespace Carbon {
|
|
|
|
// The value of a real literal token.
|
|
//
|
|
// This is either a dyadic fraction (mantissa * 2^exponent) or a decadic
|
|
// fraction (mantissa * 10^exponent).
|
|
//
|
|
// These values are not canonicalized, because we don't expect them to repeat
|
|
// and don't use them in SemIR values.
|
|
class Real : public Printable<Real> {
|
|
public:
|
|
auto Print(llvm::raw_ostream& output_stream) const -> void {
|
|
mantissa.print(output_stream, /*isSigned=*/false);
|
|
output_stream << "*" << (is_decimal ? "10" : "2") << "^" << exponent;
|
|
}
|
|
|
|
// The mantissa, represented as an unsigned integer.
|
|
llvm::APInt mantissa;
|
|
|
|
// The exponent, represented as a signed integer.
|
|
llvm::APInt exponent;
|
|
|
|
// If false, the value is mantissa * 2^exponent.
|
|
// If true, the value is mantissa * 10^exponent.
|
|
// TODO: This field increases Real from 32 bytes to 40 bytes. Consider
|
|
// changing how it's tracked for space savings.
|
|
bool is_decimal;
|
|
};
|
|
|
|
// Corresponds to a float value represented by an APFloat. This is used for
|
|
// floating-point values in SemIR.
|
|
struct FloatId : public IdBase, public Printable<FloatId> {
|
|
using ValueType = llvm::APFloat;
|
|
static const FloatId Invalid;
|
|
using IdBase::IdBase;
|
|
auto Print(llvm::raw_ostream& out) const -> void {
|
|
out << "float";
|
|
IdBase::Print(out);
|
|
}
|
|
};
|
|
constexpr FloatId FloatId::Invalid(FloatId::InvalidIndex);
|
|
|
|
// Corresponds to a Real value.
|
|
struct RealId : public IdBase, public Printable<RealId> {
|
|
using ValueType = Real;
|
|
static const RealId Invalid;
|
|
using IdBase::IdBase;
|
|
auto Print(llvm::raw_ostream& out) const -> void {
|
|
out << "real";
|
|
IdBase::Print(out);
|
|
}
|
|
};
|
|
constexpr RealId RealId::Invalid(RealId::InvalidIndex);
|
|
|
|
// Corresponds to StringRefs for identifiers.
|
|
//
|
|
// `NameId` relies on the values of this type other than `Invalid` all being
|
|
// non-negative.
|
|
struct IdentifierId : public IdBase, public Printable<IdentifierId> {
|
|
using ValueType = llvm::StringRef;
|
|
static const IdentifierId Invalid;
|
|
using IdBase::IdBase;
|
|
auto Print(llvm::raw_ostream& out) const -> void {
|
|
out << "identifier";
|
|
IdBase::Print(out);
|
|
}
|
|
};
|
|
constexpr IdentifierId IdentifierId::Invalid(IdentifierId::InvalidIndex);
|
|
|
|
// Corresponds to StringRefs for string literals.
|
|
struct StringLiteralValueId : public IdBase,
|
|
public Printable<StringLiteralValueId> {
|
|
using ValueType = llvm::StringRef;
|
|
static const StringLiteralValueId Invalid;
|
|
using IdBase::IdBase;
|
|
auto Print(llvm::raw_ostream& out) const -> void {
|
|
out << "string";
|
|
IdBase::Print(out);
|
|
}
|
|
};
|
|
constexpr StringLiteralValueId StringLiteralValueId::Invalid(
|
|
StringLiteralValueId::InvalidIndex);
|
|
|
|
} // namespace Carbon
|
|
|
|
#endif // CARBON_TOOLCHAIN_BASE_VALUE_IDS_H_
|