mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Rebuild all constants in the eval block. (#4155)
Instead of reusing instructions from the generic entity in the eval block, rebuild constants in the same way we rebuild types. The previous attempt to not rebuild these constants assumed that every constant used in a generic would be built in that generic, and not referenced directly or referenced from some enclosing scope, which isn't true in practice and is a fragile assumption in any case. We could add back some reuse of instructions from the generic -- if we happen to see the right instruction to build a constant, we could opportunistically reuse it -- but given the complexity added by doing so, I'm not pursuing that here. Now that the eval block for a generic consists of instructions uniquely owned by that generic, rather than often being shared with another entity, include the generic in the formatted SemIR output. I'm using the same scope name for the generic object itself as for the parameterized class / function / interface, because there are very frequently references between them and this keeps the IR simpler and more readable, and avoids needing to invent a second name for the scope.
This commit is contained in:
+114
-100
@@ -151,14 +151,6 @@ class FormatterImpl {
|
||||
Indent(-2);
|
||||
}
|
||||
|
||||
// Wraps the current line, prior to some text that we expect to be quite long
|
||||
// and more readable on a separate line. This is indented two levels more than
|
||||
// the ambient text.
|
||||
auto WrapLine() -> void {
|
||||
out_ << '\n';
|
||||
Indent(4);
|
||||
}
|
||||
|
||||
auto FormatConstants() -> void {
|
||||
if (!sem_ir_.constants().size()) {
|
||||
return;
|
||||
@@ -186,15 +178,31 @@ class FormatterImpl {
|
||||
out_ << "\n\n";
|
||||
}
|
||||
|
||||
template <typename IdT>
|
||||
auto FormatEntityStart(llvm::StringRef entity_kind, GenericId generic_id,
|
||||
IdT entity_id) -> void {
|
||||
if (generic_id.is_valid()) {
|
||||
FormatGenericStart(entity_kind, generic_id);
|
||||
out_ << "\n";
|
||||
Indent();
|
||||
out_ << entity_kind;
|
||||
} else {
|
||||
out_ << "\n";
|
||||
Indent();
|
||||
out_ << entity_kind << " ";
|
||||
FormatName(entity_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto FormatEntityEnd(GenericId generic_id) -> void {
|
||||
if (generic_id.is_valid()) {
|
||||
FormatGenericEnd();
|
||||
}
|
||||
}
|
||||
|
||||
auto FormatClass(ClassId id) -> void {
|
||||
const Class& class_info = sem_ir_.classes().Get(id);
|
||||
|
||||
out_ << "\nclass ";
|
||||
FormatClassName(id);
|
||||
|
||||
if (class_info.generic_id.is_valid()) {
|
||||
FormatGeneric(class_info.generic_id);
|
||||
}
|
||||
FormatEntityStart("class", class_info.generic_id, id);
|
||||
|
||||
llvm::SaveAndRestore class_scope(scope_, inst_namer_->GetScopeFor(id));
|
||||
|
||||
@@ -208,17 +216,13 @@ class FormatterImpl {
|
||||
} else {
|
||||
out_ << ";\n";
|
||||
}
|
||||
|
||||
FormatEntityEnd(class_info.generic_id);
|
||||
}
|
||||
|
||||
auto FormatInterface(InterfaceId id) -> void {
|
||||
const Interface& interface_info = sem_ir_.interfaces().Get(id);
|
||||
|
||||
out_ << "\ninterface ";
|
||||
FormatInterfaceName(id);
|
||||
|
||||
if (interface_info.generic_id.is_valid()) {
|
||||
FormatGeneric(interface_info.generic_id);
|
||||
}
|
||||
FormatEntityStart("interface", interface_info.generic_id, id);
|
||||
|
||||
llvm::SaveAndRestore interface_scope(scope_, inst_namer_->GetScopeFor(id));
|
||||
|
||||
@@ -243,13 +247,14 @@ class FormatterImpl {
|
||||
} else {
|
||||
out_ << ";\n";
|
||||
}
|
||||
|
||||
FormatEntityEnd(interface_info.generic_id);
|
||||
}
|
||||
|
||||
auto FormatImpl(ImplId id) -> void {
|
||||
const Impl& impl_info = sem_ir_.impls().Get(id);
|
||||
FormatEntityStart("impl", SemIR::GenericId::Invalid, id);
|
||||
|
||||
out_ << "\nimpl ";
|
||||
FormatImplName(id);
|
||||
out_ << ": ";
|
||||
// TODO: Include the deduced parameter list if present.
|
||||
FormatType(impl_info.self_id);
|
||||
@@ -283,15 +288,7 @@ class FormatterImpl {
|
||||
|
||||
auto FormatFunction(FunctionId id) -> void {
|
||||
const Function& fn = sem_ir_.functions().Get(id);
|
||||
|
||||
out_ << "\n";
|
||||
|
||||
if (fn.is_extern) {
|
||||
out_ << "extern ";
|
||||
}
|
||||
|
||||
out_ << "fn ";
|
||||
FormatFunctionName(id);
|
||||
FormatEntityStart(fn.is_extern ? "extern fn" : "fn", fn.generic_id, id);
|
||||
|
||||
llvm::SaveAndRestore function_scope(scope_, inst_namer_->GetScopeFor(id));
|
||||
|
||||
@@ -310,7 +307,7 @@ class FormatterImpl {
|
||||
if (fn.return_storage_id.is_valid()) {
|
||||
out_ << " -> ";
|
||||
if (!fn.body_block_ids.empty() && fn.has_return_slot()) {
|
||||
FormatInstName(fn.return_storage_id);
|
||||
FormatName(fn.return_storage_id);
|
||||
out_ << ": ";
|
||||
}
|
||||
FormatType(sem_ir_.insts().Get(fn.return_storage_id).type_id());
|
||||
@@ -323,10 +320,6 @@ class FormatterImpl {
|
||||
out_ << "\"";
|
||||
}
|
||||
|
||||
if (fn.generic_id.is_valid()) {
|
||||
FormatGeneric(fn.generic_id);
|
||||
}
|
||||
|
||||
if (!fn.body_block_ids.empty()) {
|
||||
out_ << ' ';
|
||||
OpenBrace();
|
||||
@@ -344,17 +337,37 @@ class FormatterImpl {
|
||||
} else {
|
||||
out_ << ";\n";
|
||||
}
|
||||
|
||||
FormatEntityEnd(fn.generic_id);
|
||||
}
|
||||
|
||||
auto FormatGeneric(GenericId generic_id) -> void {
|
||||
auto FormatGenericStart(llvm::StringRef entity_kind, GenericId generic_id)
|
||||
-> void {
|
||||
const auto& generic = sem_ir_.generics().Get(generic_id);
|
||||
out_ << "\n";
|
||||
Indent();
|
||||
out_ << "generic " << entity_kind << " ";
|
||||
FormatName(generic_id);
|
||||
|
||||
WrapLine();
|
||||
out_ << "generic [";
|
||||
llvm::SaveAndRestore generic_scope(scope_,
|
||||
inst_namer_->GetScopeFor(generic_id));
|
||||
|
||||
out_ << "(";
|
||||
FormatParamList(generic.bindings_id);
|
||||
out_ << "]";
|
||||
// TODO: Format at least the portions of the declaration and definition
|
||||
// blocks that don't duplicate portions of the generic body.
|
||||
out_ << ") ";
|
||||
|
||||
OpenBrace();
|
||||
FormatCodeBlock(generic.decl_block_id);
|
||||
if (generic.definition_block_id.is_valid()) {
|
||||
IndentLabel();
|
||||
out_ << "!definition:\n";
|
||||
FormatCodeBlock(generic.definition_block_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto FormatGenericEnd() -> void {
|
||||
CloseBrace();
|
||||
out_ << '\n';
|
||||
}
|
||||
|
||||
auto FormatSpecificRegion(const Generic& generic,
|
||||
@@ -365,15 +378,33 @@ class FormatterImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
IndentLabel();
|
||||
out_ << region_name << ":\n";
|
||||
for (auto [generic_inst_id, specific_inst_id] :
|
||||
llvm::zip(sem_ir_.inst_blocks().Get(generic.GetEvalBlock(region)),
|
||||
sem_ir_.inst_blocks().Get(specific.GetValueBlock(region)))) {
|
||||
if (!region_name.empty()) {
|
||||
IndentLabel();
|
||||
out_ << "!" << region_name << ":\n";
|
||||
}
|
||||
for (auto [generic_inst_id, specific_inst_id] : llvm::zip_longest(
|
||||
sem_ir_.inst_blocks().Get(generic.GetEvalBlock(region)),
|
||||
sem_ir_.inst_blocks().Get(specific.GetValueBlock(region)))) {
|
||||
if (generic_inst_id && specific_inst_id &&
|
||||
sem_ir_.insts().Is<StructTypeField>(*generic_inst_id) &&
|
||||
sem_ir_.insts().Is<StructTypeField>(*specific_inst_id)) {
|
||||
// Skip printing struct type fields to match the way we print the
|
||||
// generic.
|
||||
continue;
|
||||
}
|
||||
|
||||
Indent();
|
||||
FormatInstName(generic_inst_id);
|
||||
if (generic_inst_id) {
|
||||
FormatName(*generic_inst_id);
|
||||
} else {
|
||||
out_ << "<missing>";
|
||||
}
|
||||
out_ << " => ";
|
||||
FormatInstName(specific_inst_id);
|
||||
if (specific_inst_id) {
|
||||
FormatName(*specific_inst_id);
|
||||
} else {
|
||||
out_ << "<missing>";
|
||||
}
|
||||
out_ << "\n";
|
||||
}
|
||||
}
|
||||
@@ -384,7 +415,7 @@ class FormatterImpl {
|
||||
out_ << "\n";
|
||||
|
||||
out_ << "specific ";
|
||||
FormatSpecificName(id);
|
||||
FormatName(id);
|
||||
|
||||
// TODO: Remove once we stop forming generic specifics with no generic
|
||||
// during import.
|
||||
@@ -395,10 +426,12 @@ class FormatterImpl {
|
||||
out_ << " ";
|
||||
|
||||
const auto& generic = sem_ir_.generics().Get(specific.generic_id);
|
||||
llvm::SaveAndRestore generic_scope(
|
||||
scope_, inst_namer_->GetScopeFor(specific.generic_id));
|
||||
|
||||
OpenBrace();
|
||||
FormatSpecificRegion(generic, specific,
|
||||
GenericInstIndex::Region::Declaration, "declaration");
|
||||
GenericInstIndex::Region::Declaration, "");
|
||||
FormatSpecificRegion(generic, specific,
|
||||
GenericInstIndex::Region::Definition, "definition");
|
||||
CloseBrace();
|
||||
@@ -418,7 +451,7 @@ class FormatterImpl {
|
||||
out_ << "addr ";
|
||||
param_id = addr->inner_id;
|
||||
}
|
||||
FormatInstName(param_id);
|
||||
FormatName(param_id);
|
||||
out_ << ": ";
|
||||
FormatType(sem_ir_.insts().Get(param_id).type_id());
|
||||
}
|
||||
@@ -472,7 +505,7 @@ class FormatterImpl {
|
||||
break;
|
||||
}
|
||||
out_ << " = ";
|
||||
FormatInstName(inst_id);
|
||||
FormatName(inst_id);
|
||||
out_ << "\n";
|
||||
}
|
||||
|
||||
@@ -560,7 +593,7 @@ class FormatterImpl {
|
||||
auto FormatInstLHS(InstId inst_id, Inst inst) -> void {
|
||||
switch (inst.kind().value_kind()) {
|
||||
case InstValueKind::Typed:
|
||||
FormatInstName(inst_id);
|
||||
FormatName(inst_id);
|
||||
out_ << ": ";
|
||||
switch (GetExprCategory(sem_ir_, inst_id)) {
|
||||
case ExprCategory::NotExpr:
|
||||
@@ -586,14 +619,14 @@ class FormatterImpl {
|
||||
|
||||
// Format ImportDecl with its name.
|
||||
auto FormatInstLHS(InstId inst_id, ImportDecl /*inst*/) -> void {
|
||||
FormatInstName(inst_id);
|
||||
FormatName(inst_id);
|
||||
out_ << " = ";
|
||||
}
|
||||
|
||||
// Print ImportRefUnloaded with type-like semantics even though it lacks a
|
||||
// type_id.
|
||||
auto FormatInstLHS(InstId inst_id, ImportRefUnloaded /*inst*/) -> void {
|
||||
FormatInstName(inst_id);
|
||||
FormatName(inst_id);
|
||||
out_ << " = ";
|
||||
}
|
||||
|
||||
@@ -638,7 +671,7 @@ class FormatterImpl {
|
||||
Indent();
|
||||
}
|
||||
out_ << "if ";
|
||||
FormatInstName(inst.cond_id);
|
||||
FormatName(inst.cond_id);
|
||||
out_ << " " << Branch::Kind.ir_name() << " ";
|
||||
FormatLabel(inst.target_id);
|
||||
out_ << " else ";
|
||||
@@ -652,7 +685,7 @@ class FormatterImpl {
|
||||
out_ << BranchWithArg::Kind.ir_name() << " ";
|
||||
FormatLabel(inst.target_id);
|
||||
out_ << "(";
|
||||
FormatInstName(inst.arg_id);
|
||||
FormatName(inst.arg_id);
|
||||
out_ << ")\n";
|
||||
in_terminator_sequence_ = false;
|
||||
}
|
||||
@@ -826,17 +859,17 @@ class FormatterImpl {
|
||||
}
|
||||
}
|
||||
|
||||
auto FormatArg(FunctionId id) -> void { FormatFunctionName(id); }
|
||||
auto FormatArg(FunctionId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(ClassId id) -> void { FormatClassName(id); }
|
||||
auto FormatArg(ClassId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(InterfaceId id) -> void { FormatInterfaceName(id); }
|
||||
auto FormatArg(InterfaceId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(IntKind k) -> void { k.Print(out_); }
|
||||
|
||||
auto FormatArg(FloatKind k) -> void { k.Print(out_); }
|
||||
|
||||
auto FormatArg(ImplId id) -> void { FormatImplName(id); }
|
||||
auto FormatArg(ImplId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(ImportIRId id) -> void {
|
||||
if (!id.is_valid()) {
|
||||
@@ -891,7 +924,7 @@ class FormatterImpl {
|
||||
CloseBrace();
|
||||
}
|
||||
|
||||
auto FormatArg(InstId id) -> void { FormatInstName(id); }
|
||||
auto FormatArg(InstId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(InstBlockId id) -> void {
|
||||
if (!id.is_valid()) {
|
||||
@@ -908,7 +941,7 @@ class FormatterImpl {
|
||||
out_ << ')';
|
||||
}
|
||||
|
||||
auto FormatArg(GenericInstanceId id) -> void { FormatSpecificName(id); }
|
||||
auto FormatArg(GenericInstanceId id) -> void { FormatName(id); }
|
||||
|
||||
auto FormatArg(RealId id) -> void {
|
||||
// TODO: Format with a `.` when the exponent is near zero.
|
||||
@@ -947,44 +980,25 @@ class FormatterImpl {
|
||||
out_ << sem_ir_.names().GetFormatted(id);
|
||||
}
|
||||
|
||||
auto FormatInstName(InstId id) -> void {
|
||||
auto FormatName(InstId id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(scope_, id);
|
||||
}
|
||||
|
||||
template <typename IdT>
|
||||
auto FormatName(IdT id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(id);
|
||||
}
|
||||
|
||||
auto FormatName(GenericInstanceId id) -> void {
|
||||
const auto& specific = sem_ir_.generic_instances().Get(id);
|
||||
FormatName(specific.generic_id);
|
||||
FormatArg(specific.args_id);
|
||||
}
|
||||
|
||||
auto FormatLabel(InstBlockId id) -> void {
|
||||
out_ << inst_namer_->GetLabelFor(scope_, id);
|
||||
}
|
||||
|
||||
auto FormatFunctionName(FunctionId id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(id);
|
||||
}
|
||||
|
||||
auto FormatClassName(ClassId id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(id);
|
||||
}
|
||||
|
||||
auto FormatInterfaceName(InterfaceId id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(id);
|
||||
}
|
||||
|
||||
auto FormatImplName(ImplId id) -> void {
|
||||
out_ << inst_namer_->GetNameFor(id);
|
||||
}
|
||||
|
||||
auto FormatSpecificName(GenericInstanceId id) -> void {
|
||||
const auto& specific = sem_ir_.generic_instances().Get(id);
|
||||
// TODO: We don't yet import generics properly, and instead form specifics
|
||||
// with an invalid generic ID. In this case, just print a placeholder for
|
||||
// now. Once import works, we can remove this code.
|
||||
if (!specific.generic_id.is_valid()) {
|
||||
out_ << "<invalid>";
|
||||
} else {
|
||||
const Generic& generic = sem_ir_.generics().Get(specific.generic_id);
|
||||
FormatInstName(generic.decl_id);
|
||||
}
|
||||
FormatArg(specific.args_id);
|
||||
}
|
||||
|
||||
auto FormatConstant(ConstantId id) -> void {
|
||||
if (!id.is_valid()) {
|
||||
out_ << "<not constant>";
|
||||
@@ -999,17 +1013,17 @@ class FormatterImpl {
|
||||
if (symbolic_constant.generic_id.is_valid()) {
|
||||
const auto& generic =
|
||||
sem_ir_.generics().Get(symbolic_constant.generic_id);
|
||||
FormatInstName(sem_ir_.inst_blocks().Get(generic.GetEvalBlock(
|
||||
FormatName(sem_ir_.inst_blocks().Get(generic.GetEvalBlock(
|
||||
symbolic_constant.index
|
||||
.region()))[symbolic_constant.index.index()]);
|
||||
out_ << " (";
|
||||
FormatInstName(sem_ir_.constant_values().GetInstId(id));
|
||||
FormatName(sem_ir_.constant_values().GetInstId(id));
|
||||
out_ << ")";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FormatInstName(sem_ir_.constant_values().GetInstId(id));
|
||||
FormatName(sem_ir_.constant_values().GetInstId(id));
|
||||
}
|
||||
|
||||
auto FormatType(TypeId id) -> void {
|
||||
|
||||
Reference in New Issue
Block a user