Add well-known identifier caching (#6486)

I'm doing this because I figured it'd be an incremental improvement for
all the operator lookups that we do. Even to the extent that we've
discussed witness caching, I think it'll still apply. It does add one
more step to adding new interfaces (before, you'd just write the string,
now you add it to the def file and reference it).

I'll claim it makes GetClangOperatorKind a lot friendlier to read/edit,
nevermind removing the string comparisons. :)
This commit is contained in:
Jon Ross-Perkins
2025-12-11 21:41:47 +00:00
committed by GitHub
parent a848ae11e4
commit c0b335b87f
19 changed files with 482 additions and 239 deletions
+16 -12
View File
@@ -6,6 +6,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/control_flow.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/core_identifier.h"
#include "toolchain/check/full_pattern_stack.h"
#include "toolchain/check/handle.h"
#include "toolchain/check/inst.h"
@@ -135,10 +136,9 @@ auto HandleParseNode(Context& context, Parse::ForInId node_id) -> bool {
// For a value or reference of type `Optional(T)`, call the given accessor.
static auto CallOptionalAccessor(Context& context, Parse::NodeId node_id,
SemIR::InstId optional_id,
llvm::StringLiteral accessor_name)
CoreIdentifier accessor_name)
-> SemIR::InstId {
auto accessor_name_id =
SemIR::NameId::ForIdentifier(context.identifiers().Add(accessor_name));
auto accessor_name_id = context.core_identifiers().AddNameId(accessor_name);
auto accessor_id =
PerformMemberAccess(context, node_id, optional_id, accessor_name_id);
return PerformCall(context, node_id, accessor_id, {});
@@ -160,9 +160,11 @@ auto HandleParseNode(Context& context, Parse::ForHeaderId node_id) -> bool {
// Create the cursor variable.
// TODO: Produce a custom diagnostic if the range operand can't be used as a
// range.
auto cursor_id = BuildUnaryOperator(
context, node_id, {.interface_name = "Iterate", .op_name = "NewCursor"},
range_id);
auto cursor_id =
BuildUnaryOperator(context, node_id,
{.interface_name = CoreIdentifier::Iterate,
.op_name = CoreIdentifier::NewCursor},
range_id);
auto cursor_type_id = context.insts().Get(cursor_id).type_id();
auto cursor_var_id = AddInstWithCleanup<SemIR::VarStorage>(
context, node_id,
@@ -180,9 +182,11 @@ auto HandleParseNode(Context& context, Parse::ForHeaderId node_id) -> bool {
context, node_id,
{.type_id = GetPointerType(context, cursor_type_inst_id),
.lvalue_id = cursor_var_id});
auto element_id = BuildBinaryOperator(
context, node_id, {.interface_name = "Iterate", .op_name = "Next"},
range_id, cursor_addr_id);
auto element_id =
BuildBinaryOperator(context, node_id,
{.interface_name = CoreIdentifier::Iterate,
.op_name = CoreIdentifier::Next},
range_id, cursor_addr_id);
// We need to convert away from an initializing expression in order to call
// `HasValue` and then separately pattern-match against the element.
// TODO: Instead, form a `.Some(pattern_id)` pattern and pattern-match against
@@ -190,8 +194,8 @@ auto HandleParseNode(Context& context, Parse::ForHeaderId node_id) -> bool {
element_id = ConvertToValueOrRefExpr(context, element_id);
// Branch to the loop body if the optional element has a value.
auto cond_value_id =
CallOptionalAccessor(context, node_id, element_id, "HasValue");
auto cond_value_id = CallOptionalAccessor(context, node_id, element_id,
CoreIdentifier::HasValue);
BranchAndStartLoopBody(context, node_id, loop_header_id, cond_value_id);
// The loop pattern's initializer is now complete, and any bindings in it
@@ -204,7 +208,7 @@ auto HandleParseNode(Context& context, Parse::ForHeaderId node_id) -> bool {
// Initialize the pattern from `<element>.Get()`.
auto element_value_id =
CallOptionalAccessor(context, node_id, element_id, "Get");
CallOptionalAccessor(context, node_id, element_id, CoreIdentifier::Get);
LocalPatternMatch(context, pattern_id, element_value_id);
return true;
}