Commit ad0e581c authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[torque] Add option for printing Torque IR

While working on the Torque compiler, I've sometimes found it difficult
to understand Torque's intermediate representation and how it
corresponds to the output. In this change, I propose adding a build flag
that instructs Torque to emit comments describing its IR, interspersed
in the generated code. This is particularly useful for seeing the stack
management instructions (Peek, Poke, and DeleteRange) which don't emit
any corresponding C++ code.

Bug: v8:7793
Change-Id: I24bdec47da76c9bd751b928d3cd92aa513dc6593
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2748040Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#73352}
parent df748fc0
...@@ -252,6 +252,9 @@ declare_args() { ...@@ -252,6 +252,9 @@ declare_args() {
# file generation # file generation
v8_verify_torque_generation_invariance = false v8_verify_torque_generation_invariance = false
# Generate comments describing the Torque intermediate representation.
v8_annotate_torque_ir = false
# Disable all snapshot compression. # Disable all snapshot compression.
v8_enable_snapshot_compression = true v8_enable_snapshot_compression = true
...@@ -1537,6 +1540,9 @@ template("run_torque") { ...@@ -1537,6 +1540,9 @@ template("run_torque") {
"-v8-root", "-v8-root",
rebase_path(".", root_build_dir), rebase_path(".", root_build_dir),
] ]
if (v8_annotate_torque_ir) {
args += [ "-annotate-ir" ]
}
if (defined(invoker.args)) { if (defined(invoker.args)) {
args += invoker.args args += invoker.args
} }
......
...@@ -14,6 +14,7 @@ DEFINE_CONTEXTUAL_VARIABLE(TargetArchitecture) ...@@ -14,6 +14,7 @@ DEFINE_CONTEXTUAL_VARIABLE(TargetArchitecture)
GlobalContext::GlobalContext(Ast ast) GlobalContext::GlobalContext(Ast ast)
: collect_language_server_data_(false), : collect_language_server_data_(false),
force_assert_statements_(false), force_assert_statements_(false),
annotate_ir_(false),
ast_(std::move(ast)) { ast_(std::move(ast)) {
CurrentScope::Scope current_scope(nullptr); CurrentScope::Scope current_scope(nullptr);
CurrentSourcePosition::Scope current_source_position( CurrentSourcePosition::Scope current_source_position(
......
...@@ -54,6 +54,8 @@ class GlobalContext : public ContextualClass<GlobalContext> { ...@@ -54,6 +54,8 @@ class GlobalContext : public ContextualClass<GlobalContext> {
static bool force_assert_statements() { static bool force_assert_statements() {
return Get().force_assert_statements_; return Get().force_assert_statements_;
} }
static void SetAnnotateIR() { Get().annotate_ir_ = true; }
static bool annotate_ir() { return Get().annotate_ir_; }
static Ast* ast() { return &Get().ast_; } static Ast* ast() { return &Get().ast_; }
static std::string MakeUniqueName(const std::string& base) { static std::string MakeUniqueName(const std::string& base) {
return base + "_" + std::to_string(Get().fresh_ids_[base]++); return base + "_" + std::to_string(Get().fresh_ids_[base]++);
...@@ -106,6 +108,7 @@ class GlobalContext : public ContextualClass<GlobalContext> { ...@@ -106,6 +108,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
private: private:
bool collect_language_server_data_; bool collect_language_server_data_;
bool force_assert_statements_; bool force_assert_statements_;
bool annotate_ir_;
Namespace* default_namespace_; Namespace* default_namespace_;
Ast ast_; Ast ast_;
std::vector<std::unique_ptr<Declarable>> declarables_; std::vector<std::unique_ptr<Declarable>> declarables_;
......
...@@ -129,6 +129,11 @@ DefinitionLocation NamespaceConstantInstruction::GetValueDefinition( ...@@ -129,6 +129,11 @@ DefinitionLocation NamespaceConstantInstruction::GetValueDefinition(
return DefinitionLocation::Instruction(this, index); return DefinitionLocation::Instruction(this, index);
} }
std::ostream& operator<<(std::ostream& os,
const NamespaceConstantInstruction& instruction) {
return os << "NamespaceConstant " << instruction.constant->external_name();
}
void InstructionBase::InvalidateTransientTypes( void InstructionBase::InvalidateTransientTypes(
Stack<const Type*>* stack) const { Stack<const Type*>* stack) const {
auto current = stack->begin(); auto current = stack->begin();
...@@ -183,6 +188,22 @@ DefinitionLocation CallIntrinsicInstruction::GetValueDefinition( ...@@ -183,6 +188,22 @@ DefinitionLocation CallIntrinsicInstruction::GetValueDefinition(
return DefinitionLocation::Instruction(this, index); return DefinitionLocation::Instruction(this, index);
} }
std::ostream& operator<<(std::ostream& os,
const CallIntrinsicInstruction& instruction) {
os << "CallIntrinsic " << instruction.intrinsic->ReadableName();
if (!instruction.specialization_types.empty()) {
os << "<";
PrintCommaSeparatedList(
os, instruction.specialization_types,
[](const Type* type) -> const Type& { return *type; });
os << ">";
}
os << "(";
PrintCommaSeparatedList(os, instruction.constexpr_arguments);
os << ")";
return os;
}
void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack, void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types = std::vector<const Type*> parameter_types =
...@@ -243,6 +264,18 @@ DefinitionLocation CallCsaMacroInstruction::GetValueDefinition( ...@@ -243,6 +264,18 @@ DefinitionLocation CallCsaMacroInstruction::GetValueDefinition(
return DefinitionLocation::Instruction(this, index); return DefinitionLocation::Instruction(this, index);
} }
std::ostream& operator<<(std::ostream& os,
const CallCsaMacroInstruction& instruction) {
os << "CallCsaMacro " << instruction.macro->ReadableName();
os << "(";
PrintCommaSeparatedList(os, instruction.constexpr_arguments);
os << ")";
if (instruction.catch_block) {
os << ", catch block " << (*instruction.catch_block)->id();
}
return os;
}
void CallCsaMacroAndBranchInstruction::TypeInstruction( void CallCsaMacroAndBranchInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const { Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types = std::vector<const Type*> parameter_types =
...@@ -363,6 +396,26 @@ CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const { ...@@ -363,6 +396,26 @@ CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const {
return DefinitionLocation::Instruction(this, GetValueDefinitionCount()); return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
} }
std::ostream& operator<<(std::ostream& os,
const CallCsaMacroAndBranchInstruction& instruction) {
os << "CallCsaMacroAndBranch " << instruction.macro->ReadableName();
os << "(";
PrintCommaSeparatedList(os, instruction.constexpr_arguments);
os << ")";
if (instruction.return_continuation) {
os << ", return continuation " << (*instruction.return_continuation)->id();
}
if (!instruction.label_blocks.empty()) {
os << ", label blocks ";
PrintCommaSeparatedList(os, instruction.label_blocks,
[](Block* block) { return block->id(); });
}
if (instruction.catch_block) {
os << ", catch block " << (*instruction.catch_block)->id();
}
return os;
}
void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack, void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc); std::vector<const Type*> argument_types = stack->PopMany(argc);
...@@ -447,6 +500,19 @@ DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition( ...@@ -447,6 +500,19 @@ DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition(
return DefinitionLocation::Instruction(this, index); return DefinitionLocation::Instruction(this, index);
} }
std::ostream& operator<<(std::ostream& os,
const CallBuiltinInstruction& instruction) {
os << "CallBuiltin " << instruction.builtin->ReadableName()
<< ", argc: " << instruction.argc;
if (instruction.is_tailcall) {
os << ", is_tailcall";
}
if (instruction.catch_block) {
os << ", catch block " << (*instruction.catch_block)->id();
}
return os;
}
void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack, void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc); std::vector<const Type*> argument_types = stack->PopMany(argc);
...@@ -507,6 +573,19 @@ CallRuntimeInstruction::GetExceptionObjectDefinition() const { ...@@ -507,6 +573,19 @@ CallRuntimeInstruction::GetExceptionObjectDefinition() const {
return DefinitionLocation::Instruction(this, GetValueDefinitionCount()); return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
} }
std::ostream& operator<<(std::ostream& os,
const CallRuntimeInstruction& instruction) {
os << "CallRuntime " << instruction.runtime_function->ReadableName()
<< ", argc: " << instruction.argc;
if (instruction.is_tailcall) {
os << ", is_tailcall";
}
if (instruction.catch_block) {
os << ", catch block " << (*instruction.catch_block)->id();
}
return os;
}
void BranchInstruction::TypeInstruction(Stack<const Type*>* stack, void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
const Type* condition_type = stack->Pop(); const Type* condition_type = stack->Pop();
...@@ -524,6 +603,12 @@ void BranchInstruction::RecomputeDefinitionLocations( ...@@ -524,6 +603,12 @@ void BranchInstruction::RecomputeDefinitionLocations(
if_false->MergeInputDefinitions(*locations, worklist); if_false->MergeInputDefinitions(*locations, worklist);
} }
std::ostream& operator<<(std::ostream& os,
const BranchInstruction& instruction) {
return os << "Branch true: " << instruction.if_true->id()
<< ", false: " << instruction.if_false->id();
}
void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack, void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
if_true->SetInputTypes(*stack); if_true->SetInputTypes(*stack);
...@@ -536,6 +621,13 @@ void ConstexprBranchInstruction::RecomputeDefinitionLocations( ...@@ -536,6 +621,13 @@ void ConstexprBranchInstruction::RecomputeDefinitionLocations(
if_false->MergeInputDefinitions(*locations, worklist); if_false->MergeInputDefinitions(*locations, worklist);
} }
std::ostream& operator<<(std::ostream& os,
const ConstexprBranchInstruction& instruction) {
return os << "ConstexprBranch " << instruction.condition
<< ", true: " << instruction.if_true->id()
<< ", false: " << instruction.if_false->id();
}
void GotoInstruction::TypeInstruction(Stack<const Type*>* stack, void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
destination->SetInputTypes(*stack); destination->SetInputTypes(*stack);
...@@ -546,6 +638,10 @@ void GotoInstruction::RecomputeDefinitionLocations( ...@@ -546,6 +638,10 @@ void GotoInstruction::RecomputeDefinitionLocations(
destination->MergeInputDefinitions(*locations, worklist); destination->MergeInputDefinitions(*locations, worklist);
} }
std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction) {
return os << "Goto " << instruction.destination->id();
}
void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack, void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const { ControlFlowGraph* cfg) const {
if (variable_names.size() != stack->Size()) { if (variable_names.size() != stack->Size()) {
...@@ -693,6 +789,16 @@ DefinitionLocation MakeLazyNodeInstruction::GetValueDefinition() const { ...@@ -693,6 +789,16 @@ DefinitionLocation MakeLazyNodeInstruction::GetValueDefinition() const {
return DefinitionLocation::Instruction(this, 0); return DefinitionLocation::Instruction(this, 0);
} }
std::ostream& operator<<(std::ostream& os,
const MakeLazyNodeInstruction& instruction) {
os << "MakeLazyNode " << instruction.macro->ReadableName() << ", "
<< *instruction.result_type;
for (const std::string& arg : instruction.constexpr_arguments) {
os << ", " << arg;
}
return os;
}
bool CallRuntimeInstruction::IsBlockTerminator() const { bool CallRuntimeInstruction::IsBlockTerminator() const {
return is_tailcall || runtime_function->signature().return_type == return is_tailcall || runtime_function->signature().return_type ==
TypeOracle::GetNeverType(); TypeOracle::GetNeverType();
......
This diff is collapsed.
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "src/torque/torque-code-generator.h" #include "src/torque/torque-code-generator.h"
#include "src/torque/global-context.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace torque { namespace torque {
...@@ -33,6 +35,9 @@ void TorqueCodeGenerator::EmitInstruction(const Instruction& instruction, ...@@ -33,6 +35,9 @@ void TorqueCodeGenerator::EmitInstruction(const Instruction& instruction,
switch (instruction.kind()) { switch (instruction.kind()) {
#define ENUM_ITEM(T) \ #define ENUM_ITEM(T) \
case InstructionKind::k##T: \ case InstructionKind::k##T: \
if (GlobalContext::annotate_ir()) { \
EmitIRAnnotation(instruction.Cast<T>(), stack); \
} \
return EmitInstruction(instruction.Cast<T>(), stack); return EmitInstruction(instruction.Cast<T>(), stack);
TORQUE_INSTRUCTION_LIST(ENUM_ITEM) TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
#undef ENUM_ITEM #undef ENUM_ITEM
......
...@@ -74,6 +74,12 @@ class TorqueCodeGenerator { ...@@ -74,6 +74,12 @@ class TorqueCodeGenerator {
void EmitInstruction(const Instruction& instruction, void EmitInstruction(const Instruction& instruction,
Stack<std::string>* stack); Stack<std::string>* stack);
template <typename T>
void EmitIRAnnotation(const T& instruction, Stack<std::string>* stack) {
out() << " // " << instruction
<< ", starting stack size: " << stack->Size() << "\n";
}
#define EMIT_INSTRUCTION_DECLARATION(T) \ #define EMIT_INSTRUCTION_DECLARATION(T) \
void EmitInstruction(const T& instruction, Stack<std::string>* stack); void EmitInstruction(const T& instruction, Stack<std::string>* stack);
TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION) TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION)
......
...@@ -53,6 +53,9 @@ void CompileCurrentAst(TorqueCompilerOptions options) { ...@@ -53,6 +53,9 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
if (options.force_assert_statements) { if (options.force_assert_statements) {
GlobalContext::SetForceAssertStatements(); GlobalContext::SetForceAssertStatements();
} }
if (options.annotate_ir) {
GlobalContext::SetAnnotateIR();
}
TargetArchitecture::Scope target_architecture(options.force_32bit_output); TargetArchitecture::Scope target_architecture(options.force_32bit_output);
TypeOracle::Scope type_oracle; TypeOracle::Scope type_oracle;
CurrentScope::Scope current_namespace(GlobalContext::GetDefaultNamespace()); CurrentScope::Scope current_namespace(GlobalContext::GetDefaultNamespace());
......
...@@ -30,6 +30,9 @@ struct TorqueCompilerOptions { ...@@ -30,6 +30,9 @@ struct TorqueCompilerOptions {
// architectures. Note that this does not needed in Chromium/V8 land, since we // architectures. Note that this does not needed in Chromium/V8 land, since we
// always build with the same bit width as the target architecture. // always build with the same bit width as the target architecture.
bool force_32bit_output = false; bool force_32bit_output = false;
// Adds extra comments in output that show Torque intermediate representation.
bool annotate_ir = false;
}; };
struct TorqueCompilerResult { struct TorqueCompilerResult {
......
...@@ -34,6 +34,8 @@ int WrappedMain(int argc, const char** argv) { ...@@ -34,6 +34,8 @@ int WrappedMain(int argc, const char** argv) {
options.v8_root = std::string(argv[++i]); options.v8_root = std::string(argv[++i]);
} else if (argument == "-m32") { } else if (argument == "-m32") {
options.force_32bit_output = true; options.force_32bit_output = true;
} else if (argument == "-annotate-ir") {
options.annotate_ir = true;
} else { } else {
// Otherwise it's a .tq file. Remember it for compilation. // Otherwise it's a .tq file. Remember it for compilation.
files.emplace_back(std::move(argument)); files.emplace_back(std::move(argument));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment