Files
carbon-lang/toolchain/base/int.cpp
T
Chandler Carruth d010d52f37 Switch the ValueStore-related templates to use explicit instantiation (#7116)
As part of this, move functions that seem reasonable to make out-of-line
to a separate `_impl.h` header file that is only included where the
explicit instantiation _definition_ is provided.

By using explicit instantiation we can make these templates behave more
like non-template classes in terms of supporting out-of-line definitions
that don't need to be compiled by every translation unit. The set of
eventual instantiations here is fundamentally known, and there tend to
be headers that define a canonical "leaf" type where it makes sense to
trigger the explicit instantiation.

Where we already had a `.cpp` file to put the explicit instantiation
definition, use it. But in some places we didn't have such a `.cpp` file
so this PR adds those.

This also requires that we have precise constraints on APIs that _can't_
be instantiated for specific argument types, as now we don't do this
lazily.

Combined, this appears to reduce the sum of object file sizes in the
`check` directory by almost 40% (122mb -> 74mb) in my measurement.

My actual goal was to improve compile times, but so far I don't have a
great methodology for measuring these... But the object file size
reduction seems to confirm this is a net win and likely represents a
non-trivial improvement in compile time.

Assisted-by: Antigravity with Gemini
2026-05-14 08:29:17 +00:00

76 lines
2.5 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/int.h"
#include <algorithm>
#include <string>
#include "toolchain/base/canonical_value_store_impl.h"
#include "toolchain/base/value_store_impl.h"
namespace Carbon {
auto IntStore::CanonicalBitWidth(int significant_bits) -> int {
// For larger integers, we store them in as a signed APInt with a canonical
// width that is the smallest multiple of the word type's bits, but no
// smaller than a minimum of 64 bits to avoid spurious resizing of the most
// common cases (<= 64 bits).
static constexpr int WordWidth = llvm::APInt::APINT_BITS_PER_WORD;
return std::max<int>(
MinAPWidth, ((significant_bits + WordWidth - 1) / WordWidth) * WordWidth);
}
auto IntStore::CanonicalizeSigned(llvm::APInt value) -> llvm::APInt {
return value.sextOrTrunc(CanonicalBitWidth(value.getSignificantBits()));
}
auto IntStore::CanonicalizeUnsigned(llvm::APInt value) -> llvm::APInt {
// We need the width to include a zero sign bit as we canonicalize to a
// signed representation.
return value.zextOrTrunc(CanonicalBitWidth(value.getActiveBits() + 1));
}
auto IntStore::AddLarge(int64_t value) -> IntId {
auto ap_id =
values_.Add(llvm::APInt(CanonicalBitWidth(64), value, /*isSigned=*/true));
return MakeIndexOrNone(ap_id.index);
}
auto IntStore::AddSignedLarge(llvm::APInt value) -> IntId {
auto ap_id = values_.Add(CanonicalizeSigned(value));
return MakeIndexOrNone(ap_id.index);
}
auto IntStore::AddUnsignedLarge(llvm::APInt value) -> IntId {
auto ap_id = values_.Add(CanonicalizeUnsigned(value));
return MakeIndexOrNone(ap_id.index);
}
auto IntStore::LookupLarge(int64_t value) const -> IntId {
auto ap_id = values_.Lookup(
llvm::APInt(CanonicalBitWidth(64), value, /*isSigned=*/true));
return MakeIndexOrNone(ap_id.index);
}
auto IntStore::LookupSignedLarge(llvm::APInt value) const -> IntId {
auto ap_id = values_.Lookup(CanonicalizeSigned(value));
return MakeIndexOrNone(ap_id.index);
}
auto IntStore::OutputYaml() const -> Yaml::OutputMapping {
return values_.OutputYaml();
}
auto IntStore::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
-> void {
mem_usage.Collect(std::string(label), values_);
}
template class CanonicalValueStore<IntStore::APIntId, llvm::APInt>;
template class ValueStore<IntStore::APIntId, llvm::APInt>;
} // namespace Carbon