Files
carbon-lang/toolchain/base/shared_value_stores_test.cpp
T
3ba4997855 Canonicalize away bit width and embed small integers into IntIds (#4487)
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>
2024-11-13 09:36:20 +00:00

62 lines
2.3 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
#include "toolchain/base/shared_value_stores.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "testing/base/test_raw_ostream.h"
#include "toolchain/testing/yaml_test_helpers.h"
namespace Carbon::Testing {
namespace {
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::Pair;
auto MatchSharedValues(testing::Matcher<Yaml::MappingValue> ints,
testing::Matcher<Yaml::MappingValue> reals,
testing::Matcher<Yaml::MappingValue> identifiers,
testing::Matcher<Yaml::MappingValue> strings) -> auto {
return Yaml::IsYaml(Yaml::Sequence(ElementsAre(Yaml::Mapping(ElementsAre(Pair(
"shared_values",
Yaml::Mapping(ElementsAre(Pair("ints", Yaml::Mapping(ints)),
Pair("reals", Yaml::Mapping(reals)),
Pair("identifiers", Yaml::Mapping(identifiers)),
Pair("strings", Yaml::Mapping(strings))))))))));
}
TEST(SharedValueStores, PrintEmpty) {
SharedValueStores value_stores;
TestRawOstream out;
value_stores.Print(out);
EXPECT_THAT(Yaml::Value::FromText(out.TakeStr()),
MatchSharedValues(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty()));
}
TEST(SharedValueStores, PrintVals) {
SharedValueStores value_stores;
llvm::APInt apint(64, 8, /*isSigned=*/true);
value_stores.ints().AddSigned(apint);
value_stores.ints().AddSigned(llvm::APInt(64, 999'999'999'999));
value_stores.reals().Add(
Real{.mantissa = apint, .exponent = apint, .is_decimal = true});
value_stores.identifiers().Add("a");
value_stores.string_literal_values().Add("foo'\"baz");
TestRawOstream out;
value_stores.Print(out);
EXPECT_THAT(Yaml::Value::FromText(out.TakeStr()),
MatchSharedValues(
ElementsAre(Pair("ap_int0", Yaml::Scalar("999999999999"))),
ElementsAre(Pair("real0", Yaml::Scalar("8*10^8"))),
ElementsAre(Pair("identifier0", Yaml::Scalar("a"))),
ElementsAre(Pair("string0", Yaml::Scalar("foo'\"baz")))));
}
} // namespace
} // namespace Carbon::Testing