diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 4f612715b5a3..739c980576fd 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -80,7 +80,7 @@ auto Context::AddInstInNoBlock(SemIR::LocIdAndInst loc_id_and_inst) auto const_id = TryEvalInst(*this, inst_id, loc_id_and_inst.inst); if (const_id.is_constant()) { CARBON_VLOG() << "Constant: " << loc_id_and_inst.inst << " -> " - << const_id.inst_id() << "\n"; + << constant_values().GetInstId(const_id) << "\n"; constant_values().Set(inst_id, const_id); } @@ -128,7 +128,7 @@ auto Context::ReplaceLocIdAndInstBeforeConstantUse( auto const_id = TryEvalInst(*this, inst_id, loc_id_and_inst.inst); if (const_id.is_constant()) { CARBON_VLOG() << "Constant: " << loc_id_and_inst.inst << " -> " - << const_id.inst_id() << "\n"; + << constant_values().GetInstId(const_id) << "\n"; } constant_values().Set(inst_id, const_id); } @@ -144,8 +144,8 @@ auto Context::ReplaceInstBeforeConstantUse(SemIR::InstId inst_id, // ensure. auto const_id = TryEvalInst(*this, inst_id, inst); if (const_id.is_constant()) { - CARBON_VLOG() << "Constant: " << inst << " -> " << const_id.inst_id() - << "\n"; + CARBON_VLOG() << "Constant: " << inst << " -> " + << constant_values().GetInstId(const_id) << "\n"; } constant_values().Set(inst_id, const_id); } @@ -470,7 +470,7 @@ auto Context::LookupNameInCore(SemIRLoc loc, llvm::StringRef name) } // Look through import_refs and aliases. - return constant_values().Get(inst_id).inst_id(); + return constant_values().GetConstantInstId(inst_id); } template @@ -558,7 +558,7 @@ auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id, if (!cond_const_id.is_template()) { // Symbolic or non-constant condition means a non-constant result. } else if (auto literal = insts().TryGetAs( - cond_const_id.inst_id())) { + constant_values().GetInstId(cond_const_id))) { const_id = constant_values().Get(literal.value().value.ToBool() ? if_true : if_false); } else { @@ -569,7 +569,7 @@ auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id, if (const_id.is_constant()) { CARBON_VLOG() << "Constant: " << insts().Get(select_id) << " -> " - << const_id.inst_id() << "\n"; + << constant_values().GetInstId(const_id) << "\n"; constant_values().Set(select_id, const_id); } } @@ -892,13 +892,8 @@ class TypeCompleter { if (field_value_rep.type_id != field.field_type_id) { same_as_object_rep = false; field.field_type_id = field_value_rep.type_id; - // TODO: Use `TryEvalInst` to form this value. - field_id = context_ - .AddConstant(field, context_.constant_values() - .Get(context_.types().GetInstId( - field.field_type_id)) - .is_symbolic()) - .inst_id(); + field_id = context_.constant_values().GetInstId( + TryEvalInst(context_, SemIR::InstId::Invalid, field)); } value_rep_fields.push_back(field_id); } diff --git a/toolchain/check/decl_name_stack.cpp b/toolchain/check/decl_name_stack.cpp index 9c2b69edefdf..93b95e3696c0 100644 --- a/toolchain/check/decl_name_stack.cpp +++ b/toolchain/check/decl_name_stack.cpp @@ -302,7 +302,8 @@ static auto DiagnoseQualifiedDeclInUndefinedInterfaceScope( auto builder = context.emitter().Build( loc, QualifiedDeclInUndefinedInterfaceScope, context.sem_ir().StringifyTypeExpr( - context.sem_ir().constant_values().Get(interface_inst_id).inst_id())); + context.sem_ir().constant_values().GetConstantInstId( + interface_inst_id))); context.NoteUndefinedInterface(interface_id, builder); builder.Emit(); } diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index a6d8887be528..6146653bdb7d 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -113,7 +113,7 @@ static auto GetConstantValue(Context& context, SemIR::InstId inst_id, Phase* phase) -> SemIR::InstId { auto const_id = context.constant_values().Get(inst_id); *phase = LatestPhase(*phase, GetPhase(const_id)); - return const_id.inst_id(); + return context.constant_values().GetInstId(const_id); } // A type is always constant, but we still need to extract its phase. @@ -1156,8 +1156,8 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) auto const_id = context.constant_values().Get(typed_inst.operand_id); auto phase = GetPhase(const_id); if (phase == Phase::Template) { - auto value = - context.insts().GetAs(const_id.inst_id()); + auto value = context.insts().GetAs( + context.constant_values().GetInstId(const_id)); return MakeBoolResult(context, value.type_id, !value.value.ToBool()); } if (phase == Phase::UnknownDueToError) { @@ -1172,7 +1172,9 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) auto inner_id = context.constant_values().Get( context.types().GetInstId(typed_inst.inner_id)); if (inner_id.is_constant() && - context.insts().Get(inner_id.inst_id()).Is()) { + context.insts() + .Get(context.constant_values().GetInstId(inner_id)) + .Is()) { return inner_id; } return MakeConstantResult(context, inst, GetPhase(inner_id)); diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index ae550ac85bd0..d7f208bd794e 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -145,8 +145,8 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id, } // Use the constant value to get the ID. - auto decl_value = - context.insts().Get(context.constant_values().Get(prev_id).inst_id()); + auto decl_value = context.insts().Get( + context.constant_values().GetConstantInstId(prev_id)); if (auto class_type = decl_value.TryAs()) { prev_class_id = class_type->class_id; prev_import_ir_id = import_ir_inst.ir_id; diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index df54fe4449f8..6afb86df5eaa 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -163,7 +163,7 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id, // Use the type to get the ID. if (auto struct_value = context.insts().TryGetAs( - context.constant_values().Get(prev_id).inst_id())) { + context.constant_values().GetConstantInstId(prev_id))) { if (auto function_type = context.types().TryGetAs( struct_value->type_id)) { prev_function_id = function_type->function_id; diff --git a/toolchain/check/handle_index.cpp b/toolchain/check/handle_index.cpp index a9e3ea0bdb1a..5fb263af212f 100644 --- a/toolchain/check/handle_index.cpp +++ b/toolchain/check/handle_index.cpp @@ -88,8 +88,8 @@ auto HandleIndexExpr(Context& context, Parse::IndexExprId node_id) -> bool { context.emitter().Emit(node_id, TupleIndexNotConstant); index_inst_id = SemIR::InstId::BuiltinError; } else { - auto index_literal = - context.insts().GetAs(index_const_id.inst_id()); + auto index_literal = context.insts().GetAs( + context.constant_values().GetInstId(index_const_id)); auto type_block = context.type_blocks().Get(tuple_type.elements_id); if (const auto* index_val = ValidateTupleIndex(context, node_id, operand_inst, diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index 1425c4c289d7..5056ef68e263 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -92,9 +92,9 @@ static auto BuildInterfaceWitness( for (auto decl_id : assoc_entities) { LoadImportRef(context, decl_id); - auto const_id = context.constant_values().Get(decl_id); - CARBON_CHECK(const_id.is_constant()) << "Non-constant associated entity"; - auto decl = context.insts().Get(const_id.inst_id()); + decl_id = context.constant_values().GetConstantInstId(decl_id); + CARBON_CHECK(decl_id.is_valid()) << "Non-constant associated entity"; + auto decl = context.insts().Get(decl_id); CARBON_KIND_SWITCH(decl) { case CARBON_KIND(SemIR::StructValue struct_value): { if (struct_value.type_id == SemIR::TypeId::Error) { diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 18f3e9cebf15..feffa87806aa 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -365,6 +365,16 @@ class ImportRefResolver { return const_id; } + // Returns the local constant InstId for an imported InstId. + auto GetLocalConstantInstId(SemIR::InstId inst_id) -> SemIR::InstId { + auto const_id = import_ir_constant_values().Get(inst_id); + if (!const_id.is_valid()) { + work_stack_.push_back({.inst_id = inst_id}); + return SemIR::InstId::Invalid; + } + return context_.constant_values().GetInstId(const_id); + } + // Returns the ConstantId for a TypeId. Adds unresolved constants to // work_stack_. auto GetLocalConstantId(SemIR::TypeId type_id) -> SemIR::ConstantId { @@ -385,7 +395,7 @@ class ImportRefResolver { inst_ids.reserve(import_block.size()); for (auto import_inst_id : import_block) { auto const_id = GetLocalConstantId(import_inst_id); - inst_ids.push_back(const_id.inst_id_if_valid()); + inst_ids.push_back(context_.constant_values().GetInstIdIfValid(const_id)); } return inst_ids; @@ -488,7 +498,7 @@ class ImportRefResolver { case SemIR::BindSymbolicName::Kind: { // The symbolic name will be created on first reference, so might // already exist. Update the value in it to refer to the parameter. - auto new_bind_inst_id = GetLocalConstantId(bind_id).inst_id(); + auto new_bind_inst_id = GetLocalConstantInstId(bind_id); auto new_bind_inst = context_.insts().GetAs( new_bind_inst_id); @@ -540,11 +550,11 @@ class ImportRefResolver { // TODO: Import the scope for an `impl` definition. return SemIR::NameScopeId::Invalid; } - auto const_id = GetLocalConstantId(inst_id); - if (!const_id.is_valid()) { + auto const_inst_id = GetLocalConstantInstId(inst_id); + if (!const_inst_id.is_valid()) { return SemIR::NameScopeId::Invalid; } - auto name_scope_inst = context_.insts().Get(const_id.inst_id()); + auto name_scope_inst = context_.insts().Get(const_inst_id); CARBON_KIND_SWITCH(name_scope_inst) { case CARBON_KIND(SemIR::Namespace inst): { return inst.name_scope_id; @@ -571,7 +581,7 @@ class ImportRefResolver { break; } default: { - if (const_id == SemIR::ConstantId::Error) { + if (const_inst_id == SemIR::InstId::BuiltinError) { return SemIR::NameScopeId::Invalid; } break; @@ -761,7 +771,7 @@ class ImportRefResolver { auto initial_work = work_stack_.size(); auto entity_type_const_id = GetLocalConstantId(inst.entity_type_id); - auto interface_const_id = GetLocalConstantId( + auto interface_inst_id = GetLocalConstantInstId( import_ir_.interfaces().Get(inst.interface_id).decl_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); @@ -769,10 +779,9 @@ class ImportRefResolver { return ResolveAs( {.type_id = SemIR::TypeId::TypeType, - .interface_id = - context_.insts() - .GetAs(interface_const_id.inst_id()) - .interface_id, + .interface_id = context_.insts() + .GetAs(interface_inst_id) + .interface_id, .entity_type_id = context_.GetTypeIdForTypeConstant(entity_type_const_id)}); } @@ -871,7 +880,7 @@ class ImportRefResolver { auto AddClassDefinition(const SemIR::Class& import_class, SemIR::Class& new_class, SemIR::ConstantId object_repr_const_id, - SemIR::ConstantId base_const_id) -> void { + SemIR::InstId base_id) -> void { new_class.definition_id = new_class.decl_id; new_class.object_repr_id = @@ -889,7 +898,7 @@ class ImportRefResolver { new_class.body_block_id = context_.inst_block_stack().Pop(); if (import_class.base_id.is_valid()) { - new_class.base_id = base_const_id.inst_id(); + new_class.base_id = base_id; // Add the base scope to extended scopes. auto base_inst_id = context_.types().GetInstId( context_.insts() @@ -918,7 +927,8 @@ class ImportRefResolver { } else { // On the second pass, compute the class ID from the constant value of the // declaration. - auto class_const_inst = context_.insts().Get(class_const_id.inst_id()); + auto class_const_inst = context_.insts().Get( + context_.constant_values().GetInstId(class_const_id)); if (auto class_type = class_const_inst.TryAs()) { class_id = class_type->class_id; } else { @@ -942,9 +952,9 @@ class ImportRefResolver { import_class.object_repr_id.is_valid() ? GetLocalConstantId(import_class.object_repr_id) : SemIR::ConstantId::Invalid; - auto base_const_id = import_class.base_id.is_valid() - ? GetLocalConstantId(import_class.base_id) - : SemIR::ConstantId::Invalid; + auto base_id = import_class.base_id.is_valid() + ? GetLocalConstantInstId(import_class.base_id) + : SemIR::InstId::Invalid; if (HasNewWork(initial_work)) { return ResolveResult::Retry(class_const_id); @@ -960,7 +970,7 @@ class ImportRefResolver { if (import_class.is_defined()) { AddClassDefinition(import_class, new_class, object_repr_const_id, - base_const_id); + base_id); } return {.const_id = class_const_id}; @@ -979,7 +989,8 @@ class ImportRefResolver { // Find the corresponding class type. For a non-generic class, this is the // type of the class declaration. For a generic class, build a class type // referencing this specialization of the generic class. - auto class_const_inst = context_.insts().Get(class_const_id.inst_id()); + auto class_const_inst = context_.insts().Get( + context_.constant_values().GetInstId(class_const_id)); if (class_const_inst.Is()) { return {.const_id = class_const_id}; } else { @@ -1094,12 +1105,12 @@ class ImportRefResolver { auto TryResolveTypedInst(SemIR::FunctionType inst) -> ResolveResult { auto initial_work = work_stack_.size(); CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); - auto fn_const_id = GetLocalConstantId( + auto fn_val_id = GetLocalConstantInstId( import_ir_.functions().Get(inst.function_id).decl_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } - auto fn_val = context_.insts().Get(fn_const_id.inst_id()); + auto fn_val = context_.insts().Get(fn_val_id); CARBON_CHECK(context_.types().Is(fn_val.type_id())); return {.const_id = context_.types().GetConstantId(fn_val.type_id())}; } @@ -1107,12 +1118,12 @@ class ImportRefResolver { auto TryResolveTypedInst(SemIR::GenericClassType inst) -> ResolveResult { auto initial_work = work_stack_.size(); CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); - auto class_const_id = - GetLocalConstantId(import_ir_.classes().Get(inst.class_id).decl_id); + auto class_val_id = + GetLocalConstantInstId(import_ir_.classes().Get(inst.class_id).decl_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } - auto class_val = context_.insts().Get(class_const_id.inst_id()); + auto class_val = context_.insts().Get(class_val_id); CARBON_CHECK( context_.types().Is(class_val.type_id())); return {.const_id = context_.types().GetConstantId(class_val.type_id())}; @@ -1121,12 +1132,12 @@ class ImportRefResolver { auto TryResolveTypedInst(SemIR::GenericInterfaceType inst) -> ResolveResult { auto initial_work = work_stack_.size(); CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType); - auto interface_const_id = GetLocalConstantId( + auto interface_val_id = GetLocalConstantInstId( import_ir_.interfaces().Get(inst.interface_id).decl_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } - auto interface_val = context_.insts().Get(interface_const_id.inst_id()); + auto interface_val = context_.insts().Get(interface_val_id); CARBON_CHECK(context_.types().Is( interface_val.type_id())); return {.const_id = @@ -1147,7 +1158,8 @@ class ImportRefResolver { return {.const_id = SemIR::ConstantId::Error}; } - auto new_constant_id = GetLocalConstantId(constant_id.inst_id()); + auto new_constant_id = + GetLocalConstantId(import_ir_.constant_values().GetInstId(constant_id)); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } @@ -1201,7 +1213,7 @@ class ImportRefResolver { // declaration. auto AddInterfaceDefinition(const SemIR::Interface& import_interface, SemIR::Interface& new_interface, - SemIR::ConstantId self_param_id) -> void { + SemIR::InstId self_param_id) -> void { new_interface.scope_id = context_.name_scopes().Add( new_interface.decl_id, SemIR::NameId::Invalid, new_interface.parent_scope_id); @@ -1215,7 +1227,7 @@ class ImportRefResolver { new_interface.associated_entities_id = AddAssociatedEntities(import_interface.associated_entities_id); new_interface.body_block_id = context_.inst_block_stack().Pop(); - new_interface.self_param_id = self_param_id.inst_id(); + new_interface.self_param_id = self_param_id; CARBON_CHECK(import_scope.extended_scopes.empty()) << "Interfaces don't currently have extended scopes to support."; @@ -1235,8 +1247,8 @@ class ImportRefResolver { } else { // On the second pass, compute the interface ID from the constant value of // the declaration. - auto interface_const_inst = - context_.insts().Get(interface_const_id.inst_id()); + auto interface_const_inst = context_.insts().Get( + context_.constant_values().GetInstId(interface_const_id)); if (auto interface_type = interface_const_inst.TryAs()) { interface_id = interface_type->interface_id; @@ -1256,7 +1268,7 @@ class ImportRefResolver { GetLocalParamConstantIds(import_interface.implicit_param_refs_id); llvm::SmallVector param_const_ids = GetLocalParamConstantIds(import_interface.param_refs_id); - auto self_param_id = GetLocalConstantId(import_interface.self_param_id); + auto self_param_id = GetLocalConstantInstId(import_interface.self_param_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(interface_const_id); @@ -1289,8 +1301,8 @@ class ImportRefResolver { // is the type of the interface declaration. For a generic interface, build // a interface type referencing this specialization of the generic // interface. - auto interface_const_inst = - context_.insts().Get(interface_const_id.inst_id()); + auto interface_const_inst = context_.insts().Get( + context_.constant_values().GetInstId(interface_const_id)); if (interface_const_inst.Is()) { return {.const_id = interface_const_id}; } else { @@ -1307,22 +1319,12 @@ class ImportRefResolver { auto TryResolveTypedInst(SemIR::InterfaceWitness inst) -> ResolveResult { auto initial_work = work_stack_.size(); - llvm::SmallVector elements; - auto import_elements = import_ir_.inst_blocks().Get(inst.elements_id); - elements.reserve(import_elements.size()); - for (auto import_elem_id : import_elements) { - if (auto const_id = GetLocalConstantId(import_elem_id); - const_id.is_valid()) { - elements.push_back(const_id.inst_id()); - } - } + auto elements = GetLocalInstBlockContents(inst.elements_id); if (HasNewWork(initial_work)) { return ResolveResult::Retry(); } - CARBON_CHECK(elements.size() == import_elements.size()) - << "Failed to import an element without adding new work."; - auto elements_id = context_.inst_blocks().Add(elements); + auto elements_id = GetLocalCanonicalInstBlockId(inst.elements_id, elements); return ResolveAs( {.type_id = context_.GetBuiltinType(SemIR::BuiltinKind::WitnessType), .elements_id = elements_id}); diff --git a/toolchain/check/member_access.cpp b/toolchain/check/member_access.cpp index 6a140f236e14..c16c0ab71edb 100644 --- a/toolchain/check/member_access.cpp +++ b/toolchain/check/member_access.cpp @@ -21,7 +21,8 @@ namespace Carbon::Check { static auto GetAsNameScope(Context& context, Parse::NodeId node_id, SemIR::ConstantId base_const_id) -> std::optional { - auto base = context.insts().Get(base_const_id.inst_id()); + auto base_id = context.constant_values().GetInstId(base_const_id); + auto base = context.insts().Get(base_id); if (auto base_as_namespace = base.TryAs()) { return base_as_namespace->name_scope_id; } @@ -35,7 +36,7 @@ static auto GetAsNameScope(Context& context, Parse::NodeId node_id, std::string); auto builder = context.emitter().Build( node_id, QualifiedExprInIncompleteClassScope, - context.sem_ir().StringifyTypeExpr(base_const_id.inst_id())); + context.sem_ir().StringifyType(base_const_id)); context.NoteIncompleteClass(base_as_class->class_id, builder); builder.Emit(); } @@ -50,7 +51,7 @@ static auto GetAsNameScope(Context& context, Parse::NodeId node_id, std::string); auto builder = context.emitter().Build( node_id, QualifiedExprInUndefinedInterfaceScope, - context.sem_ir().StringifyTypeExpr(base_const_id.inst_id())); + context.sem_ir().StringifyType(base_const_id)); context.NoteUndefinedInterface(base_as_interface->interface_id, builder); builder.Emit(); } @@ -131,7 +132,8 @@ static auto LookupInterfaceWitness(Context& context, // considering impls that are for the same interface we're querying. We can // also skip impls that mention any types that aren't part of our impl query. for (const auto& impl : context.impls().array_ref()) { - if (context.types().GetInstId(impl.self_id) != type_const_id.inst_id()) { + if (context.types().GetInstId(impl.self_id) != + context.constant_values().GetInstId(type_const_id)) { continue; } auto interface_type = @@ -168,22 +170,22 @@ static auto PerformImplLookup(Context& context, Parse::NodeId node_id, "Cannot access member of interface {0} in type {1} " "that does not implement that interface.", SemIR::NameId, std::string); - context.emitter().Emit( - node_id, MissingImplInMemberAccess, interface.name_id, - context.sem_ir().StringifyTypeExpr(type_const_id.inst_id())); + context.emitter().Emit(node_id, MissingImplInMemberAccess, + interface.name_id, + context.sem_ir().StringifyType(type_const_id)); return SemIR::InstId::BuiltinError; } - auto const_id = context.constant_values().Get(member_id); - if (!const_id.is_constant()) { - if (const_id != SemIR::ConstantId::Error) { + auto member_value_id = context.constant_values().GetConstantInstId(member_id); + if (!member_value_id.is_valid()) { + if (member_value_id != SemIR::InstId::BuiltinError) { context.TODO(member_id, "non-constant associated entity"); } return SemIR::InstId::BuiltinError; } auto assoc_entity = - context.insts().TryGetAs(const_id.inst_id()); + context.insts().TryGetAs(member_value_id); if (!assoc_entity) { context.TODO(member_id, "unexpected value for associated entity"); return SemIR::InstId::BuiltinError; @@ -256,11 +258,11 @@ static auto PerformInstanceBinding(Context& context, Parse::NodeId node_id, // Find the specified element, which could be either a field or a base // class, and build an element access expression. - auto element_id = context.constant_values().Get(member_id); - CARBON_CHECK(element_id.is_constant()) + auto element_id = context.constant_values().GetConstantInstId(member_id); + CARBON_CHECK(element_id.is_valid()) << "Non-constant value " << context.insts().Get(member_id) << " of unbound element type"; - auto index = GetClassElementIndex(context, element_id.inst_id()); + auto index = GetClassElementIndex(context, element_id); auto access_id = context.AddInst( node_id, {.type_id = unbound_element_type.element_type_id, .base_id = base_id, @@ -329,7 +331,7 @@ auto PerformMemberAccess(Context& context, Parse::NodeId node_id, if (!name_scope_id) { // The base type is not a name scope. Try some fallback options. if (auto struct_type = context.insts().TryGetAs( - base_type_const_id.inst_id())) { + context.constant_values().GetInstId(base_type_const_id))) { // TODO: Do we need to optimize this with a lookup table for O(1)? for (auto [i, ref_id] : llvm::enumerate(context.inst_blocks().Get(struct_type->fields_id))) { diff --git a/toolchain/check/operator.cpp b/toolchain/check/operator.cpp index 1e33f24e41a5..d4d123183af8 100644 --- a/toolchain/check/operator.cpp +++ b/toolchain/check/operator.cpp @@ -47,7 +47,7 @@ static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id, } // Look through import_refs and aliases. - op_id = context.constant_values().Get(op_id).inst_id(); + op_id = context.constant_values().GetConstantInstId(op_id); // We expect it to be an associated function. if (context.insts().Is(op_id)) { diff --git a/toolchain/check/subst.cpp b/toolchain/check/subst.cpp index a5dd133d8a06..08ce8fcf9b70 100644 --- a/toolchain/check/subst.cpp +++ b/toolchain/check/subst.cpp @@ -148,7 +148,7 @@ static auto Rebuild(Context& context, Worklist& worklist, SemIR::InstId inst_id) auto result_id = TryEvalInst(context, SemIR::InstId::Invalid, inst); CARBON_CHECK(result_id.is_constant()) << "Substitution into constant produced non-constant"; - return result_id.inst_id(); + return context.constant_values().GetInstId(result_id); } auto SubstConstant(Context& context, SemIR::ConstantId const_id, @@ -165,7 +165,7 @@ auto SubstConstant(Context& context, SemIR::ConstantId const_id, return const_id; } - Worklist worklist(const_id.inst_id()); + Worklist worklist(context.constant_values().GetInstId(const_id)); // For each instruction that forms part of the constant, we will visit it // twice: @@ -208,7 +208,7 @@ auto SubstConstant(Context& context, SemIR::ConstantId const_id, if (context.bind_names().Get(bind->bind_name_id).bind_index == bind_index) { // This is the binding we're replacing. Perform substitution. - item.inst_id = replacement_id.inst_id(); + item.inst_id = context.constant_values().GetInstId(replacement_id); break; } } diff --git a/toolchain/lower/constant.cpp b/toolchain/lower/constant.cpp index c70496431c18..a1091d211e08 100644 --- a/toolchain/lower/constant.cpp +++ b/toolchain/lower/constant.cpp @@ -30,11 +30,15 @@ class ConstantContext { // Gets the lowered constant value for a constant that has already been // lowered. auto GetConstant(SemIR::ConstantId const_id) const -> llvm::Constant* { - CARBON_CHECK(const_id.is_template() && const_id.inst_id().index >= 0) + CARBON_CHECK(const_id.is_template()) << "Unexpected constant ID " << const_id; - CARBON_CHECK(const_id.inst_id().index <= last_lowered_constant_index_) - << "Queried constant " << const_id << " that has not been lowered yet"; - return constants_[const_id.inst_id().index]; + auto inst_id = + file_context_->sem_ir().constant_values().GetInstId(const_id); + CARBON_CHECK(inst_id.index >= 0 && + inst_id.index <= last_lowered_constant_index_) + << "Queried constant " << const_id << " with instruction " << inst_id + << " that has not been lowered yet"; + return constants_[inst_id.index]; } // Returns a constant for the case of a value that should never be used. @@ -238,13 +242,14 @@ auto LowerConstants(FileContext& file_context, // We are only interested in lowering template constants. continue; } + auto inst_id = file_context.sem_ir().constant_values().GetInstId(const_id); - if (const_id.inst_id().index != static_cast(inst_id_val)) { + if (inst_id.index != static_cast(inst_id_val)) { // This isn't the instruction that defines the constant. continue; } - auto inst = file_context.sem_ir().insts().Get(const_id.inst_id()); + auto inst = file_context.sem_ir().insts().Get(inst_id); llvm::Constant* value = nullptr; CARBON_KIND_SWITCH(inst) { #define CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER(...) @@ -259,8 +264,8 @@ auto LowerConstants(FileContext& file_context, CARBON_FATAL() << "Unexpected constant instruction kind " << inst; } - constants[const_id.inst_id().index] = value; - context.SetLastLoweredConstantIndex(const_id.inst_id().index); + constants[inst_id.index] = value; + context.SetLastLoweredConstantIndex(inst_id.index); } } diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 73f0f351e3f7..c70e705faff4 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -70,11 +70,13 @@ auto FileContext::GetGlobal(SemIR::InstId inst_id) -> llvm::Value* { auto const_id = sem_ir().constant_values().Get(inst_id); if (const_id.is_template()) { + auto const_inst_id = sem_ir().constant_values().GetInstId(const_id); + // For value expressions and initializing expressions, the value produced by // a constant instruction is a value representation of the constant. For // initializing expressions, `FinishInit` will perform a copy if needed. // TODO: Handle reference expression constants. - auto* const_value = constants_[const_id.inst_id().index]; + auto* const_value = constants_[const_inst_id.index]; // If we want a pointer to the constant, materialize a global to hold it. // TODO: We could reuse the same global if the constant is used more than @@ -86,7 +88,7 @@ auto FileContext::GetGlobal(SemIR::InstId inst_id) -> llvm::Value* { llvm::StringRef const_name; llvm::StringRef use_name; if (inst_namer_) { - const_name = inst_namer_->GetUnscopedNameFor(const_id.inst_id()); + const_name = inst_namer_->GetUnscopedNameFor(const_inst_id); use_name = inst_namer_->GetUnscopedNameFor(inst_id); } diff --git a/toolchain/sem_ir/constant.h b/toolchain/sem_ir/constant.h index 289ad180eadf..566799df551d 100644 --- a/toolchain/sem_ir/constant.h +++ b/toolchain/sem_ir/constant.h @@ -37,6 +37,24 @@ class ConstantValueStore { values_[inst_id.index] = const_id; } + // Gets the instruction ID that defines the value of the given constant. + // Returns Invalid if the constant ID is non-constant. Requires is_valid. + auto GetInstId(ConstantId const_id) const -> InstId { + return const_id.inst_id(); + } + + // Gets the instruction ID that defines the value of the given constant. + // Returns Invalid if the constant ID is non-constant or invalid. + auto GetInstIdIfValid(ConstantId const_id) const -> InstId { + return const_id.is_valid() ? GetInstId(const_id) : InstId::Invalid; + } + + // Given an instruction, returns the unique constant instruction that is + // equivalent to it. Returns Invalid for a non-constant instruction. + auto GetConstantInstId(InstId inst_id) const -> InstId { + return GetInstId(Get(inst_id)); + } + // Returns the constant values mapping as an ArrayRef whose keys are // instruction indexes. Some of the elements in this mapping may be Invalid or // NotConstant. diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index af7086d8b71e..a016ce6c7c32 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -496,6 +496,11 @@ auto File::StringifyType(TypeId type_id) const -> std::string { return StringifyTypeExprImpl(*this, types().GetInstId(type_id)); } +auto File::StringifyType(ConstantId type_const_id) const -> std::string { + return StringifyTypeExprImpl(*this, + constant_values().GetInstId(type_const_id)); +} + auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { return StringifyTypeExprImpl(*this, outer_inst_id); } diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index f1bc96db2a7a..364ef825c30a 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -80,6 +80,9 @@ class File : public Printable { // Produces a string version of a type. auto StringifyType(TypeId type_id) const -> std::string; + // Same, but with a constant ID rather than a type ID. + auto StringifyType(ConstantId type_const_id) const -> std::string; + // Same as `StringifyType`, but starting with an instruction representing a // type expression rather than a canonical type. auto StringifyTypeExpr(InstId outer_inst_id) const -> std::string; @@ -238,7 +241,7 @@ class File : public Printable { ConstantStore constants_; // Descriptions of types used in this file. - TypeStore types_ = TypeStore(&insts_); + TypeStore types_ = TypeStore(&insts_, &constant_values_); // Types that were completed in this file. llvm::SmallVector complete_types_; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index db4faca19d9c..c7de1e54bba7 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -401,7 +401,7 @@ class Formatter { out_ << InstT::Kind.ir_name(); pending_constant_value_ = sem_ir_.constant_values().Get(inst_id); pending_constant_value_is_self_ = - pending_constant_value_.inst_id() == inst_id; + sem_ir_.constant_values().GetInstId(pending_constant_value_) == inst_id; FormatInstructionRHS(inst); FormatPendingConstantValue(AddSpace::Before); out_ << "\n"; @@ -433,7 +433,8 @@ class Formatter { out_ << (pending_constant_value_.is_symbolic() ? "symbolic" : "template"); if (!pending_constant_value_is_self_) { out_ << " = "; - FormatInstName(pending_constant_value_.inst_id()); + FormatInstName( + sem_ir_.constant_values().GetInstId(pending_constant_value_)); } } else { out_ << pending_constant_value_; diff --git a/toolchain/sem_ir/function.cpp b/toolchain/sem_ir/function.cpp index 99d3eba16fb6..3d921b9ba8ef 100644 --- a/toolchain/sem_ir/function.cpp +++ b/toolchain/sem_ir/function.cpp @@ -19,11 +19,11 @@ auto GetCalleeFunction(const File& sem_ir, InstId callee_id) -> CalleeFunction { } // Identify the function we're calling. - auto val_id = sem_ir.constant_values().Get(callee_id); - if (!val_id.is_constant()) { + auto val_id = sem_ir.constant_values().GetConstantInstId(callee_id); + if (!val_id.is_valid()) { return result; } - auto val_inst = sem_ir.insts().Get(val_id.inst_id()); + auto val_inst = sem_ir.insts().Get(val_id); auto struct_val = val_inst.TryAs(); if (!struct_val) { result.is_error = val_inst.type_id() == SemIR::TypeId::Error; diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 3130ac873af8..f93f2adb0911 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -134,19 +134,6 @@ struct ConstantId : public IdBase, public Printable { return index >= IndexOffset; } - // Returns the instruction that describes this constant value, or - // InstId::Invalid for a runtime value. Requires is_valid. - constexpr auto inst_id() const -> InstId { - CARBON_CHECK(is_valid()); - return InstId(Abs(index) - IndexOffset); - } - - // Returns the instruction that describes this constant value, or - // InstId::Invalid if this is invalid or a runtime value. - constexpr auto inst_id_if_valid() const -> InstId { - return is_valid() ? inst_id() : InstId::Invalid; - } - auto Print(llvm::raw_ostream& out) const -> void { if (!is_valid()) { IdBase::Print(out); @@ -160,17 +147,27 @@ struct ConstantId : public IdBase, public Printable { } private: + friend class ConstantValueStore; + // TODO: C++23 makes std::abs constexpr, but until then we mirror std::abs // logic here. LLVM should still optimize this. static constexpr auto Abs(int32_t i) -> int32_t { return i > 0 ? i : -i; } + // Returns the instruction that describes this constant value, or + // InstId::Invalid for a runtime value. This is not part of the public + // interface of `ConstantId`. Use `ConstantValueStore::GetInstId` to get the + // instruction ID of a `ConstantId`. + constexpr auto inst_id() const -> InstId { + CARBON_CHECK(is_valid()); + return InstId(Abs(index) - IndexOffset); + } + static constexpr int32_t NotConstantIndex = InvalidIndex - 1; // The offset of InstId indices to ConstantId indices. static constexpr int32_t IndexOffset = -NotConstantIndex + 1; }; constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex); -static_assert(ConstantId::NotConstant.inst_id() == InstId::Invalid); constexpr ConstantId ConstantId::Error = ConstantId::ForTemplateConstant(InstId::BuiltinError); constexpr ConstantId ConstantId::Invalid = ConstantId(InvalidIndex); diff --git a/toolchain/sem_ir/inst_namer.cpp b/toolchain/sem_ir/inst_namer.cpp index afc5a1919246..3cabc4f76160 100644 --- a/toolchain/sem_ir/inst_namer.cpp +++ b/toolchain/sem_ir/inst_namer.cpp @@ -457,9 +457,11 @@ auto InstNamer::CollectNamesInBlock(ScopeId scope_id, // a block. Constants that refer to them need to be separately // named. auto const_id = sem_ir_.constant_values().Get(inst_id); - if (const_id.is_valid() && const_id.is_template() && - !insts[const_id.inst_id().index].second) { - CollectNamesInBlock(ScopeId::ImportRef, const_id.inst_id()); + if (const_id.is_valid() && const_id.is_template()) { + auto const_inst_id = sem_ir_.constant_values().GetInstId(const_id); + if (!insts[const_inst_id.index].second) { + CollectNamesInBlock(ScopeId::ImportRef, const_inst_id); + } } continue; } diff --git a/toolchain/sem_ir/type.h b/toolchain/sem_ir/type.h index 05b9c3933f9b..74b3eab5f3c4 100644 --- a/toolchain/sem_ir/type.h +++ b/toolchain/sem_ir/type.h @@ -6,6 +6,7 @@ #define CARBON_TOOLCHAIN_SEM_IR_TYPE_H_ #include "toolchain/base/value_store.h" +#include "toolchain/sem_ir/constant.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/type_info.h" @@ -15,7 +16,8 @@ namespace Carbon::SemIR { // Provides a ValueStore wrapper with an API specific to types. class TypeStore : public ValueStore { public: - explicit TypeStore(InstStore* insts) : insts_(insts) {} + explicit TypeStore(InstStore* insts, ConstantValueStore* constants) + : insts_(insts), constants_(constants) {} // Returns the ID of the constant used to define the specified type. auto GetConstantId(TypeId type_id) const -> ConstantId { @@ -33,7 +35,7 @@ class TypeStore : public ValueStore { // Returns the ID of the instruction used to define the specified type. auto GetInstId(TypeId type_id) const -> InstId { - return GetConstantId(type_id).inst_id(); + return constants_->GetInstId(GetConstantId(type_id)); } // Returns the instruction used to define the specified type. @@ -56,7 +58,8 @@ class TypeStore : public ValueStore { return GetAsInst(type_id).As(); } else { // The type is not a builtin, so no need to check for special values. - return insts_->Get(Get(type_id).constant_id.inst_id()).As(); + auto inst_id = constants_->GetInstId(Get(type_id).constant_id); + return insts_->GetAs(inst_id); } } @@ -95,6 +98,7 @@ class TypeStore : public ValueStore { private: InstStore* insts_; + ConstantValueStore* constants_; }; } // namespace Carbon::SemIR