Convert StructTypeField to a specific type. (#4492)

This converts `StructTypeField` from an instruction to a dedicated type,
with its own store. This had originated from discussing how
`.GetAs<SemIR::StructTypeField>` was more prevalent than for other
instructions, but is probably more interesting for the storage savings
(16 bytes StructTypeField + 4 byte LocId + 4 byte InstId -> 8 byte
StructTypeField).

Due to the different structure, these now have their own stack during
construction, reducing (but not eliminating) `args_type_info_stack_`
use-cases.

The test changes of different InstIds is expected because structs and
classes generate fewer instructions now. Other than that, results should
remain the same.

I'm generally trying to avoid unrelated cleanup here due to the PR size,
though I did scrutinize the `VerifyOnFinish` calls, adding one and
commenting others (putting them in member order because that's how I was
checking what was verified and what wasn't).
This commit is contained in:
Jon Ross-Perkins
2024-11-06 21:38:27 +00:00
committed by GitHub
parent 7977a9cddc
commit be56ff87c6
48 changed files with 535 additions and 436 deletions
+30 -3
View File
@@ -310,6 +310,36 @@ static auto GetConstantValue(EvalContext& eval_context,
return eval_context.inst_blocks().AddCanonical(const_insts);
}
// Compute the constant value of a type block. This may be different from the
// input type block if we have known generic arguments.
static auto GetConstantValue(EvalContext& eval_context,
SemIR::StructTypeFieldsId fields_id, Phase* phase)
-> SemIR::StructTypeFieldsId {
if (!fields_id.is_valid()) {
return SemIR::StructTypeFieldsId::Invalid;
}
auto fields = eval_context.context().struct_type_fields().Get(fields_id);
llvm::SmallVector<SemIR::StructTypeField> new_fields;
for (auto field : fields) {
auto new_type_id = GetConstantValue(eval_context, field.type_id, phase);
if (!new_type_id.is_valid()) {
return SemIR::StructTypeFieldsId::Invalid;
}
// Once we leave the small buffer, we know the first few elements are all
// constant, so it's likely that the entire block is constant. Resize to the
// target size given that we're going to allocate memory now anyway.
if (new_fields.size() == new_fields.capacity()) {
new_fields.reserve(fields.size());
}
new_fields.push_back({.name_id = field.name_id, .type_id = new_type_id});
}
// TODO: If the new block is identical to the original block, and we know the
// old ID was canonical, return the original ID.
return eval_context.context().struct_type_fields().AddCanonical(new_fields);
}
// Compute the constant value of a type block. This may be different from the
// input type block if we have known generic arguments.
static auto GetConstantValue(EvalContext& eval_context,
@@ -1235,9 +1265,6 @@ static auto TryEvalInstInContext(EvalContext& eval_context,
case SemIR::StructType::Kind:
return RebuildIfFieldsAreConstant(eval_context, inst,
&SemIR::StructType::fields_id);
case SemIR::StructTypeField::Kind:
return RebuildIfFieldsAreConstant(eval_context, inst,
&SemIR::StructTypeField::field_type_id);
case SemIR::StructValue::Kind:
return RebuildIfFieldsAreConstant(eval_context, inst,
&SemIR::StructValue::type_id,