Use inline small storage for small SemIR ID sets in toolchain (#7796)

Apply SmallSize = 16 to frequent identifier and instruction/function
sets in ScopeStack, Class, FacetType, and SpecificCoalescer to avoid
dynamic heap allocations on small scopes. Also defer dest_field_names
set allocation in struct conversion and provide default KeyContext for
SetBase. This was found by inspection, but does seem to be a clear 1.5%
win on overall compile time.

```
Ran baseline and experiment 10 times on 128 x 2450 MHz CPUs
CPU caches:
  L1 Data 32Ki
  L1 Instruction 32Ki
  L2 Unified 512Ki
  L3 Unified 32Mi
Load avg: 1.2041 1.16895 2.86133
Computing statistically significant deltas only wherethe P-value < 𝛂 of 0.05
Metric key:
   BenchmarkName... 👍 <delta>    p=<U-test P-value>
          baseline:    <median> ± <% at 95th conf>
        experiment:    <median> ± <% at 95th conf>

 Benchmark                                                      ┃          CPU Time          ┃           CYCLES           ┃       INSTRUCTIONS        ┃          Lines
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/256... │ 👍  -1.768%      p=0.0346  │ 👍  -1.683%      p=0.0346  │ 👍   0.160%    p=0.000428 │ ~
                                                      baseline: │     49.11  ms  ±   1.363%  │    155.6   M   ±   1.875%  │    293.9   M ±   0.015%   │     4.093 k ±   1.360%
                                                    experiment: │     48.24  ms  ±   2.213%  │    153     M   ±   2.465%  │    293.4   M ±   0.081%   │     4.166 k ±   2.165%
                                                                │                            │                            │                           │
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/1024.. │      ??          p=0.159   │      ??          p=0.067   │ 👍   0.153%    p=0.000249 │ ~
                                                      baseline: │     50.61  ms  ±   2.379%  │    160.7   M   ±   2.777%  │    309.7   M ±   0.015%   │    19.96  k ±   2.326%
                                                    experiment: │     50.32  ms  ±   0.971%  │    159.6   M   ±   0.787%  │    309.2   M ±   0.086%   │    20.07  k ±   0.980%
                                                                │                            │                            │                           │
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/4096.. │ 👍  -1.593%      p=0.0112  │ 👍  -1.632%      p=0.00743 │ 👍   0.138%    p=0.000328 │ ~
                                                      baseline: │     58.58  ms  ±   1.673%  │    186.5   M   ±   1.487%  │    371.2   M ±   0.102%   │    70.96  k ±   1.645%
                                                    experiment: │     57.65  ms  ±   1.032%  │    183.5   M   ±   1.079%  │    370.7   M ±   0.091%   │    72.11  k ±   1.043%
                                                                │                            │                            │                           │
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/16384. │ 👍  -1.695%      p=0.029   │ 👍  -1.823%      p=0.0411  │ 👍   0.221%    p=0.000428 │ ~
                                                      baseline: │     90.07  ms  ±   3.686%  │    287.1   M   ±   3.694%  │    618.9   M ±   0.106%   │   186.9   k ±   3.555%
                                                    experiment: │     88.55  ms  ±   1.891%  │    281.8   M   ±   2.142%  │    617.6   M ±   0.158%   │   190.1   k ±   1.856%
                                                                │                            │                            │                           │
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/65536. │ 👍  -1.797%      p=0.0201  │ 👍  -1.762%      p=0.0201  │ 👍   0.222%    p=0.000328 │ ~
                                                      baseline: │    222.1   ms  ±   2.560%  │    711     M   ±   2.417%  │      1.613 G ±   0.158%   │   304.2   k ±   2.496%
                                                    experiment: │    218.1   ms  ±   1.950%  │    698.5   M   ±   2.010%  │      1.61  G ±   0.075%   │   309.7   k ±   1.989%
                                                                │                            │                            │                           │
 BM_CompileApiFileDenseDecls<Lang::Carbon, Phase::Check>/262144 │      ??          p=0.398   │      ??          p=0.36    │ 👍   0.166%    p=0.000931 │ ~
                                                      baseline: │    782.2   ms  ±   2.666%  │      2.502 G   ±   2.546%  │      5.596 G ±   0.038%   │   345.8   k ±   2.597%
                                                    experiment: │    780.6   ms  ±   4.249%  │      2.483 G   ±   4.691%  │      5.587 G ±   0.024%   │   346.5   k ±   4.075%
                                                                │                            │                            │                           │
```

Assisted-by: Antigravity with Gemini
This commit is contained in:
Chandler Carruth
2026-09-17 15:49:43 +00:00
committed by GitHub
parent e65694db57
commit ae4be1be14
8 changed files with 19 additions and 17 deletions
+1 -1
View File
@@ -131,7 +131,7 @@ class SetView : RawHashtable::ViewImpl<InputKeyT, void, InputKeyContextT> {
// A pointer or reference to this type is the preferred way to pass a mutable
// handle to a `Set` type across API boundaries as it avoids encoding specific
// SSO sizing information while providing a near-complete mutable API.
template <typename InputKeyT, typename InputKeyContextT>
template <typename InputKeyT, typename InputKeyContextT = DefaultKeyContext>
class SetBase
: protected RawHashtable::BaseImpl<InputKeyT, void, InputKeyContextT> {
protected:
+1 -1
View File
@@ -222,7 +222,7 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
};
llvm::SmallVector<SemIR::InstId> vtable;
Set<SemIR::FunctionId> implemented_impls;
Set<SemIR::FunctionId, 16> implemented_impls;
bool carbon_native_vtable = true;
// Add vtable entries from the base class, updating them to point to a derived
+5 -5
View File
@@ -649,15 +649,15 @@ static auto ConvertStructToStructOrClass(
value_id = MaterializeIfInitializer(context, value_id);
}
Set<SemIR::NameId> dest_field_names;
for (auto field : dest_elem_fields) {
dest_field_names.Insert(field.name_id);
}
// Prepare to look up fields in the source by index. Also check for
// source fields that don't match any field in the destination.
Map<SemIR::NameId, int32_t> src_field_indexes;
if (src_type.fields_id != dest_type.fields_id) {
Set<SemIR::NameId, 16> dest_field_names;
for (auto field : dest_elem_fields) {
dest_field_names.Insert(field.name_id);
}
for (auto [i, field] : llvm::enumerate(src_elem_fields)) {
if (!dest_field_names.Lookup(field.name_id)) {
if (target.diagnose) {
+1 -1
View File
@@ -550,7 +550,7 @@ auto FindWhere(Context& context, SemIR::ConstantId const_id) -> bool {
private:
bool* found_;
Set<SemIR::InstId> searched_;
Set<SemIR::InstId, 16> searched_;
};
if (!const_id.is_constant()) {
+1 -1
View File
@@ -359,7 +359,7 @@ class ScopeStack {
// Names which are registered with lexical_lookup_, and will need to be
// unregistered when the scope ends.
Set<SemIR::NameId> names = {};
Set<SemIR::NameId, 16> names = {};
};
// A scope in which `return` can be used.
+1
View File
@@ -69,6 +69,7 @@ cc_library(
"//common:map",
"//common:pretty_stack_trace_function",
"//common:raw_string_ostream",
"//common:set",
"//common:vlog",
"//toolchain/base:fixed_size_value_store",
"//toolchain/base:kind_switch",
+4 -4
View File
@@ -59,7 +59,7 @@ auto SpecificCoalescer::CoalesceEquivalentSpecifics(
continue;
}
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>, 16>
visited_equivalent_specifics;
InsertPair(specifics[i], specifics[j], visited_equivalent_specifics);
// Function type information matches; check usages inside the function
@@ -205,7 +205,7 @@ auto SpecificCoalescer::AreFunctionTypesEquivalent(
auto SpecificCoalescer::AreFunctionBodiesEquivalent(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>&
SetBase<std::pair<SemIR::SpecificId, SemIR::SpecificId>>&
visited_equivalent_specifics) -> bool {
llvm::SmallVector<std::pair<SemIR::SpecificId, SemIR::SpecificId>> worklist;
worklist.push_back({specific_id1, specific_id2});
@@ -251,7 +251,7 @@ auto SpecificCoalescer::AreFunctionBodiesEquivalent(
auto SpecificCoalescer::InsertPair(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
SetBase<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
-> bool {
if (specific_id1.index > specific_id2.index) {
std::swap(specific_id1.index, specific_id2.index);
@@ -263,7 +263,7 @@ auto SpecificCoalescer::InsertPair(
auto SpecificCoalescer::ContainsPair(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
const Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
SetView<std::pair<SemIR::SpecificId, SemIR::SpecificId>> set_of_pairs)
-> bool {
if (specific_id1.index > specific_id2.index) {
std::swap(specific_id1.index, specific_id2.index);
+5 -4
View File
@@ -5,6 +5,7 @@
#ifndef CARBON_TOOLCHAIN_LOWER_SPECIFIC_COALESCER_H_
#define CARBON_TOOLCHAIN_LOWER_SPECIFIC_COALESCER_H_
#include "common/set.h"
#include "llvm/Support/BLAKE3.h"
#include "toolchain/lower/context.h"
#include "toolchain/sem_ir/ids.h"
@@ -87,7 +88,7 @@ class SpecificCoalescer {
// found, if the two specifics given as arguments are found to be equivalent.
auto AreFunctionBodiesEquivalent(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>&
SetBase<std::pair<SemIR::SpecificId, SemIR::SpecificId>>&
visited_equivalent_specifics) -> bool;
// Given an equivalent pair of specifics, updates the canonical specific to
@@ -118,13 +119,13 @@ class SpecificCoalescer {
// checks entry already existed if it cannot be inserted.
auto InsertPair(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
SetBase<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
-> bool;
// Checks if a pair is contained into a set of pairs, in canonical form.
auto ContainsPair(
SemIR::SpecificId specific_id1, SemIR::SpecificId specific_id2,
const Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
SetView<std::pair<SemIR::SpecificId, SemIR::SpecificId>> set_of_pairs)
-> bool;
// The optional vlog stream.
@@ -154,7 +155,7 @@ class SpecificCoalescer {
// Non-equivalent specifics found.
// TODO: Revisit this due to its quadratic space growth.
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>
Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>, 16>
non_equivalent_specifics_;
};