Repository: carbon-language/carbon-lang
File: toolchain/lower/file_context.cpp (C++)

Code before:
        } else {
          // Only mark non-equivalence based on state for starting specifics.
          InsertPair(specifics[i], specifics[j], non_equivalent_specifics_);
        }
      }
    }

    // Update equivalent specific llvm::Functions, once all equivalences are
    // found and the algorithm has converged on a canonical specific.
    for (auto specific_id : specifics_to_delete) {
      UpdateEquivalentSpecific(specific_id);
      UpdateAndDeleteLLVMFunction(specific_id);
    }
  }
}

auto FileContext::ProcessSpecificEquivalence(
    std::pair<SemIR::SpecificId, SemIR::SpecificId> pair) -> void {
  auto [specific_id1, specific_id2] = pair;
  CARBON_CHECK(specific_id1.has_value() && specific_id2.has_value(),
               "Expected values in equivalence check");

  auto get_canon = [&](SemIR::SpecificId specific_id) {
    return equivalent_specifics_.Get(specific_id).has_value()
               ? equivalent_specifics_.Get(specific_id)
               : specific_id;
  };
  auto canon_id1 = get_canon(specific_id1);
  auto canon_id2 = get_canon(specific_id2);

  if (canon_id1 == canon_id2) {
    // Already equivalent, there was a previous replacement.
    return;
  }

  if (canon_id1.index >= canon_id2.index) {
    // Prefer the earlier index for canonical values.
    std::swap(canon_id1, canon_id2);
  }

  // Update equivalent_specifics_ for all. This is used as an indicator that
  // this specific_id may be the canonical one when reducing the equivalence
  // chains in `IsKnownEquivalence`.
  equivalent_specifics_.Set(specific_id1, canon_id1);
  equivalent_specifics_.Set(specific_id2, canon_id1);
  equivalent_specifics_.Set(canon_id1, canon_id1);
  equivalent_specifics_.Set(canon_id2, canon_id1);
}

auto FileContext::UpdateEquivalentSpecific(SemIR::SpecificId specific_id)
    -> void {

Review comment (performance):
The repeated `.Get` might be optimized away, but still feels nice to avoid. :)

```suggestion
    auto equiv_id = equivalent_specifics_.Get(specific_id);
    return equiv_id.has_value() ? equiv_id : specific_id;
```

Code after:
        } else {
          // Only mark non-equivalence based on state for starting specifics.
          InsertPair(specifics[i], specifics[j], non_equivalent_specifics_);
        }
      }
    }

    // Once all equivalences are found for a generic, update and delete up
    // equivalent specifics.
    for (auto specific_id : specifics_to_delete) {
      UpdateAndDeleteLLVMFunction(specific_id);
    }
  }
}

auto FileContext::ProcessSpecificEquivalence(
    std::pair<SemIR::SpecificId, SemIR::SpecificId> pair) -> void {
  auto [specific_id1, specific_id2] = pair;
  CARBON_CHECK(specific_id1.has_value() && specific_id2.has_value(),
               "Expected values in equivalence check");

  auto get_canon = [&](SemIR::SpecificId specific_id) {
    auto equiv_id = equivalent_specifics_.Get(specific_id);
    return equiv_id.has_value() ? equiv_id : specific_id;
  };
  auto canon_id1 = get_canon(specific_id1);
  auto canon_id2 = get_canon(specific_id2);

  if (canon_id1 == canon_id2) {
    // Already equivalent, there was a previous replacement.
    return;
  }

  if (canon_id1.index >= canon_id2.index) {
    // Prefer the earlier index for canonical values.
    std::swap(canon_id1, canon_id2);
  }

  // Update equivalent_specifics_ for all. This is used as an indicator that
  // this specific_id may be the canonical one when reducing the equivalence
  // chains in `IsKnownEquivalence`.
  equivalent_specifics_.Set(specific_id1, canon_id1);
  equivalent_specifics_.Set(specific_id2, canon_id1);
  equivalent_specifics_.Set(canon_id1, canon_id1);
  equivalent_specifics_.Set(canon_id2, canon_id1);
}

auto FileContext::UpdateEquivalentSpecific(SemIR::SpecificId specific_id)
    -> void {
  if (!equivalent_specifics_.Get(specific_id).has_value()) {
    return;