Răsfoiți Sursa

Add more `Dump` methods for debugging (#4747)

Follow-on to #4669 . Did some manual testing, but may have not exercised
all code paths.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
josh11b 1 an în urmă
părinte
comite
7edb0b8f59

+ 1 - 0
toolchain/check/BUILD

@@ -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.

+ 82 - 0
toolchain/check/dump.cpp

@@ -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 {
@@ -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 - 0
toolchain/driver/BUILD

@@ -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",

+ 14 - 0
toolchain/sem_ir/BUILD

@@ -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",

+ 243 - 0
toolchain/sem_ir/dump.cpp

@@ -0,0 +1,243 @@
+// 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 DumpNameIfValid(const File& file, NameId name_id) -> void {
+  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;
+    DumpNameIfValid(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;
+  if (class_id.is_valid()) {
+    auto class_obj = file.classes().Get(class_id);
+    llvm::errs() << ": " << class_obj;
+    DumpNameIfValid(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;
+  if (entity_name_id.is_valid()) {
+    auto entity_name = file.entity_names().Get(entity_name_id);
+    llvm::errs() << ": " << entity_name;
+    DumpNameIfValid(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;
+    DumpNameIfValid(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;
+  DumpNameIfValid(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());
+    }
+    DumpNameIfValid(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;
+      DumpNameIfValid(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);
+    }
+  } 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

+ 44 - 0
toolchain/sem_ir/dump.h

@@ -0,0 +1,44 @@
+// 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
+
+// This library contains functions to assist dumping objects to stderr during
+// interactive debugging. Functions named `Dump` are intended for direct use by
+// developers, and should use overload resolution to determine which will be
+// invoked. The debugger should do namespace resolution automatically. For
+// example:
+//
+// - lldb: `expr Dump(tokens, id)`
+// - gdb: `call Dump(tokens, id)`
+
+#ifndef CARBON_TOOLCHAIN_SEM_IR_DUMP_H_
+#define CARBON_TOOLCHAIN_SEM_IR_DUMP_H_
+
+#ifndef NDEBUG
+
+#include "toolchain/sem_ir/file.h"
+
+namespace Carbon::SemIR {
+
+auto Dump(const File& file, ClassId class_id) -> void;
+auto Dump(const File& file, ConstantId const_id) -> void;
+auto Dump(const File& file, EntityNameId entity_name_id) -> void;
+auto Dump(const File& file, FacetTypeId facet_type_id) -> void;
+auto Dump(const File& file, FunctionId function_id) -> void;
+auto Dump(const File& file, GenericId generic_id) -> void;
+auto Dump(const File& file, ImplId impl_id) -> void;
+auto Dump(const File& file, InstBlockId inst_block_id) -> void;
+auto Dump(const File& file, InstId inst_id) -> void;
+auto Dump(const File& file, InterfaceId interface_id) -> void;
+auto Dump(const File& file, NameId name_id) -> void;
+auto Dump(const File& file, NameScopeId name_scope_id) -> void;
+auto Dump(const File& file, SpecificId specific_id) -> void;
+auto Dump(const File& file, StructTypeFieldsId struct_type_fields_id) -> void;
+auto Dump(const File& file, TypeBlockId type_block_id) -> void;
+auto Dump(const File& file, TypeId type_id) -> void;
+
+}  // namespace Carbon::SemIR
+
+#endif  // NDEBUG
+
+#endif  // CARBON_TOOLCHAIN_SEM_IR_DUMP_H_