mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:10:12 +01:00
Previously Collect() was used for types that implemented CollectMemUsage() but otherwise Add() was used. This required the caller to think about the type of the field and know/decide which method to use. Now, the caller always uses Collect() unless they are adding specific byte values, in which case Add is used. Typically then, Add will only be used to implement the CollectMemUsage() function. To do this we require all Collect() methods to be templates so that they all be a single overload set. The Collect on BumpPtrAllocator is converted to a template that checks `std::same_as<llvm::BumpPtrAllocator, T>`.
101 lines
3.4 KiB
C++
101 lines
3.4 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/sem_ir/generic.h"
|
|
|
|
#include "toolchain/sem_ir/file.h"
|
|
|
|
namespace Carbon::SemIR {
|
|
|
|
class SpecificStore::KeyContext : public TranslatingKeyContext<KeyContext> {
|
|
public:
|
|
// A lookup key for a specific.
|
|
struct Key {
|
|
GenericId generic_id;
|
|
InstBlockId args_id;
|
|
|
|
friend auto operator==(const Key&, const Key&) -> bool = default;
|
|
};
|
|
|
|
explicit KeyContext(llvm::ArrayRef<Specific> specifics)
|
|
: specifics_(specifics) {}
|
|
|
|
auto TranslateKey(SpecificId id) const -> Key {
|
|
const auto& specific = specifics_[id.index];
|
|
return {.generic_id = specific.generic_id, .args_id = specific.args_id};
|
|
}
|
|
|
|
private:
|
|
llvm::ArrayRef<Specific> specifics_;
|
|
};
|
|
|
|
auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
|
|
-> SpecificId {
|
|
CARBON_CHECK(generic_id.is_valid());
|
|
return lookup_table_
|
|
.Insert(
|
|
KeyContext::Key{.generic_id = generic_id, .args_id = args_id},
|
|
[&] {
|
|
return specifics_.Add(
|
|
{.generic_id = generic_id, .args_id = args_id});
|
|
},
|
|
KeyContext(specifics_.array_ref()))
|
|
.key();
|
|
}
|
|
|
|
auto SpecificStore::CollectMemUsage(MemUsage& mem_usage,
|
|
llvm::StringRef label) const -> void {
|
|
mem_usage.Collect(MemUsage::ConcatLabel(label, "specifics_"), specifics_);
|
|
mem_usage.Collect(MemUsage::ConcatLabel(label, "lookup_table_"),
|
|
lookup_table_, KeyContext(specifics_.array_ref()));
|
|
}
|
|
|
|
auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
ConstantId const_id) -> ConstantId {
|
|
if (!const_id.is_symbolic()) {
|
|
// Type does not depend on a generic parameter.
|
|
return const_id;
|
|
}
|
|
|
|
const auto& symbolic = sem_ir.constant_values().GetSymbolicConstant(const_id);
|
|
if (!symbolic.generic_id.is_valid()) {
|
|
// Constant is an abstract symbolic constant, not associated with some
|
|
// particular generic.
|
|
return const_id;
|
|
}
|
|
|
|
if (!specific_id.is_valid()) {
|
|
// We have a generic constant but no specific. We treat as a request for the
|
|
// canonical value of the constant.
|
|
return sem_ir.constant_values().Get(symbolic.inst_id);
|
|
}
|
|
|
|
const auto& specific = sem_ir.specifics().Get(specific_id);
|
|
CARBON_CHECK(specific.generic_id == symbolic.generic_id,
|
|
"Given a specific for the wrong generic");
|
|
|
|
auto value_block_id = specific.GetValueBlock(symbolic.index.region());
|
|
CARBON_CHECK(
|
|
value_block_id.is_valid(),
|
|
"Queried {0} in {1} for {2} before it was resolved.", symbolic.index,
|
|
specific_id,
|
|
sem_ir.insts().Get(sem_ir.generics().Get(specific.generic_id).decl_id));
|
|
return sem_ir.constant_values().Get(
|
|
sem_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]);
|
|
}
|
|
|
|
auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
InstId inst_id) -> ConstantId {
|
|
return GetConstantInSpecific(sem_ir, specific_id,
|
|
sem_ir.constant_values().Get(inst_id));
|
|
}
|
|
|
|
auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
TypeId type_id) -> TypeId {
|
|
return TypeId::ForTypeConstant(GetConstantInSpecific(
|
|
sem_ir, specific_id, sem_ir.types().GetConstantId(type_id)));
|
|
}
|
|
|
|
} // namespace Carbon::SemIR
|