Răsfoiți Sursa

Make ConstantValueStore use ValueStore internally (#5811)

This changes ConstantValueStore to use ValueStore so that we get the
allocation flow that we're leaning towards there. This adds
`ConstantId::SymbolicId` to represent what was previously an int32
"symbolic_index" (although called an index, it's consistent with ID
usages).

I'm also changing Chunk::at/push to be consistent with the wrapping
Get/Add naming; the naming difference sticks out more with
UninitializedFill being added.
Jon Ross-Perkins 9 luni în urmă
părinte
comite
61290fdee9

+ 55 - 18
toolchain/base/value_store.h

@@ -8,6 +8,7 @@
 #include <bit>
 #include <cstddef>
 #include <limits>
+#include <memory>
 #include <type_traits>
 #include <utility>
 
@@ -92,7 +93,7 @@ class ValueStore
     }
 
     CARBON_DCHECK(pos == chunks_[chunk_index].size());
-    chunks_[chunk_index].push(std::move(value));
+    chunks_[chunk_index].Add(std::move(value));
     return id;
   }
 
@@ -101,7 +102,7 @@ class ValueStore
     CARBON_DCHECK(id.index >= 0, "{0}", id);
     CARBON_DCHECK(id.index < size_, "{0}", id);
     auto [chunk_index, pos] = IdToChunkIndices(id);
-    return chunks_[chunk_index].at(pos);
+    return chunks_[chunk_index].Get(pos);
   }
 
   // Returns the value for an ID.
@@ -109,20 +110,47 @@ class ValueStore
     CARBON_DCHECK(id.index >= 0, "{0}", id);
     CARBON_DCHECK(id.index < size_, "{0}", id);
     auto [chunk_index, pos] = IdToChunkIndices(id);
-    return chunks_[chunk_index].at(pos);
+    return chunks_[chunk_index].Get(pos);
   }
 
   // Reserves space.
-  auto Reserve(size_t size) -> void {
-    // We get the number of chunks needed to satisfy `size` by rounding any
-    // partial result up.
-    size_t num_more_chunks = (size + Chunk::Capacity() - 1) / Chunk::Capacity();
-    if (chunks_.size() < num_more_chunks) {
-      // We resize() rather than reserve() here to create the new `ChunkType`
-      // objects, which will in turn allocate space for values in those chunks
-      // (but not initialize them).
-      chunks_.resize(num_more_chunks);
+  auto Reserve(int32_t size) -> void {
+    if (size <= size_) {
+      return;
     }
+    auto [final_chunk_index, _] = IdToChunkIndices(IdType(size - 1));
+    chunks_.resize(final_chunk_index + 1);
+  }
+
+  // Grows the ValueStore to `size`. Fills entries with `default_value`.
+  auto Resize(int32_t size, ConstRefType default_value) -> void {
+    if (size <= size_) {
+      return;
+    }
+
+    auto [begin_chunk_index, begin_pos] = IdToChunkIndices(IdType(size_));
+    // Use an inclusive range so that if `size` would be the next chunk, we
+    // don't try doing something with it.
+    auto [end_chunk_index, end_pos] = IdToChunkIndices(IdType(size - 1));
+    chunks_.resize(end_chunk_index + 1);
+
+    // If the begin and end chunks are the same, we only fill from begin to end.
+    if (begin_chunk_index == end_chunk_index) {
+      chunks_[begin_chunk_index].UninitializedFill(end_pos - begin_pos + 1,
+                                                   default_value);
+    } else {
+      // Otherwise, we do partial fills on the begin and end chunk, and full
+      // fills on intermediate chunks.
+      chunks_[begin_chunk_index].UninitializedFill(
+          Chunk::Capacity() - begin_pos, default_value);
+      for (auto i = begin_chunk_index + 1; i < end_chunk_index; ++i) {
+        chunks_[i].UninitializedFill(Chunk::Capacity(), default_value);
+      }
+      chunks_[end_chunk_index].UninitializedFill(end_pos + 1, default_value);
+    }
+
+    // Update size.
+    size_ = size;
   }
 
   // These are to support printable structures, and are not guaranteed.
@@ -246,21 +274,30 @@ class ValueStore
       }
     }
 
-    auto at(int32_t i) -> ValueType& {
-      CARBON_CHECK(i < num_, "{0}", i);
+    auto Get(int32_t i) -> ValueType& {
+      CARBON_DCHECK(i < num_, "{0}", i);
       return buf_[i];
     }
-    auto at(int32_t i) const -> const ValueType& {
-      CARBON_CHECK(i < num_, "{0}", i);
+    auto Get(int32_t i) const -> const ValueType& {
+      CARBON_DCHECK(i < num_, "{0}", i);
       return buf_[i];
     }
 
-    auto push(ValueType&& value) -> void {
-      CARBON_CHECK(num_ < Capacity());
+    auto Add(ValueType&& value) -> void {
+      CARBON_DCHECK(num_ < Capacity());
       std::construct_at(buf_ + num_, std::move(value));
       ++num_;
     }
 
+    // Fills `fill_count` entries with `default_value`, increasing the size
+    // respectively.
+    auto UninitializedFill(int32_t fill_count, ConstRefType default_value)
+        -> void {
+      CARBON_DCHECK(num_ + fill_count <= Capacity());
+      std::uninitialized_fill_n(buf_ + num_, fill_count, default_value);
+      num_ += fill_count;
+    }
+
     auto size() const -> int32_t { return num_; }
 
    private:

+ 17 - 16
toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon

@@ -51,22 +51,23 @@
 // CHECK:STDOUT:     'inst(WitnessType)': {kind: WitnessType, type: type(TypeType)}
 // CHECK:STDOUT:     inst14:          {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     'inst(TypeType)':  concrete_constant(inst(TypeType))
-// CHECK:STDOUT:     'inst(AutoType)':  concrete_constant(inst(AutoType))
-// CHECK:STDOUT:     'inst(BoolType)':  concrete_constant(inst(BoolType))
-// CHECK:STDOUT:     'inst(BoundMethodType)': concrete_constant(inst(BoundMethodType))
-// CHECK:STDOUT:     'inst(ErrorInst)': concrete_constant(inst(ErrorInst))
-// CHECK:STDOUT:     'inst(ImplWitnessTablePlaceholder)': concrete_constant(inst(ImplWitnessTablePlaceholder))
-// CHECK:STDOUT:     'inst(InstType)':  concrete_constant(inst(InstType))
-// CHECK:STDOUT:     'inst(IntLiteralType)': concrete_constant(inst(IntLiteralType))
-// CHECK:STDOUT:     'inst(LegacyFloatType)': concrete_constant(inst(LegacyFloatType))
-// CHECK:STDOUT:     'inst(NamespaceType)': concrete_constant(inst(NamespaceType))
-// CHECK:STDOUT:     'inst(SpecificFunctionType)': concrete_constant(inst(SpecificFunctionType))
-// CHECK:STDOUT:     'inst(StringType)': concrete_constant(inst(StringType))
-// CHECK:STDOUT:     'inst(VtableType)': concrete_constant(inst(VtableType))
-// CHECK:STDOUT:     'inst(WitnessType)': concrete_constant(inst(WitnessType))
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       'inst(TypeType)':  concrete_constant(inst(TypeType))
+// CHECK:STDOUT:       'inst(AutoType)':  concrete_constant(inst(AutoType))
+// CHECK:STDOUT:       'inst(BoolType)':  concrete_constant(inst(BoolType))
+// CHECK:STDOUT:       'inst(BoundMethodType)': concrete_constant(inst(BoundMethodType))
+// CHECK:STDOUT:       'inst(ErrorInst)': concrete_constant(inst(ErrorInst))
+// CHECK:STDOUT:       'inst(ImplWitnessTablePlaceholder)': concrete_constant(inst(ImplWitnessTablePlaceholder))
+// CHECK:STDOUT:       'inst(InstType)':  concrete_constant(inst(InstType))
+// CHECK:STDOUT:       'inst(IntLiteralType)': concrete_constant(inst(IntLiteralType))
+// CHECK:STDOUT:       'inst(LegacyFloatType)': concrete_constant(inst(LegacyFloatType))
+// CHECK:STDOUT:       'inst(NamespaceType)': concrete_constant(inst(NamespaceType))
+// CHECK:STDOUT:       'inst(SpecificFunctionType)': concrete_constant(inst(SpecificFunctionType))
+// CHECK:STDOUT:       'inst(StringType)': concrete_constant(inst(StringType))
+// CHECK:STDOUT:       'inst(VtableType)': concrete_constant(inst(VtableType))
+// CHECK:STDOUT:       'inst(WitnessType)': concrete_constant(inst(WitnessType))
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:         {}

+ 21 - 19
toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon

@@ -63,12 +63,13 @@ fn B() {
 // CHECK:STDOUT:     inst18:          {kind: StructValue, arg0: inst_block_empty, type: type(inst16)}
 // CHECK:STDOUT:     inst19:          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst15:          concrete_constant(inst18)
-// CHECK:STDOUT:     inst16:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst17:          concrete_constant(inst17)
-// CHECK:STDOUT:     inst18:          concrete_constant(inst18)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst15:          concrete_constant(inst18)
+// CHECK:STDOUT:       inst16:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst17:          concrete_constant(inst17)
+// CHECK:STDOUT:       inst18:          concrete_constant(inst18)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
@@ -135,19 +136,20 @@ fn B() {
 // CHECK:STDOUT:     inst27:          {kind: Call, arg0: inst26, arg1: inst_block_empty, type: type(inst19)}
 // CHECK:STDOUT:     inst28:          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst16:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst17:          concrete_constant(inst20)
-// CHECK:STDOUT:     inst18:          concrete_constant(inst18)
-// CHECK:STDOUT:     inst19:          concrete_constant(inst19)
-// CHECK:STDOUT:     inst20:          concrete_constant(inst20)
-// CHECK:STDOUT:     inst21:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst22:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst23:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst24:          concrete_constant(inst24)
-// CHECK:STDOUT:     inst25:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst26:          concrete_constant(inst25)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst16:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst17:          concrete_constant(inst20)
+// CHECK:STDOUT:       inst18:          concrete_constant(inst18)
+// CHECK:STDOUT:       inst19:          concrete_constant(inst19)
+// CHECK:STDOUT:       inst20:          concrete_constant(inst20)
+// CHECK:STDOUT:       inst21:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst22:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst23:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst24:          concrete_constant(inst24)
+// CHECK:STDOUT:       inst25:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst26:          concrete_constant(inst25)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:

+ 21 - 19
toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon

@@ -63,12 +63,13 @@ fn B() {
 // CHECK:STDOUT:     inst18:          {kind: StructValue, arg0: inst_block_empty, type: type(inst16)}
 // CHECK:STDOUT:     inst19:          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst15:          concrete_constant(inst18)
-// CHECK:STDOUT:     inst16:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst17:          concrete_constant(inst17)
-// CHECK:STDOUT:     inst18:          concrete_constant(inst18)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst15:          concrete_constant(inst18)
+// CHECK:STDOUT:       inst16:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst17:          concrete_constant(inst17)
+// CHECK:STDOUT:       inst18:          concrete_constant(inst18)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:
@@ -154,19 +155,20 @@ fn B() {
 // CHECK:STDOUT:     inst27:          {kind: Call, arg0: inst26, arg1: inst_block_empty, type: type(inst19)}
 // CHECK:STDOUT:     inst28:          {kind: Return}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst16:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst17:          concrete_constant(inst20)
-// CHECK:STDOUT:     inst18:          concrete_constant(inst18)
-// CHECK:STDOUT:     inst19:          concrete_constant(inst19)
-// CHECK:STDOUT:     inst20:          concrete_constant(inst20)
-// CHECK:STDOUT:     inst21:          concrete_constant(inst16)
-// CHECK:STDOUT:     inst22:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst23:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst24:          concrete_constant(inst24)
-// CHECK:STDOUT:     inst25:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst26:          concrete_constant(inst25)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst16:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst17:          concrete_constant(inst20)
+// CHECK:STDOUT:       inst18:          concrete_constant(inst18)
+// CHECK:STDOUT:       inst19:          concrete_constant(inst19)
+// CHECK:STDOUT:       inst20:          concrete_constant(inst20)
+// CHECK:STDOUT:       inst21:          concrete_constant(inst16)
+// CHECK:STDOUT:       inst22:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst23:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst24:          concrete_constant(inst24)
+// CHECK:STDOUT:       inst25:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst26:          concrete_constant(inst25)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:

+ 52 - 51
toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon

@@ -115,57 +115,58 @@ fn Foo[T:! type](n: T) -> (T, ()) {
 // CHECK:STDOUT:     inst64:          {kind: Converted, arg0: inst54, arg1: inst63, type: type(symbolic_constant5)}
 // CHECK:STDOUT:     inst65:          {kind: ReturnExpr, arg0: inst64, arg1: inst41}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst15:          symbolic_constant0
-// CHECK:STDOUT:     inst16:          symbolic_constant0
-// CHECK:STDOUT:     inst17:          symbolic_constant0
-// CHECK:STDOUT:     inst18:          concrete_constant(inst18)
-// CHECK:STDOUT:     inst19:          concrete_constant(inst19)
-// CHECK:STDOUT:     inst20:          symbolic_constant0
-// CHECK:STDOUT:     inst22:          symbolic_constant2
-// CHECK:STDOUT:     inst23:          concrete_constant(inst23)
-// CHECK:STDOUT:     inst24:          symbolic_constant2
-// CHECK:STDOUT:     inst25:          concrete_constant(inst25)
-// CHECK:STDOUT:     inst26:          symbolic_constant0
-// CHECK:STDOUT:     inst27:          concrete_constant(inst27)
-// CHECK:STDOUT:     inst29:          concrete_constant(inst29)
-// CHECK:STDOUT:     inst31:          concrete_constant(inst27)
-// CHECK:STDOUT:     inst32:          symbolic_constant4
-// CHECK:STDOUT:     inst33:          symbolic_constant4
-// CHECK:STDOUT:     inst34:          symbolic_constant4
-// CHECK:STDOUT:     inst35:          symbolic_constant6
-// CHECK:STDOUT:     inst36:          concrete_constant(inst36)
-// CHECK:STDOUT:     inst37:          symbolic_constant6
-// CHECK:STDOUT:     inst38:          concrete_constant(inst38)
-// CHECK:STDOUT:     inst42:          concrete_constant(inst44)
-// CHECK:STDOUT:     inst43:          concrete_constant(inst43)
-// CHECK:STDOUT:     inst44:          concrete_constant(inst44)
-// CHECK:STDOUT:     inst45:          symbolic_constant8
-// CHECK:STDOUT:     inst46:          symbolic_constant9
-// CHECK:STDOUT:     inst47:          symbolic_constant9
-// CHECK:STDOUT:     inst48:          symbolic_constant9
-// CHECK:STDOUT:     inst49:          symbolic_constant11
-// CHECK:STDOUT:     inst50:          symbolic_constant11
-// CHECK:STDOUT:     inst51:          symbolic_constant11
-// CHECK:STDOUT:     inst55:          symbolic_constant9
-// CHECK:STDOUT:     inst57:          symbolic_constant11
-// CHECK:STDOUT:     inst60:          concrete_constant(inst61)
-// CHECK:STDOUT:     inst61:          concrete_constant(inst61)
-// CHECK:STDOUT:     inst62:          concrete_constant(inst61)
-// CHECK:STDOUT:   symbolic_constants:
-// CHECK:STDOUT:     symbolic_constant0: {inst: inst16, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant1: {inst: inst16, generic: generic0, index: generic_inst_in_decl0, kind: checked}
-// CHECK:STDOUT:     symbolic_constant2: {inst: inst22, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant3: {inst: inst22, generic: generic0, index: generic_inst_in_decl1, kind: checked}
-// CHECK:STDOUT:     symbolic_constant4: {inst: inst32, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant5: {inst: inst32, generic: generic0, index: generic_inst_in_decl2, kind: checked}
-// CHECK:STDOUT:     symbolic_constant6: {inst: inst35, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant7: {inst: inst35, generic: generic0, index: generic_inst_in_decl3, kind: checked}
-// CHECK:STDOUT:     symbolic_constant8: {inst: inst45, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant9: {inst: inst47, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant10: {inst: inst47, generic: generic0, index: generic_inst_in_def0, kind: checked}
-// CHECK:STDOUT:     symbolic_constant11: {inst: inst50, generic: generic<none>, index: generic_inst<none>, kind: checked}
-// CHECK:STDOUT:     symbolic_constant12: {inst: inst50, generic: generic0, index: generic_inst_in_def1, kind: checked}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst15:          symbolic_constant1
+// CHECK:STDOUT:       inst16:          symbolic_constant0
+// CHECK:STDOUT:       inst17:          symbolic_constant1
+// CHECK:STDOUT:       inst18:          concrete_constant(inst18)
+// CHECK:STDOUT:       inst19:          concrete_constant(inst19)
+// CHECK:STDOUT:       inst20:          symbolic_constant1
+// CHECK:STDOUT:       inst22:          symbolic_constant2
+// CHECK:STDOUT:       inst23:          concrete_constant(inst23)
+// CHECK:STDOUT:       inst24:          symbolic_constant3
+// CHECK:STDOUT:       inst25:          concrete_constant(inst25)
+// CHECK:STDOUT:       inst26:          symbolic_constant1
+// CHECK:STDOUT:       inst27:          concrete_constant(inst27)
+// CHECK:STDOUT:       inst29:          concrete_constant(inst29)
+// CHECK:STDOUT:       inst31:          concrete_constant(inst27)
+// CHECK:STDOUT:       inst32:          symbolic_constant4
+// CHECK:STDOUT:       inst33:          symbolic_constant5
+// CHECK:STDOUT:       inst34:          symbolic_constant5
+// CHECK:STDOUT:       inst35:          symbolic_constant6
+// CHECK:STDOUT:       inst36:          concrete_constant(inst36)
+// CHECK:STDOUT:       inst37:          symbolic_constant7
+// CHECK:STDOUT:       inst38:          concrete_constant(inst38)
+// CHECK:STDOUT:       inst42:          concrete_constant(inst44)
+// CHECK:STDOUT:       inst43:          concrete_constant(inst43)
+// CHECK:STDOUT:       inst44:          concrete_constant(inst44)
+// CHECK:STDOUT:       inst45:          symbolic_constant8
+// CHECK:STDOUT:       inst46:          symbolic_constant10
+// CHECK:STDOUT:       inst47:          symbolic_constant9
+// CHECK:STDOUT:       inst48:          symbolic_constant10
+// CHECK:STDOUT:       inst49:          symbolic_constant12
+// CHECK:STDOUT:       inst50:          symbolic_constant11
+// CHECK:STDOUT:       inst51:          symbolic_constant12
+// CHECK:STDOUT:       inst55:          symbolic_constant10
+// CHECK:STDOUT:       inst57:          symbolic_constant12
+// CHECK:STDOUT:       inst60:          concrete_constant(inst61)
+// CHECK:STDOUT:       inst61:          concrete_constant(inst61)
+// CHECK:STDOUT:       inst62:          concrete_constant(inst61)
+// CHECK:STDOUT:     symbolic_constants:
+// CHECK:STDOUT:       symbolic_constant0: {inst: inst16, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant1: {inst: inst16, generic: generic0, index: generic_inst_in_decl0, kind: checked}
+// CHECK:STDOUT:       symbolic_constant2: {inst: inst22, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant3: {inst: inst22, generic: generic0, index: generic_inst_in_decl1, kind: checked}
+// CHECK:STDOUT:       symbolic_constant4: {inst: inst32, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant5: {inst: inst32, generic: generic0, index: generic_inst_in_decl2, kind: checked}
+// CHECK:STDOUT:       symbolic_constant6: {inst: inst35, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant7: {inst: inst35, generic: generic0, index: generic_inst_in_decl3, kind: checked}
+// CHECK:STDOUT:       symbolic_constant8: {inst: inst45, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant9: {inst: inst47, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant10: {inst: inst47, generic: generic0, index: generic_inst_in_def0, kind: checked}
+// CHECK:STDOUT:       symbolic_constant11: {inst: inst50, generic: generic<none>, index: generic_inst<none>, kind: checked}
+// CHECK:STDOUT:       symbolic_constant12: {inst: inst50, generic: generic0, index: generic_inst_in_def1, kind: checked}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:

+ 28 - 27
toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon

@@ -92,33 +92,34 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:     inst52:          {kind: Converted, arg0: inst42, arg1: inst50, type: type(inst24)}
 // CHECK:STDOUT:     inst53:          {kind: ReturnExpr, arg0: inst52, arg1: inst35}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:     inst15:          concrete_constant(inst15)
-// CHECK:STDOUT:     inst17:          concrete_constant(inst15)
-// CHECK:STDOUT:     inst19:          concrete_constant(inst19)
-// CHECK:STDOUT:     inst20:          concrete_constant(inst20)
-// CHECK:STDOUT:     inst21:          concrete_constant(inst21)
-// CHECK:STDOUT:     inst24:          concrete_constant(inst24)
-// CHECK:STDOUT:     inst26:          concrete_constant(inst15)
-// CHECK:STDOUT:     inst27:          concrete_constant(inst15)
-// CHECK:STDOUT:     inst28:          concrete_constant(inst24)
-// CHECK:STDOUT:     inst29:          concrete_constant(inst29)
-// CHECK:STDOUT:     inst30:          concrete_constant(inst30)
-// CHECK:STDOUT:     inst31:          concrete_constant(inst31)
-// CHECK:STDOUT:     inst33:          concrete_constant(inst15)
-// CHECK:STDOUT:     inst36:          concrete_constant(inst38)
-// CHECK:STDOUT:     inst37:          concrete_constant(inst37)
-// CHECK:STDOUT:     inst38:          concrete_constant(inst38)
-// CHECK:STDOUT:     inst39:          concrete_constant(inst39)
-// CHECK:STDOUT:     inst44:          concrete_constant(inst45)
-// CHECK:STDOUT:     inst45:          concrete_constant(inst45)
-// CHECK:STDOUT:     inst46:          concrete_constant(inst45)
-// CHECK:STDOUT:     inst48:          concrete_constant(inst45)
-// CHECK:STDOUT:     inst49:          concrete_constant(inst45)
-// CHECK:STDOUT:     inst50:          concrete_constant(inst51)
-// CHECK:STDOUT:     inst51:          concrete_constant(inst51)
-// CHECK:STDOUT:     inst52:          concrete_constant(inst51)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:       inst15:          concrete_constant(inst15)
+// CHECK:STDOUT:       inst17:          concrete_constant(inst15)
+// CHECK:STDOUT:       inst19:          concrete_constant(inst19)
+// CHECK:STDOUT:       inst20:          concrete_constant(inst20)
+// CHECK:STDOUT:       inst21:          concrete_constant(inst21)
+// CHECK:STDOUT:       inst24:          concrete_constant(inst24)
+// CHECK:STDOUT:       inst26:          concrete_constant(inst15)
+// CHECK:STDOUT:       inst27:          concrete_constant(inst15)
+// CHECK:STDOUT:       inst28:          concrete_constant(inst24)
+// CHECK:STDOUT:       inst29:          concrete_constant(inst29)
+// CHECK:STDOUT:       inst30:          concrete_constant(inst30)
+// CHECK:STDOUT:       inst31:          concrete_constant(inst31)
+// CHECK:STDOUT:       inst33:          concrete_constant(inst15)
+// CHECK:STDOUT:       inst36:          concrete_constant(inst38)
+// CHECK:STDOUT:       inst37:          concrete_constant(inst37)
+// CHECK:STDOUT:       inst38:          concrete_constant(inst38)
+// CHECK:STDOUT:       inst39:          concrete_constant(inst39)
+// CHECK:STDOUT:       inst44:          concrete_constant(inst45)
+// CHECK:STDOUT:       inst45:          concrete_constant(inst45)
+// CHECK:STDOUT:       inst46:          concrete_constant(inst45)
+// CHECK:STDOUT:       inst48:          concrete_constant(inst45)
+// CHECK:STDOUT:       inst49:          concrete_constant(inst45)
+// CHECK:STDOUT:       inst50:          concrete_constant(inst51)
+// CHECK:STDOUT:       inst51:          concrete_constant(inst51)
+// CHECK:STDOUT:       inst52:          concrete_constant(inst51)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:

+ 3 - 2
toolchain/driver/testdata/stdin.carbon

@@ -49,8 +49,9 @@
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     inst14:          {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:   constant_values:
-// CHECK:STDOUT:     inst14:          concrete_constant(inst14)
-// CHECK:STDOUT:   symbolic_constants: {}
+// CHECK:STDOUT:     values:
+// CHECK:STDOUT:       inst14:          concrete_constant(inst14)
+// CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
 // CHECK:STDOUT:     exports:         {}

+ 26 - 21
toolchain/sem_ir/constant.h

@@ -87,7 +87,7 @@ class ConstantValueStore {
     CARBON_DCHECK(inst_id.index >= 0);
     return static_cast<size_t>(inst_id.index) >= values_.size()
                ? default_
-               : values_[inst_id.index];
+               : values_.Get(inst_id);
   }
 
   // Sets the constant value of the given instruction, or sets that it is known
@@ -95,9 +95,9 @@ class ConstantValueStore {
   auto Set(InstId inst_id, ConstantId const_id) -> void {
     CARBON_DCHECK(inst_id.index >= 0);
     if (static_cast<size_t>(inst_id.index) >= values_.size()) {
-      values_.resize(inst_id.index + 1, default_);
+      values_.Resize(inst_id.index + 1, default_);
     }
-    values_[inst_id.index] = const_id;
+    values_.Get(inst_id) = const_id;
   }
 
   // Gets the instruction ID that defines the value of the given constant.
@@ -135,17 +135,16 @@ class ConstantValueStore {
   }
 
   auto AddSymbolicConstant(SymbolicConstant constant) -> ConstantId {
-    symbolic_constants_.push_back(constant);
-    return ConstantId::ForSymbolicConstantIndex(symbolic_constants_.size() - 1);
+    return ConstantId::ForSymbolicConstantId(symbolic_constants_.Add(constant));
   }
 
   auto GetSymbolicConstant(ConstantId const_id) -> SymbolicConstant& {
-    return symbolic_constants_[const_id.symbolic_index()];
+    return symbolic_constants_.Get(const_id.symbolic_id());
   }
 
   auto GetSymbolicConstant(ConstantId const_id) const
       -> const SymbolicConstant& {
-    return symbolic_constants_[const_id.symbolic_index()];
+    return symbolic_constants_.Get(const_id.symbolic_id());
   }
 
   // Get the dependence of the given constant.
@@ -170,18 +169,24 @@ class ConstantValueStore {
 
   // Makes an iterable range over pairs of the instruction id and constant value
   // id for each value in the store.
-  auto enumerate() const -> auto {
-    auto index_to_id = [](auto pair) -> std::pair<InstId, ConstantId> {
-      auto [index, value] = pair;
-      return std::pair<InstId, ConstantId>(InstId(index), value);
-    };
-    return llvm::map_range(llvm::enumerate(values_), index_to_id);
-  }
-
-  // Returns the symbolic constants mapping as an ArrayRef whose keys are
-  // symbolic indexes of constants.
-  auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
-    return symbolic_constants_;
+  auto enumerate() const -> auto { return values_.enumerate(); }
+
+  // Outputs assigned constant values, and all symbolic constants.
+  auto OutputYaml(bool include_singletons) const -> Yaml::OutputMapping {
+    return Yaml::OutputMapping([&, include_singletons](
+                                   Yaml::OutputMapping::Map map) {
+      map.Add("values", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
+                for (auto [id, value] : values_.enumerate()) {
+                  if (!include_singletons && IsSingletonInstId(id)) {
+                    continue;
+                  }
+                  if (!value.has_value() || value.is_constant()) {
+                    map.Add(PrintToString(id), Yaml::OutputScalar(value));
+                  }
+                }
+              }));
+      map.Add("symbolic_constants", symbolic_constants_.OutputYaml());
+    });
   }
 
  private:
@@ -193,14 +198,14 @@ class ConstantValueStore {
   //
   // Set inline size to 0 because these will typically be too large for the
   // stack, while this does make File smaller.
-  llvm::SmallVector<ConstantId, 0> values_;
+  ValueStore<InstId, ConstantId> values_;
 
   // A mapping from a symbolic constant ID index to information about the
   // symbolic constant. For a concrete constant, the only information that we
   // track is the instruction ID, which is stored directly within the
   // `ConstantId`. For a symbolic constant, we also track information about
   // where the constant was used, which is stored here.
-  llvm::SmallVector<SymbolicConstant, 0> symbolic_constants_;
+  ValueStore<ConstantId::SymbolicId, SymbolicConstant> symbolic_constants_;
 };
 
 // Given a constant ID, returns an instruction that has that constant value.

+ 2 - 2
toolchain/sem_ir/dump.cpp

@@ -423,8 +423,8 @@ LLVM_DUMP_METHOD static auto MakeClassId(int id) -> ClassId {
 LLVM_DUMP_METHOD static auto MakeConstantId(int id) -> ConstantId {
   return ConstantId(id);
 }
-LLVM_DUMP_METHOD static auto MakeSymbolicConstantId(int id) -> ConstantId {
-  return ConstantId::ForSymbolicConstantIndex(id);
+LLVM_DUMP_METHOD auto MakeSymbolicConstantId(int id) -> ConstantId {
+  return ConstantId::ForSymbolicConstantId(ConstantId::SymbolicId(id));
 }
 LLVM_DUMP_METHOD static auto MakeEntityNameId(int id) -> EntityNameId {
   return EntityNameId(id);

+ 24 - 45
toolchain/sem_ir/file.cpp

@@ -95,51 +95,30 @@ auto File::OutputYaml(bool include_singletons) const -> Yaml::OutputMapping {
   return Yaml::OutputMapping([this, include_singletons](
                                  Yaml::OutputMapping::Map map) {
     map.Add("filename", filename_);
-    map.Add(
-        "sem_ir", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
-          map.Add("import_irs", import_irs_.OutputYaml());
-          map.Add("import_ir_insts", import_ir_insts_.OutputYaml());
-          map.Add("name_scopes", name_scopes_.OutputYaml());
-          map.Add("entity_names", entity_names_.OutputYaml());
-          map.Add("functions", functions_.OutputYaml());
-          map.Add("classes", classes_.OutputYaml());
-          map.Add("generics", generics_.OutputYaml());
-          map.Add("specifics", specifics_.OutputYaml());
-          map.Add("struct_type_fields", struct_type_fields_.OutputYaml());
-          map.Add("types", types_.OutputYaml());
-          map.Add("insts",
-                  Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
-                    for (auto [id, inst] : insts_.enumerate()) {
-                      if (!include_singletons && IsSingletonInstId(id)) {
-                        continue;
-                      }
-                      map.Add(PrintToString(id), Yaml::OutputScalar(inst));
-                    }
-                  }));
-          map.Add("constant_values",
-                  Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
-                    for (auto [id, _] : insts_.enumerate()) {
-                      if (!include_singletons && IsSingletonInstId(id)) {
-                        continue;
-                      }
-                      auto value = constant_values_.Get(id);
-                      if (!value.has_value() || value.is_constant()) {
-                        map.Add(PrintToString(id), Yaml::OutputScalar(value));
-                      }
-                    }
-                  }));
-          map.Add(
-              "symbolic_constants",
-              Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
-                for (const auto& [i, symbolic] :
-                     llvm::enumerate(constant_values().symbolic_constants())) {
-                  map.Add(
-                      PrintToString(ConstantId::ForSymbolicConstantIndex(i)),
-                      Yaml::OutputScalar(symbolic));
-                }
-              }));
-          map.Add("inst_blocks", inst_blocks_.OutputYaml());
-        }));
+    map.Add("sem_ir", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
+              map.Add("import_irs", import_irs_.OutputYaml());
+              map.Add("import_ir_insts", import_ir_insts_.OutputYaml());
+              map.Add("name_scopes", name_scopes_.OutputYaml());
+              map.Add("entity_names", entity_names_.OutputYaml());
+              map.Add("functions", functions_.OutputYaml());
+              map.Add("classes", classes_.OutputYaml());
+              map.Add("generics", generics_.OutputYaml());
+              map.Add("specifics", specifics_.OutputYaml());
+              map.Add("struct_type_fields", struct_type_fields_.OutputYaml());
+              map.Add("types", types_.OutputYaml());
+              map.Add("insts",
+                      Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
+                        for (auto [id, inst] : insts_.enumerate()) {
+                          if (!include_singletons && IsSingletonInstId(id)) {
+                            continue;
+                          }
+                          map.Add(PrintToString(id), Yaml::OutputScalar(inst));
+                        }
+                      }));
+              map.Add("constant_values",
+                      constant_values_.OutputYaml(include_singletons));
+              map.Add("inst_blocks", inst_blocks_.OutputYaml());
+            }));
   });
 }
 

+ 1 - 1
toolchain/sem_ir/ids.cpp

@@ -33,7 +33,7 @@ auto ConstantId::Print(llvm::raw_ostream& out, bool disambiguate) const
       out << ")";
     }
   } else if (is_symbolic()) {
-    out << "symbolic_constant" << symbolic_index();
+    out << symbolic_id();
   } else {
     CARBON_CHECK(!is_constant());
     out << "runtime";

+ 19 - 10
toolchain/sem_ir/ids.h

@@ -153,12 +153,6 @@ struct ConstantId : public IdBase<ConstantId> {
     return ConstantId(const_id.index);
   }
 
-  // Returns the constant ID corresponding to a symbolic constant index.
-  static constexpr auto ForSymbolicConstantIndex(int32_t symbolic_index)
-      -> ConstantId {
-    return ConstantId(FirstSymbolicIndex - symbolic_index);
-  }
-
   using IdBase::IdBase;
 
   // Returns whether this represents a constant. Requires has_value.
@@ -169,7 +163,7 @@ struct ConstantId : public IdBase<ConstantId> {
   // Returns whether this represents a symbolic constant. Requires has_value.
   constexpr auto is_symbolic() const -> bool {
     CARBON_DCHECK(has_value());
-    return index <= FirstSymbolicIndex;
+    return index <= FirstSymbolicId;
   }
   // Returns whether this represents a concrete constant. Requires has_value.
   constexpr auto is_concrete() const -> bool {
@@ -186,6 +180,21 @@ struct ConstantId : public IdBase<ConstantId> {
  private:
   friend class ConstantValueStore;
 
+  // For Dump.
+  friend auto MakeSymbolicConstantId(int id) -> ConstantId;
+
+  // A symbolic constant.
+  struct SymbolicId : public IdBase<SymbolicId> {
+    static constexpr llvm::StringLiteral Label = "symbolic_constant";
+    using IdBase::IdBase;
+  };
+
+  // Returns the constant ID corresponding to a symbolic constant index.
+  static constexpr auto ForSymbolicConstantId(SymbolicId symbolic_id)
+      -> ConstantId {
+    return ConstantId(FirstSymbolicId - symbolic_id.index);
+  }
+
   // 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; }
@@ -200,13 +209,13 @@ struct ConstantId : public IdBase<ConstantId> {
 
   // Returns the symbolic constant index that describes this symbolic constant
   // value. Requires `is_symbolic()`.
-  constexpr auto symbolic_index() const -> int32_t {
+  constexpr auto symbolic_id() const -> SymbolicId {
     CARBON_DCHECK(is_symbolic());
-    return FirstSymbolicIndex - index;
+    return SymbolicId(FirstSymbolicId - index);
   }
 
   static constexpr int32_t NotConstantIndex = NoneIndex - 1;
-  static constexpr int32_t FirstSymbolicIndex = NoneIndex - 2;
+  static constexpr int32_t FirstSymbolicId = NoneIndex - 2;
 };
 
 constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex);

+ 4 - 2
toolchain/sem_ir/yaml_test.cpp

@@ -86,8 +86,10 @@ TEST(SemIRTest, Yaml) {
                                              Pair("arg1", "inst_block_empty"),
                                              Pair("type", type_id)))))))),
       Pair("constant_values",
-           Yaml::Mapping(AllOf(Each(Pair(inst_id, constant_id))))),
-      Pair("symbolic_constants", Yaml::Mapping(SizeIs(0))),
+           Yaml::Mapping(ElementsAre(
+               Pair("values",
+                    Yaml::Mapping(AllOf(Each(Pair(inst_id, constant_id))))),
+               Pair("symbolic_constants", Yaml::Mapping(SizeIs(0)))))),
       Pair("inst_blocks",
            Yaml::Mapping(ElementsAre(
                Pair("inst_block_empty", Yaml::Mapping(IsEmpty())),