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() {
# file generation
v8_verify_torque_generation_invariance = false
# Generate comments describing the Torque intermediate representation.
v8_annotate_torque_ir = false
# Disable all snapshot compression.
v8_enable_snapshot_compression = true
......@@ -1537,6 +1540,9 @@ template("run_torque") {
"-v8-root",
rebase_path(".", root_build_dir),
]
if (v8_annotate_torque_ir) {
args += [ "-annotate-ir" ]
}
if (defined(invoker.args)) {
args += invoker.args
}
......
......@@ -14,6 +14,7 @@ DEFINE_CONTEXTUAL_VARIABLE(TargetArchitecture)
GlobalContext::GlobalContext(Ast ast)
: collect_language_server_data_(false),
force_assert_statements_(false),
annotate_ir_(false),
ast_(std::move(ast)) {
CurrentScope::Scope current_scope(nullptr);
CurrentSourcePosition::Scope current_source_position(
......
......@@ -54,6 +54,8 @@ class GlobalContext : public ContextualClass<GlobalContext> {
static bool 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 std::string MakeUniqueName(const std::string& base) {
return base + "_" + std::to_string(Get().fresh_ids_[base]++);
......@@ -106,6 +108,7 @@ class GlobalContext : public ContextualClass<GlobalContext> {
private:
bool collect_language_server_data_;
bool force_assert_statements_;
bool annotate_ir_;
Namespace* default_namespace_;
Ast ast_;
std::vector<std::unique_ptr<Declarable>> declarables_;
......
......@@ -129,6 +129,11 @@ DefinitionLocation NamespaceConstantInstruction::GetValueDefinition(
return DefinitionLocation::Instruction(this, index);
}
std::ostream& operator<<(std::ostream& os,
const NamespaceConstantInstruction& instruction) {
return os << "NamespaceConstant " << instruction.constant->external_name();
}
void InstructionBase::InvalidateTransientTypes(
Stack<const Type*>* stack) const {
auto current = stack->begin();
......@@ -183,6 +188,22 @@ DefinitionLocation CallIntrinsicInstruction::GetValueDefinition(
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,
ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
......@@ -243,6 +264,18 @@ DefinitionLocation CallCsaMacroInstruction::GetValueDefinition(
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(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
std::vector<const Type*> parameter_types =
......@@ -363,6 +396,26 @@ CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const {
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,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
......@@ -447,6 +500,19 @@ DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition(
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,
ControlFlowGraph* cfg) const {
std::vector<const Type*> argument_types = stack->PopMany(argc);
......@@ -507,6 +573,19 @@ CallRuntimeInstruction::GetExceptionObjectDefinition() const {
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,
ControlFlowGraph* cfg) const {
const Type* condition_type = stack->Pop();
......@@ -524,6 +603,12 @@ void BranchInstruction::RecomputeDefinitionLocations(
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,
ControlFlowGraph* cfg) const {
if_true->SetInputTypes(*stack);
......@@ -536,6 +621,13 @@ void ConstexprBranchInstruction::RecomputeDefinitionLocations(
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,
ControlFlowGraph* cfg) const {
destination->SetInputTypes(*stack);
......@@ -546,6 +638,10 @@ void GotoInstruction::RecomputeDefinitionLocations(
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,
ControlFlowGraph* cfg) const {
if (variable_names.size() != stack->Size()) {
......@@ -693,6 +789,16 @@ DefinitionLocation MakeLazyNodeInstruction::GetValueDefinition() const {
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 {
return is_tailcall || runtime_function->signature().return_type ==
TypeOracle::GetNeverType();
......
This diff is collapsed.
......@@ -4,6 +4,8 @@
#include "src/torque/torque-code-generator.h"
#include "src/torque/global-context.h"
namespace v8 {
namespace internal {
namespace torque {
......@@ -31,8 +33,11 @@ void TorqueCodeGenerator::EmitInstruction(const Instruction& instruction,
#endif
switch (instruction.kind()) {
#define ENUM_ITEM(T) \
case InstructionKind::k##T: \
#define ENUM_ITEM(T) \
case InstructionKind::k##T: \
if (GlobalContext::annotate_ir()) { \
EmitIRAnnotation(instruction.Cast<T>(), stack); \
} \
return EmitInstruction(instruction.Cast<T>(), stack);
TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
#undef ENUM_ITEM
......
......@@ -74,6 +74,12 @@ class TorqueCodeGenerator {
void EmitInstruction(const Instruction& instruction,
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) \
void EmitInstruction(const T& instruction, Stack<std::string>* stack);
TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION)
......
......@@ -53,6 +53,9 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
if (options.force_assert_statements) {
GlobalContext::SetForceAssertStatements();
}
if (options.annotate_ir) {
GlobalContext::SetAnnotateIR();
}
TargetArchitecture::Scope target_architecture(options.force_32bit_output);
TypeOracle::Scope type_oracle;
CurrentScope::Scope current_namespace(GlobalContext::GetDefaultNamespace());
......
......@@ -30,6 +30,9 @@ struct TorqueCompilerOptions {
// architectures. Note that this does not needed in Chromium/V8 land, since we
// always build with the same bit width as the target architecture.
bool force_32bit_output = false;
// Adds extra comments in output that show Torque intermediate representation.
bool annotate_ir = false;
};
struct TorqueCompilerResult {
......
......@@ -34,6 +34,8 @@ int WrappedMain(int argc, const char** argv) {
options.v8_root = std::string(argv[++i]);
} else if (argument == "-m32") {
options.force_32bit_output = true;
} else if (argument == "-annotate-ir") {
options.annotate_ir = true;
} else {
// Otherwise it's a .tq file. Remember it for compilation.
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