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();
......
...@@ -288,6 +288,15 @@ struct PeekInstruction : InstructionBase { ...@@ -288,6 +288,15 @@ struct PeekInstruction : InstructionBase {
base::Optional<const Type*> widened_type; base::Optional<const Type*> widened_type;
}; };
inline std::ostream& operator<<(std::ostream& os,
const PeekInstruction& instruction) {
os << "Peek " << instruction.slot;
if (instruction.widened_type) {
os << ", " << **instruction.widened_type;
}
return os;
}
struct PokeInstruction : InstructionBase { struct PokeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
...@@ -298,6 +307,15 @@ struct PokeInstruction : InstructionBase { ...@@ -298,6 +307,15 @@ struct PokeInstruction : InstructionBase {
base::Optional<const Type*> widened_type; base::Optional<const Type*> widened_type;
}; };
inline std::ostream& operator<<(std::ostream& os,
const PokeInstruction& instruction) {
os << "Poke " << instruction.slot;
if (instruction.widened_type) {
os << ", " << **instruction.widened_type;
}
return os;
}
// Preserve the top {preserved_slots} number of slots, and delete // Preserve the top {preserved_slots} number of slots, and delete
// {deleted_slots} number or slots below. // {deleted_slots} number or slots below.
struct DeleteRangeInstruction : InstructionBase { struct DeleteRangeInstruction : InstructionBase {
...@@ -307,6 +325,11 @@ struct DeleteRangeInstruction : InstructionBase { ...@@ -307,6 +325,11 @@ struct DeleteRangeInstruction : InstructionBase {
StackRange range; StackRange range;
}; };
inline std::ostream& operator<<(std::ostream& os,
const DeleteRangeInstruction& instruction) {
return os << "DeleteRange " << instruction.range;
}
struct PushUninitializedInstruction : InstructionBase { struct PushUninitializedInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit PushUninitializedInstruction(const Type* type) : type(type) {} explicit PushUninitializedInstruction(const Type* type) : type(type) {}
...@@ -316,6 +339,11 @@ struct PushUninitializedInstruction : InstructionBase { ...@@ -316,6 +339,11 @@ struct PushUninitializedInstruction : InstructionBase {
const Type* type; const Type* type;
}; };
inline std::ostream& operator<<(
std::ostream& os, const PushUninitializedInstruction& instruction) {
return os << "PushUninitialized " << *instruction.type;
}
struct PushBuiltinPointerInstruction : InstructionBase { struct PushBuiltinPointerInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
PushBuiltinPointerInstruction(std::string external_name, const Type* type) PushBuiltinPointerInstruction(std::string external_name, const Type* type)
...@@ -329,6 +357,13 @@ struct PushBuiltinPointerInstruction : InstructionBase { ...@@ -329,6 +357,13 @@ struct PushBuiltinPointerInstruction : InstructionBase {
const Type* type; const Type* type;
}; };
inline std::ostream& operator<<(
std::ostream& os, const PushBuiltinPointerInstruction& instruction) {
return os << "PushBuiltinPointer "
<< StringLiteralQuote(instruction.external_name) << ", "
<< *instruction.type;
}
struct NamespaceConstantInstruction : InstructionBase { struct NamespaceConstantInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit NamespaceConstantInstruction(NamespaceConstant* constant) explicit NamespaceConstantInstruction(NamespaceConstant* constant)
...@@ -340,6 +375,9 @@ struct NamespaceConstantInstruction : InstructionBase { ...@@ -340,6 +375,9 @@ struct NamespaceConstantInstruction : InstructionBase {
NamespaceConstant* constant; NamespaceConstant* constant;
}; };
std::ostream& operator<<(std::ostream& os,
const NamespaceConstantInstruction& instruction);
struct LoadReferenceInstruction : InstructionBase { struct LoadReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit LoadReferenceInstruction(const Type* type) : type(type) {} explicit LoadReferenceInstruction(const Type* type) : type(type) {}
...@@ -349,12 +387,22 @@ struct LoadReferenceInstruction : InstructionBase { ...@@ -349,12 +387,22 @@ struct LoadReferenceInstruction : InstructionBase {
const Type* type; const Type* type;
}; };
inline std::ostream& operator<<(std::ostream& os,
const LoadReferenceInstruction& instruction) {
return os << "LoadReference " << *instruction.type;
}
struct StoreReferenceInstruction : InstructionBase { struct StoreReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit StoreReferenceInstruction(const Type* type) : type(type) {} explicit StoreReferenceInstruction(const Type* type) : type(type) {}
const Type* type; const Type* type;
}; };
inline std::ostream& operator<<(std::ostream& os,
const StoreReferenceInstruction& instruction) {
return os << "StoreReference " << *instruction.type;
}
// Pops a bitfield struct; pushes a bitfield value extracted from it. // Pops a bitfield struct; pushes a bitfield value extracted from it.
struct LoadBitFieldInstruction : InstructionBase { struct LoadBitFieldInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
...@@ -368,6 +416,12 @@ struct LoadBitFieldInstruction : InstructionBase { ...@@ -368,6 +416,12 @@ struct LoadBitFieldInstruction : InstructionBase {
BitField bit_field; BitField bit_field;
}; };
inline std::ostream& operator<<(std::ostream& os,
const LoadBitFieldInstruction& instruction) {
return os << "LoadBitField " << *instruction.bit_field_struct_type << ", "
<< instruction.bit_field.name_and_type.name;
}
// Pops a bitfield value and a bitfield struct; pushes a new bitfield struct // Pops a bitfield value and a bitfield struct; pushes a new bitfield struct
// containing the updated value. // containing the updated value.
struct StoreBitFieldInstruction : InstructionBase { struct StoreBitFieldInstruction : InstructionBase {
...@@ -386,6 +440,16 @@ struct StoreBitFieldInstruction : InstructionBase { ...@@ -386,6 +440,16 @@ struct StoreBitFieldInstruction : InstructionBase {
bool starts_as_zero; bool starts_as_zero;
}; };
inline std::ostream& operator<<(std::ostream& os,
const StoreBitFieldInstruction& instruction) {
os << "StoreBitField " << *instruction.bit_field_struct_type << ", "
<< instruction.bit_field.name_and_type.name;
if (instruction.starts_as_zero) {
os << ", starts_as_zero";
}
return os;
}
struct CallIntrinsicInstruction : InstructionBase { struct CallIntrinsicInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
CallIntrinsicInstruction(Intrinsic* intrinsic, CallIntrinsicInstruction(Intrinsic* intrinsic,
...@@ -403,6 +467,9 @@ struct CallIntrinsicInstruction : InstructionBase { ...@@ -403,6 +467,9 @@ struct CallIntrinsicInstruction : InstructionBase {
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
}; };
std::ostream& operator<<(std::ostream& os,
const CallIntrinsicInstruction& instruction);
struct CallCsaMacroInstruction : InstructionBase { struct CallCsaMacroInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroInstruction(Macro* macro, CallCsaMacroInstruction(Macro* macro,
...@@ -424,6 +491,9 @@ struct CallCsaMacroInstruction : InstructionBase { ...@@ -424,6 +491,9 @@ struct CallCsaMacroInstruction : InstructionBase {
base::Optional<Block*> catch_block; base::Optional<Block*> catch_block;
}; };
std::ostream& operator<<(std::ostream& os,
const CallCsaMacroInstruction& instruction);
struct CallCsaMacroAndBranchInstruction : InstructionBase { struct CallCsaMacroAndBranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
CallCsaMacroAndBranchInstruction(Macro* macro, CallCsaMacroAndBranchInstruction(Macro* macro,
...@@ -458,6 +528,9 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase { ...@@ -458,6 +528,9 @@ struct CallCsaMacroAndBranchInstruction : InstructionBase {
base::Optional<Block*> catch_block; base::Optional<Block*> catch_block;
}; };
std::ostream& operator<<(std::ostream& os,
const CallCsaMacroAndBranchInstruction& instruction);
struct MakeLazyNodeInstruction : InstructionBase { struct MakeLazyNodeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
MakeLazyNodeInstruction(Macro* macro, const Type* result_type, MakeLazyNodeInstruction(Macro* macro, const Type* result_type,
...@@ -473,6 +546,9 @@ struct MakeLazyNodeInstruction : InstructionBase { ...@@ -473,6 +546,9 @@ struct MakeLazyNodeInstruction : InstructionBase {
std::vector<std::string> constexpr_arguments; std::vector<std::string> constexpr_arguments;
}; };
std::ostream& operator<<(std::ostream& os,
const MakeLazyNodeInstruction& instruction);
struct CallBuiltinInstruction : InstructionBase { struct CallBuiltinInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return is_tailcall; } bool IsBlockTerminator() const override { return is_tailcall; }
...@@ -496,6 +572,9 @@ struct CallBuiltinInstruction : InstructionBase { ...@@ -496,6 +572,9 @@ struct CallBuiltinInstruction : InstructionBase {
base::Optional<Block*> catch_block; base::Optional<Block*> catch_block;
}; };
std::ostream& operator<<(std::ostream& os,
const CallBuiltinInstruction& instruction);
struct CallBuiltinPointerInstruction : InstructionBase { struct CallBuiltinPointerInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return is_tailcall; } bool IsBlockTerminator() const override { return is_tailcall; }
...@@ -511,6 +590,16 @@ struct CallBuiltinPointerInstruction : InstructionBase { ...@@ -511,6 +590,16 @@ struct CallBuiltinPointerInstruction : InstructionBase {
size_t argc; size_t argc;
}; };
inline std::ostream& operator<<(
std::ostream& os, const CallBuiltinPointerInstruction& instruction) {
os << "CallBuiltinPointer " << *instruction.type
<< ", argc: " << instruction.argc;
if (instruction.is_tailcall) {
os << ", is_tailcall";
}
return os;
}
struct CallRuntimeInstruction : InstructionBase { struct CallRuntimeInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override; bool IsBlockTerminator() const override;
...@@ -535,6 +624,9 @@ struct CallRuntimeInstruction : InstructionBase { ...@@ -535,6 +624,9 @@ struct CallRuntimeInstruction : InstructionBase {
base::Optional<Block*> catch_block; base::Optional<Block*> catch_block;
}; };
std::ostream& operator<<(std::ostream& os,
const CallRuntimeInstruction& instruction);
struct BranchInstruction : InstructionBase { struct BranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; } bool IsBlockTerminator() const override { return true; }
...@@ -550,6 +642,9 @@ struct BranchInstruction : InstructionBase { ...@@ -550,6 +642,9 @@ struct BranchInstruction : InstructionBase {
Block* if_false; Block* if_false;
}; };
std::ostream& operator<<(std::ostream& os,
const BranchInstruction& instruction);
struct ConstexprBranchInstruction : InstructionBase { struct ConstexprBranchInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; } bool IsBlockTerminator() const override { return true; }
...@@ -567,6 +662,9 @@ struct ConstexprBranchInstruction : InstructionBase { ...@@ -567,6 +662,9 @@ struct ConstexprBranchInstruction : InstructionBase {
Block* if_false; Block* if_false;
}; };
std::ostream& operator<<(std::ostream& os,
const ConstexprBranchInstruction& instruction);
struct GotoInstruction : InstructionBase { struct GotoInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; } bool IsBlockTerminator() const override { return true; }
...@@ -579,6 +677,8 @@ struct GotoInstruction : InstructionBase { ...@@ -579,6 +677,8 @@ struct GotoInstruction : InstructionBase {
Block* destination; Block* destination;
}; };
std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction);
struct GotoExternalInstruction : InstructionBase { struct GotoExternalInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
bool IsBlockTerminator() const override { return true; } bool IsBlockTerminator() const override { return true; }
...@@ -592,6 +692,15 @@ struct GotoExternalInstruction : InstructionBase { ...@@ -592,6 +692,15 @@ struct GotoExternalInstruction : InstructionBase {
std::vector<std::string> variable_names; std::vector<std::string> variable_names;
}; };
inline std::ostream& operator<<(std::ostream& os,
const GotoExternalInstruction& instruction) {
os << "GotoExternal " << instruction.destination;
for (const std::string& name : instruction.variable_names) {
os << ", " << name;
}
return os;
}
struct ReturnInstruction : InstructionBase { struct ReturnInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit ReturnInstruction(size_t count) : count(count) {} explicit ReturnInstruction(size_t count) : count(count) {}
...@@ -600,6 +709,11 @@ struct ReturnInstruction : InstructionBase { ...@@ -600,6 +709,11 @@ struct ReturnInstruction : InstructionBase {
size_t count; // How many values to return. size_t count; // How many values to return.
}; };
inline std::ostream& operator<<(std::ostream& os,
const ReturnInstruction& instruction) {
return os << "Return count: " << instruction.count;
}
struct PrintConstantStringInstruction : InstructionBase { struct PrintConstantStringInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit PrintConstantStringInstruction(std::string message) explicit PrintConstantStringInstruction(std::string message)
...@@ -608,17 +722,39 @@ struct PrintConstantStringInstruction : InstructionBase { ...@@ -608,17 +722,39 @@ struct PrintConstantStringInstruction : InstructionBase {
std::string message; std::string message;
}; };
inline std::ostream& operator<<(
std::ostream& os, const PrintConstantStringInstruction& instruction) {
return os << "PrintConstantString "
<< StringLiteralQuote(instruction.message);
}
struct AbortInstruction : InstructionBase { struct AbortInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure }; enum class Kind { kDebugBreak, kUnreachable, kAssertionFailure };
bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; } bool IsBlockTerminator() const override { return kind != Kind::kDebugBreak; }
explicit AbortInstruction(Kind kind, std::string message = "") explicit AbortInstruction(Kind kind, std::string message = "")
: kind(kind), message(std::move(message)) {} : kind(kind), message(std::move(message)) {}
static const char* KindToString(Kind kind) {
switch (kind) {
case Kind::kDebugBreak:
return "kDebugBreak";
case Kind::kUnreachable:
return "kUnreachable";
case Kind::kAssertionFailure:
return "kAssertionFailure";
}
}
Kind kind; Kind kind;
std::string message; std::string message;
}; };
inline std::ostream& operator<<(std::ostream& os,
const AbortInstruction& instruction) {
return os << "Abort " << AbortInstruction::KindToString(instruction.kind)
<< ", " << StringLiteralQuote(instruction.message);
}
struct UnsafeCastInstruction : InstructionBase { struct UnsafeCastInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE() TORQUE_INSTRUCTION_BOILERPLATE()
explicit UnsafeCastInstruction(const Type* destination_type) explicit UnsafeCastInstruction(const Type* destination_type)
...@@ -629,6 +765,11 @@ struct UnsafeCastInstruction : InstructionBase { ...@@ -629,6 +765,11 @@ struct UnsafeCastInstruction : InstructionBase {
const Type* destination_type; const Type* destination_type;
}; };
inline std::ostream& operator<<(std::ostream& os,
const UnsafeCastInstruction& instruction) {
return os << "UnsafeCast " << *instruction.destination_type;
}
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -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 {
...@@ -31,8 +33,11 @@ void TorqueCodeGenerator::EmitInstruction(const Instruction& instruction, ...@@ -31,8 +33,11 @@ void TorqueCodeGenerator::EmitInstruction(const Instruction& instruction,
#endif #endif
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