[turbofan] Add instruction ranges to --trace-turbo

Bug: v8:7327
Change-Id: I6f378f0d36444e8413dfe7ad3e097091e3b86df1
Reviewed-on: https://chromium-review.googlesource.com/1098919
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53712}
This commit is contained in:
Sigurd Schneider 2018-06-13 17:50:21 +02:00 committed by Commit Bot
parent 0fe56b84d5
commit e5e15e579e
8 changed files with 181 additions and 26 deletions

View File

@ -78,7 +78,9 @@ CodeGenerator::CodeGenerator(Zone* codegen_zone, Frame* frame, Linkage* linkage,
SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS),
wasm_compilation_data_(wasm_compilation_data),
result_(kSuccess),
poisoning_level_(poisoning_level) {
poisoning_level_(poisoning_level),
block_starts_(zone()),
instr_starts_(zone()) {
for (int i = 0; i < code->InstructionBlockCount(); ++i) {
new (&labels_[i]) Label;
}
@ -179,6 +181,10 @@ void CodeGenerator::AssembleCode() {
unwinding_info_writer_.SetNumberOfInstructionBlocks(
code()->InstructionBlockCount());
if (info->trace_turbo_json_enabled()) {
block_starts_.assign(code()->instruction_blocks().size(), -1);
instr_starts_.assign(code()->instructions().size(), -1);
}
// Assemble all non-deferred blocks, followed by deferred ones.
for (int deferred = 0; deferred < 2; ++deferred) {
for (const InstructionBlock* block : code()->instruction_blocks()) {
@ -190,6 +196,9 @@ void CodeGenerator::AssembleCode() {
if (block->IsLoopHeader() && !tasm()->jump_optimization_info()) {
tasm()->Align(16);
}
if (info->trace_turbo_json_enabled()) {
block_starts_[block->rpo_number().ToInt()] = tasm()->pc_offset();
}
// Bind a label for a block.
current_block_ = block->rpo_number();
unwinding_info_writer_.BeginInstructionBlock(tasm()->pc_offset(), block);
@ -436,6 +445,9 @@ bool CodeGenerator::IsMaterializableFromRoot(
CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock(
const InstructionBlock* block) {
for (int i = block->code_start(); i < block->code_end(); ++i) {
if (info()->trace_turbo_json_enabled()) {
instr_starts_[i] = tasm()->pc_offset();
}
Instruction* instr = code()->InstructionAt(i);
CodeGenResult result = AssembleInstruction(instr, block);
if (result != kSuccess) return result;

View File

@ -123,6 +123,9 @@ class CodeGenerator final : public GapResolver::Assembler {
size_t GetSafepointTableOffset() const { return safepoints_.GetCodeOffset(); }
size_t GetHandlerTableOffset() const { return handler_table_offset_; }
const ZoneVector<int>& block_starts() const { return block_starts_; }
const ZoneVector<int>& instr_starts() const { return instr_starts_; }
private:
GapResolver* resolver() { return &resolver_; }
SafepointTableBuilder* safepoints() { return &safepoints_; }
@ -419,6 +422,8 @@ class CodeGenerator final : public GapResolver::Assembler {
WasmCompilationData* wasm_compilation_data_;
CodeGenResult result_;
PoisoningMitigationLevel poisoning_level_;
ZoneVector<int> block_starts_;
ZoneVector<int> instr_starts_;
};
} // namespace compiler

View File

@ -32,12 +32,19 @@ namespace v8 {
namespace internal {
namespace compiler {
const char* get_cached_trace_turbo_filename(OptimizedCompilationInfo* info) {
if (!info->trace_turbo_filename()) {
info->set_trace_turbo_filename(
GetVisualizerLogFileName(info, FLAG_trace_turbo_path, nullptr, "json"));
}
return info->trace_turbo_filename();
}
TurboJsonFile::TurboJsonFile(OptimizedCompilationInfo* info,
std::ios_base::openmode mode)
: std::ofstream(
GetVisualizerLogFileName(info, FLAG_trace_turbo_path, nullptr, "json")
.get(),
mode) {}
: std::ofstream(get_cached_trace_turbo_filename(info), mode) {}
TurboJsonFile::~TurboJsonFile() { flush(); }
std::ostream& operator<<(std::ostream& out,
const SourcePositionAsJSON& asJSON) {

View File

@ -30,6 +30,7 @@ class SourcePositionTable;
struct TurboJsonFile : public std::ofstream {
TurboJsonFile(OptimizedCompilationInfo* info, std::ios_base::openmode mode);
~TurboJsonFile();
};
struct SourcePositionAsJSON {

View File

@ -28,7 +28,7 @@ InstructionSelector::InstructionSelector(
SourcePositionMode source_position_mode, Features features,
EnableScheduling enable_scheduling,
EnableSerialization enable_serialization,
PoisoningMitigationLevel poisoning_level)
PoisoningMitigationLevel poisoning_level, EnableTraceTurboJson trace_turbo)
: zone_(zone),
linkage_(linkage),
sequence_(sequence),
@ -52,10 +52,16 @@ InstructionSelector::InstructionSelector(
enable_switch_jump_table_(enable_switch_jump_table),
poisoning_level_(poisoning_level),
frame_(frame),
instruction_selection_failed_(false) {
instruction_selection_failed_(false),
instr_origins_(sequence->zone()),
trace_turbo_(trace_turbo) {
instructions_.reserve(node_count);
continuation_inputs_.reserve(5);
continuation_outputs_.reserve(2);
if (trace_turbo_ == kEnableTraceTurboJson) {
instr_origins_.assign(node_count, {-1, 0});
}
}
bool InstructionSelector::SelectInstructions() {
@ -1092,13 +1098,18 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
// Visit code in reverse control flow order, because architecture-specific
// matching may cover more than one node at a time.
for (auto node : base::Reversed(*block)) {
// Skip nodes that are unused or already defined.
if (!IsUsed(node) || IsDefined(node)) continue;
// Generate code for this node "top down", but schedule the code "bottom
// up".
int current_node_end = current_num_instructions();
VisitNode(node);
if (!FinishEmittedInstructions(node, current_node_end)) return;
// Skip nodes that are unused or already defined.
if (IsUsed(node) && !IsDefined(node)) {
// Generate code for this node "top down", but schedule the code "bottom
// up".
VisitNode(node);
if (!FinishEmittedInstructions(node, current_node_end)) return;
}
if (trace_turbo_ == kEnableTraceTurboJson) {
instr_origins_[node->id()] = {current_num_instructions(),
current_node_end};
}
}
// We're done with the block.
@ -1110,7 +1121,6 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
}
instruction_block->set_code_start(current_num_instructions());
instruction_block->set_code_end(current_block_end);
current_block_ = nullptr;
}
@ -1136,25 +1146,34 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
#endif
Node* input = block->control_input();
int instruction_end = static_cast<int>(instructions_.size());
switch (block->control()) {
case BasicBlock::kGoto:
return VisitGoto(block->SuccessorAt(0));
VisitGoto(block->SuccessorAt(0));
break;
case BasicBlock::kCall: {
DCHECK_EQ(IrOpcode::kCall, input->opcode());
BasicBlock* success = block->SuccessorAt(0);
BasicBlock* exception = block->SuccessorAt(1);
return VisitCall(input, exception), VisitGoto(success);
VisitCall(input, exception);
VisitGoto(success);
break;
}
case BasicBlock::kTailCall: {
DCHECK_EQ(IrOpcode::kTailCall, input->opcode());
return VisitTailCall(input);
VisitTailCall(input);
break;
}
case BasicBlock::kBranch: {
DCHECK_EQ(IrOpcode::kBranch, input->opcode());
BasicBlock* tbranch = block->SuccessorAt(0);
BasicBlock* fbranch = block->SuccessorAt(1);
if (tbranch == fbranch) return VisitGoto(tbranch);
return VisitBranch(input, tbranch, fbranch);
if (tbranch == fbranch) {
VisitGoto(tbranch);
} else {
VisitBranch(input, tbranch, fbranch);
}
break;
}
case BasicBlock::kSwitch: {
DCHECK_EQ(IrOpcode::kSwitch, input->opcode());
@ -1176,20 +1195,24 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
// Ensure that comparison order of if-cascades is preserved.
std::stable_sort(cases.begin(), cases.end());
SwitchInfo sw(cases, min_value, max_value, default_branch);
return VisitSwitch(input, sw);
VisitSwitch(input, sw);
break;
}
case BasicBlock::kReturn: {
DCHECK_EQ(IrOpcode::kReturn, input->opcode());
return VisitReturn(input);
VisitReturn(input);
break;
}
case BasicBlock::kDeoptimize: {
DeoptimizeParameters p = DeoptimizeParametersOf(input->op());
Node* value = input->InputAt(0);
return VisitDeoptimize(p.kind(), p.reason(), p.feedback(), value);
VisitDeoptimize(p.kind(), p.reason(), p.feedback(), value);
break;
}
case BasicBlock::kThrow:
DCHECK_EQ(IrOpcode::kThrow, input->opcode());
return VisitThrow(input);
VisitThrow(input);
break;
case BasicBlock::kNone: {
// Exit block doesn't have control.
DCHECK_NULL(input);
@ -1199,6 +1222,10 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
UNREACHABLE();
break;
}
if (trace_turbo_ == kEnableTraceTurboJson && input) {
int instruction_start = static_cast<int>(instructions_.size());
instr_origins_[input->id()] = {instruction_start, instruction_end};
}
}
void InstructionSelector::MarkPairProjectionsAsWord32(Node* node) {

View File

@ -256,6 +256,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
kDisableSwitchJumpTable,
kEnableSwitchJumpTable
};
enum EnableTraceTurboJson { kDisableTraceTurboJson, kEnableTraceTurboJson };
InstructionSelector(
Zone* zone, size_t node_count, Linkage* linkage,
@ -269,7 +270,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
: kDisableScheduling,
EnableSerialization enable_serialization = kDisableSerialization,
PoisoningMitigationLevel poisoning_level =
PoisoningMitigationLevel::kDontPoison);
PoisoningMitigationLevel::kDontPoison,
EnableTraceTurboJson trace_turbo = kDisableTraceTurboJson);
// Visit code for the entire graph with the included schedule.
bool SelectInstructions();
@ -439,6 +441,10 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
Isolate* isolate() const { return sequence()->isolate(); }
const ZoneVector<std::pair<int, int>>& instr_origins() const {
return instr_origins_;
}
private:
friend class OperandGenerator;
@ -704,6 +710,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
PoisoningMitigationLevel poisoning_level_;
Frame* frame_;
bool instruction_selection_failed_;
ZoneVector<std::pair<int, int>> instr_origins_;
EnableTraceTurboJson trace_turbo_;
};
} // namespace compiler

View File

@ -1592,6 +1592,37 @@ struct ComputeSchedulePhase {
}
};
struct InstructionRangesAsJSON {
const InstructionSequence* sequence;
const ZoneVector<std::pair<int, int>>* instr_origins;
};
std::ostream& operator<<(std::ostream& out, const InstructionRangesAsJSON& s) {
const int max = static_cast<int>(s.sequence->LastInstructionIndex());
out << ", \"nodeIdToInstructionRange\": {";
bool need_comma = false;
for (size_t i = 0; i < s.instr_origins->size(); ++i) {
std::pair<int, int> offset = (*s.instr_origins)[i];
if (offset.first == -1) continue;
const int first = max - offset.first + 1;
const int second = max - offset.second + 1;
if (need_comma) out << ", ";
out << "\"" << i << "\": [" << first << ", " << second << "]";
need_comma = true;
}
out << "}";
out << ", \"blockIdtoInstructionRange\": {";
need_comma = false;
for (auto block : s.sequence->instruction_blocks()) {
if (need_comma) out << ", ";
out << "\"" << block->rpo_number() << "\": [" << block->code_start() << ", "
<< block->code_end() << "]";
need_comma = true;
}
out << "}";
return out;
}
struct InstructionSelectionPhase {
static const char* phase_name() { return "select instructions"; }
@ -1613,10 +1644,21 @@ struct InstructionSelectionPhase {
data->isolate()->serializer_enabled()
? InstructionSelector::kEnableSerialization
: InstructionSelector::kDisableSerialization,
data->info()->GetPoisoningMitigationLevel());
data->info()->GetPoisoningMitigationLevel(),
data->info()->trace_turbo_json_enabled()
? InstructionSelector::kEnableTraceTurboJson
: InstructionSelector::kDisableTraceTurboJson);
if (!selector.SelectInstructions()) {
data->set_compilation_failed();
}
if (data->info()->trace_turbo_json_enabled()) {
TurboJsonFile json_of(data->info(), std::ios_base::app);
json_of << "{\"name\":\"" << phase_name()
<< "\",\"type\":\"instructions\""
<< InstructionRangesAsJSON{data->sequence(),
&selector.instr_origins()}
<< "},\n";
}
}
};
@ -2316,14 +2358,55 @@ bool PipelineImpl::SelectInstructions(Linkage* linkage) {
return true;
}
struct InstructionStartsAsJSON {
const ZoneVector<int>* instr_starts;
};
std::ostream& operator<<(std::ostream& out, const InstructionStartsAsJSON& s) {
out << ", \"instructionOffsetToPCOffset\": {";
bool need_comma = false;
for (size_t i = 0; i < s.instr_starts->size(); ++i) {
if (need_comma) out << ", ";
int offset = (*s.instr_starts)[i];
out << "\"" << i << "\":" << offset;
need_comma = true;
}
out << "}";
return out;
}
void PipelineImpl::AssembleCode(Linkage* linkage) {
PipelineData* data = this->data_;
data->BeginPhaseKind("code generation");
data->InitializeCodeGenerator(linkage);
Run<AssembleCodePhase>();
if (data->info()->trace_turbo_json_enabled()) {
TurboJsonFile json_of(data->info(), std::ios_base::app);
json_of << "{\"name\":\"code generation\""
<< ", \"type\":\"instructions\""
<< InstructionStartsAsJSON{&data->code_generator()->instr_starts()};
json_of << "},\n";
}
data->DeleteInstructionZone();
}
struct BlockStartsAsJSON {
const ZoneVector<int>* block_starts;
};
std::ostream& operator<<(std::ostream& out, const BlockStartsAsJSON& s) {
out << ", \"blockIdToOffset\": {";
bool need_comma = false;
for (size_t i = 0; i < s.block_starts->size(); ++i) {
if (need_comma) out << ", ";
int offset = (*s.block_starts)[i];
out << "\"" << i << "\":" << offset;
need_comma = true;
}
out << "},";
return out;
}
Handle<Code> PipelineImpl::FinalizeCode() {
PipelineData* data = this->data_;
Run<FinalizeCodePhase>();
@ -2344,7 +2427,10 @@ Handle<Code> PipelineImpl::FinalizeCode() {
if (info()->trace_turbo_json_enabled()) {
TurboJsonFile json_of(info(), std::ios_base::app);
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\",\"data\":\"";
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\""
<< BlockStartsAsJSON{&data->code_generator()->block_starts()}
<< "\"data\":\"";
#ifdef ENABLE_DISASSEMBLER
std::stringstream disassembly_stream;
code->Disassemble(nullptr, disassembly_stream);

View File

@ -266,6 +266,14 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
StackFrame::Type GetOutputStackFrameType() const;
const char* trace_turbo_filename() const {
return trace_turbo_filename_.get();
}
void set_trace_turbo_filename(std::unique_ptr<char[]> filename) {
trace_turbo_filename_ = std::move(filename);
}
private:
OptimizedCompilationInfo(Vector<const char> debug_name,
AbstractCode::Kind code_kind, Zone* zone);
@ -313,6 +321,7 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
JavaScriptFrame* osr_frame_ = nullptr;
Vector<const char> debug_name_;
std::unique_ptr<char[]> trace_turbo_filename_;
DISALLOW_COPY_AND_ASSIGN(OptimizedCompilationInfo);
};