Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more Dump methods for debugging #4747

Merged
merged 5 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions toolchain/check/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ cc_library(
"//toolchain/lex:tokenized_buffer",
"//toolchain/parse:dump",
"//toolchain/parse:tree",
"//toolchain/sem_ir:dump",
"//toolchain/sem_ir:file",
],
# Always link dump methods.
Expand Down
82 changes: 82 additions & 0 deletions toolchain/check/dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "toolchain/lex/tokenized_buffer.h"
#include "toolchain/parse/dump.h"
#include "toolchain/parse/tree.h"
#include "toolchain/sem_ir/dump.h"
#include "toolchain/sem_ir/file.h"

namespace Carbon::Check {
Expand Down Expand Up @@ -67,12 +68,93 @@ LLVM_DUMP_METHOD static auto Dump(const Context& context, Parse::NodeId node_id)
Parse::Dump(context.parse_tree(), node_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::ClassId class_id) -> void {
SemIR::Dump(context.sem_ir(), class_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::ConstantId const_id) -> void {
SemIR::Dump(context.sem_ir(), const_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::EntityNameId entity_name_id) -> void {
SemIR::Dump(context.sem_ir(), entity_name_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::FacetTypeId facet_type_id) -> void {
SemIR::Dump(context.sem_ir(), facet_type_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::FunctionId function_id) -> void {
SemIR::Dump(context.sem_ir(), function_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::GenericId generic_id) -> void {
SemIR::Dump(context.sem_ir(), generic_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::ImplId impl_id)
-> void {
SemIR::Dump(context.sem_ir(), impl_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::InstBlockId inst_block_id) -> void {
SemIR::Dump(context.sem_ir(), inst_block_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::InstId inst_id)
-> void {
SemIR::Dump(context.sem_ir(), inst_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::InterfaceId interface_id) -> void {
SemIR::Dump(context.sem_ir(), interface_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::LocId loc_id)
-> void {
DumpNoNewline(context, loc_id);
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::NameId name_id)
-> void {
SemIR::Dump(context.sem_ir(), name_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::NameScopeId name_scope_id) -> void {
SemIR::Dump(context.sem_ir(), name_scope_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::SpecificId specific_id) -> void {
SemIR::Dump(context.sem_ir(), specific_id);
}

LLVM_DUMP_METHOD static auto Dump(
const Context& context, SemIR::StructTypeFieldsId struct_type_fields_id)
-> void {
SemIR::Dump(context.sem_ir(), struct_type_fields_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context,
SemIR::TypeBlockId type_block_id) -> void {
SemIR::Dump(context.sem_ir(), type_block_id);
}

LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::TypeId type_id)
-> void {
SemIR::Dump(context.sem_ir(), type_id);
}

} // namespace Carbon::Check

#endif // NDEBUG
1 change: 1 addition & 0 deletions toolchain/driver/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ cc_library(
"//toolchain/lower",
"//toolchain/parse",
"//toolchain/parse:tree",
"//toolchain/sem_ir:dump",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:formatter",
"//toolchain/sem_ir:inst_namer",
Expand Down
14 changes: 14 additions & 0 deletions toolchain/sem_ir/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ cc_library(
],
)

cc_library(
name = "dump",
srcs = ["dump.cpp"],
hdrs = ["dump.h"],
deps = [
":file",
":stringify_type",
"//common:ostream",
],
# Always link dump methods so they are callable from a debugger
# even though they are never called.
alwayslink = 1,
)

cc_test(
name = "name_scope_test",
size = "small",
Expand Down
244 changes: 244 additions & 0 deletions toolchain/sem_ir/dump.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef NDEBUG

#include "toolchain/sem_ir/dump.h"

#include "common/ostream.h"
#include "toolchain/sem_ir/stringify_type.h"

namespace Carbon::SemIR {

static auto DumpIfValid(const File& file, NameId name_id) -> void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DumpNameIfValid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (name_id.is_valid()) {
llvm::errs() << " `" << file.names().GetFormatted(name_id) << "`";
}
}

static auto DumpNoNewline(const File& file, ConstantId const_id) -> void {
llvm::errs() << const_id;
if (const_id.is_symbolic()) {
llvm::errs() << ": "
<< file.constant_values().GetSymbolicConstant(const_id);
} else if (const_id.is_template()) {
llvm::errs() << ": "
<< file.insts().Get(
file.constant_values().GetInstId(const_id));
}
}

static auto DumpNoNewline(const File& file, InstId inst_id) -> void {
llvm::errs() << inst_id;
if (inst_id.is_valid()) {
llvm::errs() << ": " << file.insts().Get(inst_id);
}
}

static auto DumpNoNewline(const File& file, InterfaceId interface_id) -> void {
llvm::errs() << interface_id;
if (interface_id.is_valid()) {
auto interface = file.interfaces().Get(interface_id);
llvm::errs() << ": " << interface;
DumpIfValid(file, interface.name_id);
}
}

static auto DumpNoNewline(const File& file, SpecificId specific_id) -> void {
llvm::errs() << specific_id;
if (specific_id.is_valid()) {
llvm::errs() << ": " << file.specifics().Get(specific_id);
}
}

LLVM_DUMP_METHOD auto Dump(const File& file, ClassId class_id) -> void {
llvm::errs() << class_id;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea with the NoNewlines is that all the dumping logic lives in those functions so that they can be composed into other DumpNoNewline classes, and the body of each Dump() is just a DumpNoNewline() + newline. So this body here could move into a DumpNoNewline function.

Same for the other Dump functions below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recognized that was the intent, and that is how I started writing this PR, but in practice it didn't seem to work out that way. The information I wanted to print for a given id (a) benefited from formatting using newlines and indents and (b) didn't decompose into calls to DumpNoNewline functions. To avoid extra boilerplate, I've instead only written DumpNoNewline functions when there was a caller that wanted the functionality of one of the Dump functions without the newline, instead of writing an extra function proactively.

if (class_id.is_valid()) {
auto class_obj = file.classes().Get(class_id);
llvm::errs() << ": " << class_obj;
DumpIfValid(file, class_obj.name_id);
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, ConstantId const_id) -> void {
DumpNoNewline(file, const_id);
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, EntityNameId entity_name_id)
-> void {
llvm::errs() << entity_name_id;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest for each of these to write the type being dumped in the output too, see for example https://github.com/carbon-language/carbon-lang/pull/4747/files?diff=unified&w=0#diff-e690edf9337d3bd7e874588bc9d865536d6c69f2b7e8db79a9ef3aa9fd4b6edbL33-L42

So it could be something like EntityNameId(...the stuff in here...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the print functions for each of the Id classes already includes its type:

out << IdT::Label;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay, unlike LocId though

if (entity_name_id.is_valid()) {
auto entity_name = file.entity_names().Get(entity_name_id);
llvm::errs() << ": " << entity_name;
DumpIfValid(file, entity_name.name_id);
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, FacetTypeId facet_type_id)
-> void {
llvm::errs() << facet_type_id;
if (facet_type_id.is_valid()) {
auto facet_type = file.facet_types().Get(facet_type_id);
llvm::errs() << ": " << facet_type;
for (auto impls : facet_type.impls_constraints) {
llvm::errs() << "\n - ";
DumpNoNewline(file, impls.interface_id);
if (impls.specific_id.is_valid()) {
llvm::errs() << "; ";
DumpNoNewline(file, impls.specific_id);
}
}
for (auto rewrite : facet_type.rewrite_constraints) {
llvm::errs() << "\n - ";
DumpNoNewline(file, rewrite.lhs_const_id);
llvm::errs() << "\n - ";
DumpNoNewline(file, rewrite.rhs_const_id);
}
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, FunctionId function_id) -> void {
llvm::errs() << function_id;
if (function_id.is_valid()) {
auto function = file.functions().Get(function_id);
llvm::errs() << ": " << function;
DumpIfValid(file, function.name_id);
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, GenericId generic_id) -> void {
llvm::errs() << generic_id;
if (generic_id.is_valid()) {
llvm::errs() << ": " << file.generics().Get(generic_id);
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, ImplId impl_id) -> void {
llvm::errs() << impl_id;
if (impl_id.is_valid()) {
llvm::errs() << ": " << file.impls().Get(impl_id);
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, InstBlockId inst_block_id)
-> void {
llvm::errs() << inst_block_id;
if (inst_block_id.is_valid()) {
llvm::errs() << ":";
auto inst_block = file.inst_blocks().Get(inst_block_id);
for (auto inst_id : inst_block) {
llvm::errs() << "\n - ";
DumpNoNewline(file, inst_id);
}
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, InstId inst_id) -> void {
DumpNoNewline(file, inst_id);
llvm::errs() << '\n';
if (inst_id.is_valid()) {
Inst inst = file.insts().Get(inst_id);
if (inst.type_id().is_valid()) {
llvm::errs() << " - type ";
Dump(file, inst.type_id());
}
ConstantId const_id = file.constant_values().Get(inst_id);
if (const_id.is_valid()) {
InstId const_inst_id = file.constant_values().GetInstId(const_id);
llvm::errs() << " - value ";
if (const_inst_id == inst_id) {
llvm::errs() << const_id << '\n';
} else {
Dump(file, const_id);
}
}
}
}

LLVM_DUMP_METHOD auto Dump(const File& file, InterfaceId interface_id) -> void {
DumpNoNewline(file, interface_id);
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, NameId name_id) -> void {
llvm::errs() << name_id;
DumpIfValid(file, name_id);
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, NameScopeId name_scope_id)
-> void {
llvm::errs() << name_scope_id;
if (name_scope_id.is_valid()) {
auto name_scope = file.name_scopes().Get(name_scope_id);
llvm::errs() << ": " << name_scope;
if (name_scope.inst_id().is_valid()) {
llvm::errs() << " " << file.insts().Get(name_scope.inst_id());
}
DumpIfValid(file, name_scope.name_id());
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, SpecificId specific_id) -> void {
DumpNoNewline(file, specific_id);
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file,
StructTypeFieldsId struct_type_fields_id) -> void {
llvm::errs() << struct_type_fields_id;
if (struct_type_fields_id.is_valid()) {
llvm::errs() << ":";
auto block = file.struct_type_fields().Get(struct_type_fields_id);
for (auto field : block) {
llvm::errs() << "\n - " << field;
DumpIfValid(file, field.name_id);
if (field.type_id.is_valid()) {
InstId inst_id =
file.constant_values().GetInstId(field.type_id.AsConstantId());
llvm::errs() << ": " << StringifyTypeExpr(file, inst_id);
}
}
}
llvm::errs() << '\n';
}

LLVM_DUMP_METHOD auto Dump(const File& file, TypeBlockId type_block_id)
-> void {
llvm::errs() << type_block_id;
if (type_block_id.is_valid()) {
llvm::errs() << ":\n";
auto type_block = file.type_blocks().Get(type_block_id);
for (auto type_id : type_block) {
llvm::errs() << " - ";
Dump(file, type_id);
llvm::errs() << '\n';
}
} else {
llvm::errs() << '\n';
}
}

LLVM_DUMP_METHOD auto Dump(const File& file, TypeId type_id) -> void {
llvm::errs() << type_id;
if (type_id.is_valid()) {
InstId inst_id = file.constant_values().GetInstId(type_id.AsConstantId());
llvm::errs() << ": " << StringifyTypeExpr(file, inst_id) << "; "
<< file.insts().Get(inst_id);
}
llvm::errs() << '\n';
}

} // namespace Carbon::SemIR

#endif // NDEBUG
Loading
Loading