Procházet zdrojové kódy

Add unit tagging to FunctionId (#6213)

David Blaikie před 6 měsíci
rodič
revize
1a9826bc29

+ 1 - 1
scripts/lldbinit.py

@@ -86,7 +86,7 @@ Example usage:
         "symbolic_constant": ("SemIR::MakeSymbolicConstantId", DECIMAL),
         "entity_name": ("SemIR::MakeEntityNameId", DECIMAL),
         "facet_type": ("SemIR::MakeFacetTypeId", DECIMAL),
-        "function": ("SemIR::MakeFunctionId", DECIMAL),
+        "function": ("SemIR::MakeFunctionId", HEX),
         "generic": ("SemIR::MakeGenericId", DECIMAL),
         "impl": ("SemIR::MakeImplId", DECIMAL),
         "inst_block": ("SemIR::MakeInstBlockId", DECIMAL),

+ 3 - 1
toolchain/base/fixed_size_value_store.h

@@ -42,7 +42,7 @@ class FixedSizeValueStore {
     requires std::same_as<IdT, typename ValueStoreT::IdType>
   static auto MakeForOverwrite(const ValueStoreT& size_source)
       -> FixedSizeValueStore {
-    FixedSizeValueStore store;
+    FixedSizeValueStore store(size_source.GetIdTag());
     store.values_.resize_for_overwrite(size_source.size());
     return store;
   }
@@ -81,6 +81,8 @@ class FixedSizeValueStore {
     values_.resize(size_source.size(), default_value);
   }
 
+  explicit FixedSizeValueStore(IdTag tag) : tag_(tag) {}
+
   // Makes a ValueStore using a mapped range of `source`. The `factory_fn`
   // receives each enumerated entry for construction of `ValueType`.
   template <typename ValueStoreT>

+ 7 - 5
toolchain/base/value_store.h

@@ -164,9 +164,10 @@ class ValueStore
     static auto MakeFlattenedRange(const ValueStore& store) -> auto {
       // Because indices into `ValueStore` are all sequential values from 0, we
       // can use llvm::seq to walk all indices in the store.
-      return llvm::map_range(
-          llvm::seq(store.size_),
-          [&](int32_t i) -> ConstRefType { return store.Get(IdType(i)); });
+      return llvm::map_range(llvm::seq(store.size_),
+                             [&](int32_t i) -> ConstRefType {
+                               return store.Get(IdType(store.tag_.Apply(i)));
+                             });
     }
 
     using FlattenedRangeType =
@@ -273,8 +274,9 @@ class ValueStore
 
   // Makes an iterable range over references to all values in the ValueStore.
   auto values() [[clang::lifetimebound]] -> auto {
-    return llvm::map_range(
-        llvm::seq(size_), [&](int32_t i) -> RefType { return Get(IdType(i)); });
+    return llvm::map_range(llvm::seq(size_), [&](int32_t i) -> RefType {
+      return Get(IdType(tag_.Apply(i)));
+    });
   }
   auto values() const [[clang::lifetimebound]] -> Range { return Range(*this); }
 

+ 15 - 15
toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon

@@ -55,11 +55,11 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     entity_name1:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:     entity_name2:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name1, parent_scope: name_scope0, call_params_id: inst_block6, body: [inst_block9]}
-// CHECK:STDOUT:     function1:       {name: name4, parent_scope: name_scope1, call_params_id: inst_block_empty}
-// CHECK:STDOUT:     function2:       {name: name6, parent_scope: name_scope1, call_params_id: inst_block_empty}
-// CHECK:STDOUT:     function3:       {name: name4, parent_scope: name_scope1, call_params_id: inst_block13}
-// CHECK:STDOUT:     function4:       {name: name6, parent_scope: name_scope1, call_params_id: inst_block18}
+// CHECK:STDOUT:     function60000000: {name: name1, parent_scope: name_scope0, call_params_id: inst_block6, body: [inst_block9]}
+// CHECK:STDOUT:     function60000001: {name: name4, parent_scope: name_scope1, call_params_id: inst_block_empty}
+// CHECK:STDOUT:     function60000002: {name: name6, parent_scope: name_scope1, call_params_id: inst_block_empty}
+// CHECK:STDOUT:     function60000003: {name: name4, parent_scope: name_scope1, call_params_id: inst_block13}
+// CHECK:STDOUT:     function60000004: {name: name6, parent_scope: name_scope1, call_params_id: inst_block18}
 // CHECK:STDOUT:   classes:
 // CHECK:STDOUT:     class60000000:   {name: name3, parent_scope: name_scope1, self_type_id: type(inst60000013), inheritance_kind: Base, is_dynamic: 0, scope_id: name_scope2, body_block_id: inst_block10, adapt_id: inst<none>, base_id: inst<none>, complete_type_witness_id: inst60000021, vtable_decl_id: inst<none>}}
 // CHECK:STDOUT:   generics:        {}
@@ -125,8 +125,8 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst60000018:    {kind: ValueParamPattern, arg0: inst60000017, arg1: call_param0, type: type(inst60000016)}
 // CHECK:STDOUT:     inst60000019:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst60000013)}
 // CHECK:STDOUT:     inst6000001A:    {kind: SpliceBlock, arg0: inst_block4, arg1: inst60000014, type: type(TypeType)}
-// CHECK:STDOUT:     inst6000001B:    {kind: FunctionDecl, arg0: function0, arg1: inst_block8, type: type(inst6000001C)}
-// CHECK:STDOUT:     inst6000001C:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000001B:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block8, type: type(inst6000001C)}
+// CHECK:STDOUT:     inst6000001C:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001D:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001E:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000001C)}
 // CHECK:STDOUT:     inst6000001F:    {kind: CustomLayoutType, arg0: struct_type_fields0, arg1: custom_layout1, type: type(TypeType)}
@@ -139,11 +139,11 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst60000026:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000025)}
 // CHECK:STDOUT:     inst60000027:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000025)}
 // CHECK:STDOUT:     inst60000028:    {kind: NameRef, arg0: name4, arg1: inst60000026, type: type(inst60000025)}
-// CHECK:STDOUT:     inst60000029:    {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst6000002A)}
-// CHECK:STDOUT:     inst6000002A:    {kind: FunctionType, arg0: function1, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000029:    {kind: FunctionDecl, arg0: function60000001, arg1: inst_block_empty, type: type(inst6000002A)}
+// CHECK:STDOUT:     inst6000002A:    {kind: FunctionType, arg0: function60000001, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000002B:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000002A)}
-// CHECK:STDOUT:     inst6000002C:    {kind: FunctionDecl, arg0: function2, arg1: inst_block_empty, type: type(inst6000002D)}
-// CHECK:STDOUT:     inst6000002D:    {kind: FunctionType, arg0: function2, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000002C:    {kind: FunctionDecl, arg0: function60000002, arg1: inst_block_empty, type: type(inst6000002D)}
+// CHECK:STDOUT:     inst6000002D:    {kind: FunctionType, arg0: function60000002, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000002E:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000002D)}
 // CHECK:STDOUT:     inst6000002F:    {kind: Call, arg0: inst6000002C, arg1: inst_block_empty, type: type(inst6000001D)}
 // CHECK:STDOUT:     inst60000030:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
@@ -153,8 +153,8 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst60000034:    {kind: BindingPattern, arg0: entity_name1, type: type(inst60000016)}
 // CHECK:STDOUT:     inst60000035:    {kind: ValueParamPattern, arg0: inst60000034, arg1: call_param0, type: type(inst60000016)}
 // CHECK:STDOUT:     inst60000036:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst60000013)}
-// CHECK:STDOUT:     inst60000037:    {kind: FunctionDecl, arg0: function3, arg1: inst_block15, type: type(inst60000038)}
-// CHECK:STDOUT:     inst60000038:    {kind: FunctionType, arg0: function3, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000037:    {kind: FunctionDecl, arg0: function60000003, arg1: inst_block15, type: type(inst60000038)}
+// CHECK:STDOUT:     inst60000038:    {kind: FunctionType, arg0: function60000003, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000039:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000038)}
 // CHECK:STDOUT:     inst6000003A:    {kind: PointerType, arg0: inst60000013, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000003B:    {kind: BindName, arg0: entity_name2, arg1: inst6000003F, type: type(inst6000003A)}
@@ -162,8 +162,8 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst6000003D:    {kind: BindingPattern, arg0: entity_name2, type: type(inst6000003C)}
 // CHECK:STDOUT:     inst6000003E:    {kind: ValueParamPattern, arg0: inst6000003D, arg1: call_param0, type: type(inst6000003C)}
 // CHECK:STDOUT:     inst6000003F:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst6000003A)}
-// CHECK:STDOUT:     inst60000040:    {kind: FunctionDecl, arg0: function4, arg1: inst_block20, type: type(inst60000041)}
-// CHECK:STDOUT:     inst60000041:    {kind: FunctionType, arg0: function4, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000040:    {kind: FunctionDecl, arg0: function60000004, arg1: inst_block20, type: type(inst60000041)}
+// CHECK:STDOUT:     inst60000041:    {kind: FunctionType, arg0: function60000004, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000042:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000041)}
 // CHECK:STDOUT:     inst60000043:    {kind: ValueAsRef, arg0: inst60000032, type: type(inst60000013)}
 // CHECK:STDOUT:     inst60000044:    {kind: AddrOf, arg0: inst60000043, type: type(inst6000003A)}

+ 9 - 9
toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon

@@ -39,7 +39,7 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst6000000F}}
 // CHECK:STDOUT:   entity_names:    {}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
+// CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
@@ -58,8 +58,8 @@ fn B() {
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst60000011)}
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     inst0000000E:    {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst6000000F:    {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst60000010)}
-// CHECK:STDOUT:     inst60000010:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000000F:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block_empty, type: type(inst60000010)}
+// CHECK:STDOUT:     inst60000010:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000011:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000012:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000010)}
 // CHECK:STDOUT:     inst60000013:    {kind: Return}
@@ -101,8 +101,8 @@ fn B() {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
-// CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
+// CHECK:STDOUT:     function50000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
+// CHECK:STDOUT:     function50000001: {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
@@ -123,14 +123,14 @@ fn B() {
 // CHECK:STDOUT:     inst0000000E:    {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst5000000F:    {kind: ImportDecl, arg0: name1}
 // CHECK:STDOUT:     inst50000010:    {kind: Namespace, arg0: name_scope1, arg1: inst5000000F, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst50000011:    {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst50000012)}
-// CHECK:STDOUT:     inst50000012:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst50000011:    {kind: FunctionDecl, arg0: function50000000, arg1: inst_block_empty, type: type(inst50000012)}
+// CHECK:STDOUT:     inst50000012:    {kind: FunctionType, arg0: function50000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000013:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000014:    {kind: StructValue, arg0: inst_block_empty, type: type(inst50000012)}
 // CHECK:STDOUT:     inst50000015:    {kind: NameRef, arg0: name1, arg1: inst50000010, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst50000016:    {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst50000018)}
-// CHECK:STDOUT:     inst50000017:    {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst50000018)}
-// CHECK:STDOUT:     inst50000018:    {kind: FunctionType, arg0: function1, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst50000017:    {kind: FunctionDecl, arg0: function50000001, arg1: inst_block_empty, type: type(inst50000018)}
+// CHECK:STDOUT:     inst50000018:    {kind: FunctionType, arg0: function50000001, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000019:    {kind: StructValue, arg0: inst_block_empty, type: type(inst50000018)}
 // CHECK:STDOUT:     inst5000001A:    {kind: NameRef, arg0: name1, arg1: inst50000016, type: type(inst50000018)}
 // CHECK:STDOUT:     inst5000001B:    {kind: Call, arg0: inst5000001A, arg1: inst_block_empty, type: type(inst50000013)}

+ 9 - 9
toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon

@@ -39,7 +39,7 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst6000000F}}
 // CHECK:STDOUT:   entity_names:    {}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
+// CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
@@ -58,8 +58,8 @@ fn B() {
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst60000011)}
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     inst0000000E:    {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst6000000F:    {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst60000010)}
-// CHECK:STDOUT:     inst60000010:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000000F:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block_empty, type: type(inst60000010)}
+// CHECK:STDOUT:     inst60000010:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000011:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000012:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000010)}
 // CHECK:STDOUT:     inst60000013:    {kind: Return}
@@ -120,8 +120,8 @@ fn B() {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
-// CHECK:STDOUT:     function1:       {name: name1, parent_scope: name_scope1}
+// CHECK:STDOUT:     function50000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
+// CHECK:STDOUT:     function50000001: {name: name1, parent_scope: name_scope1}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
@@ -142,14 +142,14 @@ fn B() {
 // CHECK:STDOUT:     inst0000000E:    {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst5000000F:    {kind: ImportDecl, arg0: name1}
 // CHECK:STDOUT:     inst50000010:    {kind: Namespace, arg0: name_scope1, arg1: inst5000000F, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst50000011:    {kind: FunctionDecl, arg0: function0, arg1: inst_block_empty, type: type(inst50000012)}
-// CHECK:STDOUT:     inst50000012:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst50000011:    {kind: FunctionDecl, arg0: function50000000, arg1: inst_block_empty, type: type(inst50000012)}
+// CHECK:STDOUT:     inst50000012:    {kind: FunctionType, arg0: function50000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000013:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000014:    {kind: StructValue, arg0: inst_block_empty, type: type(inst50000012)}
 // CHECK:STDOUT:     inst50000015:    {kind: NameRef, arg0: name1, arg1: inst50000010, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst50000016:    {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: entity_name0, type: type(inst50000018)}
-// CHECK:STDOUT:     inst50000017:    {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst50000018)}
-// CHECK:STDOUT:     inst50000018:    {kind: FunctionType, arg0: function1, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst50000017:    {kind: FunctionDecl, arg0: function50000001, arg1: inst_block_empty, type: type(inst50000018)}
+// CHECK:STDOUT:     inst50000018:    {kind: FunctionType, arg0: function50000001, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst50000019:    {kind: StructValue, arg0: inst_block_empty, type: type(inst50000018)}
 // CHECK:STDOUT:     inst5000001A:    {kind: NameRef, arg0: name1, arg1: inst50000016, type: type(inst50000018)}
 // CHECK:STDOUT:     inst5000001B:    {kind: Call, arg0: inst5000001A, arg1: inst_block_empty, type: type(inst50000013)}

+ 22 - 22
toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon

@@ -295,12 +295,12 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     entity_name60:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:     entity_name61:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block13, return_slot_pattern: inst60000030, body: [inst_block20]}
-// CHECK:STDOUT:     function1:       {name: name4, parent_scope: name_scope2, return_slot_pattern: inst60000055}
-// CHECK:STDOUT:     function2:       {name: name4, parent_scope: name_scope3, return_slot_pattern: inst60000073}
-// CHECK:STDOUT:     function3:       {name: name4, parent_scope: name_scope8, return_slot_pattern: inst600000AA}
-// CHECK:STDOUT:     function4:       {name: name4, parent_scope: name_scope11, return_slot_pattern: inst600000D5}
-// CHECK:STDOUT:     function5:       {name: name4, parent_scope: name_scope12, return_slot_pattern: inst60000111}
+// CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block13, return_slot_pattern: inst60000030, body: [inst_block20]}
+// CHECK:STDOUT:     function60000001: {name: name4, parent_scope: name_scope2, return_slot_pattern: inst60000055}
+// CHECK:STDOUT:     function60000002: {name: name4, parent_scope: name_scope3, return_slot_pattern: inst60000073}
+// CHECK:STDOUT:     function60000003: {name: name4, parent_scope: name_scope8, return_slot_pattern: inst600000AA}
+// CHECK:STDOUT:     function60000004: {name: name4, parent_scope: name_scope11, return_slot_pattern: inst600000D5}
+// CHECK:STDOUT:     function60000005: {name: name4, parent_scope: name_scope12, return_slot_pattern: inst60000111}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:
 // CHECK:STDOUT:     generic0:        {decl: inst60000035, bindings: inst_block16}
@@ -418,8 +418,8 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst60000032:    {kind: SpliceBlock, arg0: inst_block6, arg1: inst6000001A, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000033:    {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(symbolic_constant8)}
 // CHECK:STDOUT:     inst60000034:    {kind: ReturnSlot, arg0: inst6000002A, arg1: inst60000033, type: type(symbolic_constant8)}
-// CHECK:STDOUT:     inst60000035:    {kind: FunctionDecl, arg0: function0, arg1: inst_block15, type: type(inst60000036)}
-// CHECK:STDOUT:     inst60000036:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000035:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block15, type: type(inst60000036)}
+// CHECK:STDOUT:     inst60000036:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000037:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000036)}
 // CHECK:STDOUT:     inst60000038:    {kind: PointerType, arg0: inst6000002A, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000039:    {kind: RequireCompleteType, arg0: inst6000002A, type: type(inst(WitnessType))}
@@ -444,8 +444,8 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst6000004C:    {kind: AssociatedEntityType, arg0: interface0, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000004D:    {kind: ImportRefLoaded, arg0: import_ir_inst5, arg1: entity_name<none>, type: type(inst60000050)}
 // CHECK:STDOUT:     inst6000004E:    {kind: AssociatedEntity, arg0: element0, arg1: inst6000004D, type: type(inst6000004C)}
-// CHECK:STDOUT:     inst6000004F:    {kind: FunctionDecl, arg0: function1, arg1: inst_block_empty, type: type(inst60000050)}
-// CHECK:STDOUT:     inst60000050:    {kind: FunctionType, arg0: function1, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000004F:    {kind: FunctionDecl, arg0: function60000001, arg1: inst_block_empty, type: type(inst60000050)}
+// CHECK:STDOUT:     inst60000050:    {kind: FunctionType, arg0: function60000001, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000051:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000050)}
 // CHECK:STDOUT:     inst60000052:    {kind: SymbolicBindingType, arg0: entity_name4, arg1: inst60000048, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000053:    {kind: PatternType, arg0: inst60000052, type: type(TypeType)}
@@ -475,8 +475,8 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst6000006B:    {kind: SymbolicBindingType, arg0: entity_name1, arg1: inst6000006A, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000006C:    {kind: ConstType, arg0: inst6000006B, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000006D:    {kind: ImplWitness, arg0: inst60000068, arg1: specific3, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst6000006E:    {kind: FunctionDecl, arg0: function2, arg1: inst_block_empty, type: type(symbolic_constant38)}
-// CHECK:STDOUT:     inst6000006F:    {kind: FunctionType, arg0: function2, arg1: specific2, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000006E:    {kind: FunctionDecl, arg0: function60000002, arg1: inst_block_empty, type: type(symbolic_constant38)}
+// CHECK:STDOUT:     inst6000006F:    {kind: FunctionType, arg0: function60000002, arg1: specific2, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000070:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant38)}
 // CHECK:STDOUT:     inst60000071:    {kind: PatternType, arg0: inst60000061, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000072:    {kind: ReturnSlotPattern, arg0: inst<none>, type: type(symbolic_constant43)}
@@ -484,7 +484,7 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst60000074:    {kind: BindingPattern, arg0: entity_name17, type: type(symbolic_constant43)}
 // CHECK:STDOUT:     inst60000075:    {kind: ValueParamPattern, arg0: inst60000074, arg1: call_param0, type: type(symbolic_constant43)}
 // CHECK:STDOUT:     inst60000076:    {kind: ImportRefLoaded, arg0: import_ir_inst32, arg1: entity_name<none>, type: type(inst60000047)}
-// CHECK:STDOUT:     inst60000077:    {kind: FunctionType, arg0: function2, arg1: specific3, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000077:    {kind: FunctionType, arg0: function60000002, arg1: specific3, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000078:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant45)}
 // CHECK:STDOUT:     inst60000079:    {kind: BindSymbolicName, arg0: entity_name1, arg1: inst<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst6000007A:    {kind: SymbolicBindingType, arg0: entity_name1, arg1: inst60000079, type: type(TypeType)}
@@ -531,15 +531,15 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst600000A3:    {kind: BindSymbolicName, arg0: entity_name1, arg1: inst<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000A4:    {kind: PointerType, arg0: inst600000A3, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000A5:    {kind: ImplWitness, arg0: inst600000A1, arg1: specific8, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst600000A6:    {kind: FunctionDecl, arg0: function3, arg1: inst_block_empty, type: type(symbolic_constant81)}
-// CHECK:STDOUT:     inst600000A7:    {kind: FunctionType, arg0: function3, arg1: specific7, type: type(TypeType)}
+// CHECK:STDOUT:     inst600000A6:    {kind: FunctionDecl, arg0: function60000003, arg1: inst_block_empty, type: type(symbolic_constant81)}
+// CHECK:STDOUT:     inst600000A7:    {kind: FunctionType, arg0: function60000003, arg1: specific7, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000A8:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant81)}
 // CHECK:STDOUT:     inst600000A9:    {kind: ReturnSlotPattern, arg0: inst<none>, type: type(symbolic_constant85)}
 // CHECK:STDOUT:     inst600000AA:    {kind: OutParamPattern, arg0: inst600000A9, arg1: call_param1, type: type(symbolic_constant85)}
 // CHECK:STDOUT:     inst600000AB:    {kind: BindingPattern, arg0: entity_name24, type: type(symbolic_constant85)}
 // CHECK:STDOUT:     inst600000AC:    {kind: ValueParamPattern, arg0: inst600000AB, arg1: call_param0, type: type(symbolic_constant85)}
 // CHECK:STDOUT:     inst600000AD:    {kind: ImportRefLoaded, arg0: import_ir_inst77, arg1: entity_name<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst600000AE:    {kind: FunctionType, arg0: function3, arg1: specific8, type: type(TypeType)}
+// CHECK:STDOUT:     inst600000AE:    {kind: FunctionType, arg0: function60000003, arg1: specific8, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000AF:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant88)}
 // CHECK:STDOUT:     inst600000B0:    {kind: RequireCompleteType, arg0: inst600000A4, type: type(inst(WitnessType))}
 // CHECK:STDOUT:     inst600000B1:    {kind: BindSymbolicName, arg0: entity_name1, arg1: inst<none>, type: type(TypeType)}
@@ -573,8 +573,8 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst600000CD:    {kind: SymbolicBindingType, arg0: entity_name26, arg1: inst600000CB, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000CE:    {kind: TupleType, arg0: inst_block62, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000CF:    {kind: ImplWitness, arg0: inst600000C8, arg1: specific11, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst600000D0:    {kind: FunctionDecl, arg0: function4, arg1: inst_block_empty, type: type(symbolic_constant114)}
-// CHECK:STDOUT:     inst600000D1:    {kind: FunctionType, arg0: function4, arg1: specific10, type: type(TypeType)}
+// CHECK:STDOUT:     inst600000D0:    {kind: FunctionDecl, arg0: function60000004, arg1: inst_block_empty, type: type(symbolic_constant114)}
+// CHECK:STDOUT:     inst600000D1:    {kind: FunctionType, arg0: function60000004, arg1: specific10, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000D2:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant114)}
 // CHECK:STDOUT:     inst600000D3:    {kind: PatternType, arg0: inst600000C0, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000D4:    {kind: ReturnSlotPattern, arg0: inst<none>, type: type(symbolic_constant119)}
@@ -583,7 +583,7 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst600000D7:    {kind: ValueParamPattern, arg0: inst600000D6, arg1: call_param0, type: type(symbolic_constant119)}
 // CHECK:STDOUT:     inst600000D8:    {kind: ImportRefLoaded, arg0: import_ir_inst113, arg1: entity_name<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst600000D9:    {kind: ImportRefLoaded, arg0: import_ir_inst114, arg1: entity_name<none>, type: type(inst60000047)}
-// CHECK:STDOUT:     inst600000DA:    {kind: FunctionType, arg0: function4, arg1: specific11, type: type(TypeType)}
+// CHECK:STDOUT:     inst600000DA:    {kind: FunctionType, arg0: function60000004, arg1: specific11, type: type(TypeType)}
 // CHECK:STDOUT:     inst600000DB:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant121)}
 // CHECK:STDOUT:     inst600000DC:    {kind: BindSymbolicName, arg0: entity_name1, arg1: inst<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst600000DD:    {kind: SymbolicBindingType, arg0: entity_name1, arg1: inst600000DC, type: type(TypeType)}
@@ -633,8 +633,8 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst60000109:    {kind: SymbolicBindingType, arg0: entity_name41, arg1: inst60000106, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000010A:    {kind: TupleType, arg0: inst_block84, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000010B:    {kind: ImplWitness, arg0: inst60000102, arg1: specific17, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst6000010C:    {kind: FunctionDecl, arg0: function5, arg1: inst_block_empty, type: type(symbolic_constant186)}
-// CHECK:STDOUT:     inst6000010D:    {kind: FunctionType, arg0: function5, arg1: specific16, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000010C:    {kind: FunctionDecl, arg0: function60000005, arg1: inst_block_empty, type: type(symbolic_constant186)}
+// CHECK:STDOUT:     inst6000010D:    {kind: FunctionType, arg0: function60000005, arg1: specific16, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000010E:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant186)}
 // CHECK:STDOUT:     inst6000010F:    {kind: PatternType, arg0: inst600000F8, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000110:    {kind: ReturnSlotPattern, arg0: inst<none>, type: type(symbolic_constant191)}
@@ -644,7 +644,7 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     inst60000114:    {kind: ImportRefLoaded, arg0: import_ir_inst159, arg1: entity_name<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst60000115:    {kind: ImportRefLoaded, arg0: import_ir_inst160, arg1: entity_name<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst60000116:    {kind: ImportRefLoaded, arg0: import_ir_inst161, arg1: entity_name<none>, type: type(inst60000047)}
-// CHECK:STDOUT:     inst60000117:    {kind: FunctionType, arg0: function5, arg1: specific17, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000117:    {kind: FunctionType, arg0: function60000005, arg1: specific17, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000118:    {kind: StructValue, arg0: inst_block_empty, type: type(symbolic_constant193)}
 // CHECK:STDOUT:     inst60000119:    {kind: BindSymbolicName, arg0: entity_name1, arg1: inst<none>, type: type(inst60000047)}
 // CHECK:STDOUT:     inst6000011A:    {kind: SymbolicBindingType, arg0: entity_name1, arg1: inst60000119, type: type(TypeType)}

+ 3 - 3
toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon

@@ -30,7 +30,7 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:   entity_names:
 // CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function0:       {name: name0, parent_scope: name_scope0, call_params_id: inst_block9, return_slot_pattern: inst60000020, body: [inst_block12]}
+// CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block9, return_slot_pattern: inst60000020, body: [inst_block12]}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
@@ -75,8 +75,8 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:     inst60000022:    {kind: SpliceBlock, arg0: inst_block4, arg1: inst60000011, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000023:    {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(inst60000018)}
 // CHECK:STDOUT:     inst60000024:    {kind: ReturnSlot, arg0: inst60000018, arg1: inst60000023, type: type(inst60000018)}
-// CHECK:STDOUT:     inst60000025:    {kind: FunctionDecl, arg0: function0, arg1: inst_block11, type: type(inst60000026)}
-// CHECK:STDOUT:     inst60000026:    {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000025:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block11, type: type(inst60000026)}
+// CHECK:STDOUT:     inst60000026:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000027:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000026)}
 // CHECK:STDOUT:     inst60000028:    {kind: NameRef, arg0: name1, arg1: inst60000012, type: type(inst6000000F)}
 // CHECK:STDOUT:     inst60000029:    {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst6000000F)}

+ 1 - 1
toolchain/check/testdata/basics/verbose.carbon

@@ -14,7 +14,7 @@
 // SET-CHECK-SUBSET
 // CHECK:STDERR: Node Push 0: FunctionIntroducer -> <none>
 // CHECK:STDERR: AddPlaceholderInst: {kind: FunctionDecl, arg0: function<none>, arg1: inst_block_empty}
-// CHECK:STDERR: ReplaceInst: inst{{[0-9A-F]+}} -> {kind: FunctionDecl, arg0: function{{[0-9]+}}, arg1: inst_block_empty, type: type(inst{{[0-9A-F]+}})}
+// CHECK:STDERR: ReplaceInst: inst{{[0-9A-F]+}} -> {kind: FunctionDecl, arg0: function{{[0-9A-F]+}}, arg1: inst_block_empty, type: type(inst{{[0-9A-F]+}})}
 // CHECK:STDERR: inst_block_stack_ Push 1
 // CHECK:STDERR: AddInst: {kind: Return}
 // CHECK:STDERR: inst_block_stack_ Pop 1: inst_block{{[0-9]+}}

+ 1 - 0
toolchain/sem_ir/file.cpp

@@ -35,6 +35,7 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id,
                                  : LibraryNameId::Default),
       value_stores_(&value_stores),
       filename_(std::move(filename)),
+      functions_(IdTag(check_ir_id.index, 0)),
       cpp_overload_sets_(IdTag(check_ir_id.index, 0)),
       classes_(IdTag(check_ir_id.index, 0)),
       associated_constants_(IdTag(check_ir_id.index, 0)),

+ 4 - 0
toolchain/sem_ir/ids.cpp

@@ -46,6 +46,10 @@ auto CppOverloadSetId::Print(llvm::raw_ostream& out) const -> void {
   IdBase::PrintHex(out);
 }
 
+auto FunctionId::Print(llvm::raw_ostream& out) const -> void {
+  IdBase::PrintHex(out);
+}
+
 auto CheckIRId::Print(llvm::raw_ostream& out) const -> void {
   if (*this == Cpp) {
     out << Label << "(Cpp)";

+ 2 - 0
toolchain/sem_ir/ids.h

@@ -285,6 +285,8 @@ struct FunctionId : public IdBase<FunctionId> {
   static constexpr llvm::StringLiteral Label = "function";
 
   using IdBase::IdBase;
+
+  auto Print(llvm::raw_ostream& out) const -> void;
 };
 
 // The ID of an IR within the set of all IRs being evaluated in the current

+ 2 - 0
toolchain/sem_ir/inst_namer.h

@@ -57,6 +57,8 @@ class InstNamer {
       index = sem_ir_->cpp_overload_sets().GetRawIndex(id);
     } else if constexpr (std::is_same_v<IdT, AssociatedConstantId>) {
       index = sem_ir_->associated_constants().GetRawIndex(id);
+    } else if constexpr (std::is_same_v<IdT, FunctionId>) {
+      index = sem_ir_->functions().GetRawIndex(id);
     }
     return static_cast<ScopeId>(GetScopeIdOffset(ScopeIdTypeEnum::For<IdT>) +
                                 index);

+ 1 - 1
toolchain/sem_ir/yaml_test.cpp

@@ -82,7 +82,7 @@ TEST(SemIRTest, Yaml) {
                         Contains(Pair(_, Yaml::Mapping(ElementsAre(
 
                                              Pair("kind", "FunctionDecl"),
-                                             Pair("arg0", "function0"),
+                                             Pair("arg0", "function60000000"),
                                              Pair("arg1", "inst_block_empty"),
                                              Pair("type", type_id)))))))),
       Pair("constant_values",