27 machine_(zone(), word, flags, alignment_requirements),
30 call_descriptor_(call_descriptor),
31 dynamic_js_parameter_count_(nullptr),
32 target_parameter_(nullptr),
37 graph->SetStart(graph->NewNode(
common_.
Start(param_count + 1)));
39 target_parameter_ = AddNode(
40 common()->Parameter(Linkage::kJSCallClosureParamIndex), graph->start());
61 if (!p.
IsKnown())
return {
nullptr, -1};
65 return {file_name, line};
91 if (
v8_flags.trace_turbo_scheduler) {
92 PrintF(
"--- RAW SCHEDULE -------------------------------------------\n");
99 if (
v8_flags.trace_turbo_scheduler) {
100 PrintF(
"--- EDGE SPLIT AND PROPAGATED DEFERRED SCHEDULE ------------\n");
113 if (
v8_flags.trace_turbo_scheduler) {
114 PrintF(
"--- RAW SCHEDULE -------------------------------------------\n");
120 if (
v8_flags.trace_turbo_scheduler) {
121 PrintF(
"--- SCHEDULE BEFORE GRAPH CREATION -------------------------\n");
133 for (
bool changed =
true; changed;) {
137 if (block ==
nullptr)
continue;
148 for (
Node* node : *successor) {
152 block->set_control(successor->control());
153 Node* control_input = successor->control_input();
154 block->set_control_input(control_input);
158 if (successor->deferred()) block->set_deferred(
true);
159 block->ClearSuccessors();
172 Node* phi = block->NodeAt(0);
173 if (phi->opcode() != IrOpcode::kPhi)
continue;
174 Node* branch = block->control_input();
177 if (phi->UseCount() != 1)
continue;
178 DCHECK_EQ(phi->op()->ValueInputCount(), block->PredecessorCount());
186 (*true_block->
begin())->Kill();
188 (*false_block->
begin())->Kill();
193 size_t arity = block->PredecessorCount();
194 for (
size_t j = 0; j < arity; ++j) {
198 Node* branch_clone = graph->CloneNode(branch);
199 int phi_input =
static_cast<int>(j);
233 std::vector<LoopHeader> loop_headers;
236 std::vector<Node*> merge_inputs;
237 std::vector<Node*> effect_phi_inputs;
240 Node* current_control;
241 Node* current_effect;
243 current_control = current_effect =
graph()->
start();
245 for (
size_t i = 0;
i < block->PredecessorCount(); ++
i) {
247 graph(),
common(), block->PredecessorAt(
i)->control_input());
249 }
else if (block->IsLoopHeader()) {
262 loop_headers.push_back(
263 LoopHeader{
block, current_control, current_effect});
264 }
else if (block->PredecessorCount() == 1) {
267 current_effect = block_final_effect[predecessor->
id().
ToSize()];
268 current_control = block_final_control[predecessor->
id().
ToSize()];
271 merge_inputs.clear();
272 effect_phi_inputs.clear();
273 int predecessor_count =
static_cast<int>(block->PredecessorCount());
274 for (
int i = 0;
i < predecessor_count; ++
i) {
277 merge_inputs.push_back(block_final_control[predecessor->
id().
ToSize()]);
278 effect_phi_inputs.push_back(
279 block_final_effect[predecessor->
id().
ToSize()]);
282 static_cast<int>(merge_inputs.size()),
283 merge_inputs.data());
284 effect_phi_inputs.push_back(current_control);
286 common()->EffectPhi(predecessor_count),
287 static_cast<int>(effect_phi_inputs.size()), effect_phi_inputs.data());
290 auto update_current_control_and_effect = [&](
Node*
node) {
291 bool existing_effect_and_control =
294 if (node->op()->EffectInputCount() > 0) {
295 DCHECK_EQ(1, node->op()->EffectInputCount());
296 if (existing_effect_and_control) {
299 node->AppendInput(
graph()->
zone(), current_effect);
302 if (node->op()->ControlInputCount() > 0) {
303 DCHECK_EQ(1, node->op()->ControlInputCount());
304 if (existing_effect_and_control) {
307 node->AppendInput(
graph()->
zone(), current_control);
310 if (node->op()->EffectOutputCount() > 0) {
311 DCHECK_EQ(1, node->op()->EffectOutputCount());
312 current_effect =
node;
314 if (node->op()->ControlOutputCount() > 0) {
315 current_control =
node;
319 for (
Node* node : *block) {
320 update_current_control_and_effect(node);
324 if (
Node* block_terminator = block->control_input()) {
325 update_current_control_and_effect(block_terminator);
328 block_final_effect[block->id().ToSize()] = current_effect;
329 block_final_control[block->id().ToSize()] = current_control;
334 for (
const LoopHeader& loop_header : loop_headers) {
336 std::vector<BasicBlock*> loop_entries;
337 std::vector<BasicBlock*> loop_backedges;
338 for (
size_t i = 0;
i < block->PredecessorCount(); ++
i) {
340 if (block->LoopContains(predecessor)) {
341 loop_backedges.push_back(predecessor);
343 DCHECK(loop_backedges.empty());
344 loop_entries.push_back(predecessor);
347 DCHECK(!loop_entries.empty());
348 DCHECK(!loop_backedges.empty());
350 int entrance_count =
static_cast<int>(loop_entries.size());
351 int backedge_count =
static_cast<int>(loop_backedges.size());
353 loop_entries, block_final_control,
common()->Merge(entrance_count), {});
354 Node* control_backedge =
356 common()->Merge(backedge_count), {});
358 loop_entries, block_final_effect,
common()->EffectPhi(entrance_count),
359 {control_loop_entry});
361 loop_backedges, block_final_effect,
common()->EffectPhi(backedge_count),
364 loop_header.loop_node->
ReplaceInput(0, control_loop_entry);
365 loop_header.loop_node->ReplaceInput(1, control_backedge);
366 loop_header.effect_phi->ReplaceInput(0, effect_loop_entry);
367 loop_header.effect_phi->ReplaceInput(1, effect_backedge);
369 for (
Node* node : *block) {
370 if (node->opcode() == IrOpcode::kPhi) {
372 control_loop_entry, control_backedge);
379 const std::vector<BasicBlock*>& predecessors,
380 const std::vector<Node*>& sidetable,
const Operator* op,
381 const std::vector<Node*>& additional_inputs) {
382 if (predecessors.size() == 1) {
383 return sidetable[predecessors.front()->id().ToSize()];
385 std::vector<Node*> inputs;
386 inputs.reserve(predecessors.size());
387 for (
BasicBlock* predecessor : predecessors) {
388 inputs.push_back(sidetable[predecessor->id().ToSize()]);
390 for (
Node* additional_input : additional_inputs) {
391 inputs.push_back(additional_input);
393 return graph()->
NewNode(op,
static_cast<int>(inputs.size()), inputs.data());
398 Node* right_control) {
399 int value_count = phi->op()->ValueInputCount();
400 if (value_count == 2)
return;
405 int left_input_count = split_point;
406 int right_input_count = value_count - split_point;
409 if (left_input_count == 1) {
412 std::vector<Node*> inputs;
413 inputs.reserve(left_input_count);
414 for (
int i = 0;
i < left_input_count; ++
i) {
417 inputs.push_back(left_control);
420 static_cast<int>(inputs.size()), inputs.data());
424 if (right_input_count == 1) {
427 std::vector<Node*> inputs;
428 for (
int i = split_point;
i < value_count; ++
i) {
431 inputs.push_back(right_control);
433 common()->
Phi(rep,
static_cast<int>(right_input_count)),
434 static_cast<int>(inputs.size()), inputs.data());
438 phi->TrimInputCount(3);
439 phi->ReplaceInput(0, left_input);
440 phi->ReplaceInput(1, right_input);
441 phi->ReplaceInput(2, control);
447 Node* responsible_branch =
nullptr;
448 while (responsible_branch ==
nullptr) {
449 switch (control_node->
opcode()) {
450 case IrOpcode::kIfException:
453 case IrOpcode::kIfSuccess:
456 case IrOpcode::kIfValue: {
460 control_node,
common()->IfValue(parameters.
value(),
466 case IrOpcode::kIfDefault:
472 case IrOpcode::kIfTrue: {
482 responsible_branch = branch;
485 case IrOpcode::kIfFalse: {
495 responsible_branch = branch;
498 case IrOpcode::kMerge:
499 for (
int i = 0;
i < control_node->
op()->ControlInputCount(); ++
i) {
503 case IrOpcode::kLoop:
506 case IrOpcode::kBranch:
507 case IrOpcode::kSwitch:
509 case IrOpcode::kStart:
512 DCHECK_EQ(1, control_node->
op()->ControlInputCount());
519 if (hint == new_branch_hint)
return;
568 const int32_t* case_values,
572 size_t succ_count = case_count + 1;
575 for (
size_t i = 0;
i < case_count; ++
i) {
576 int32_t case_value = case_values[
i];
582 succ_blocks[
i] = case_block;
588 succ_blocks[case_count] = default_block;
622 using Node_ptr =
Node*;
648 Node* values[] = {pop, value};
655 Node* values[] = {pop, v1, v2};
663 Node* values[] = {pop, v1, v2, v3};
671 Node* values[] = {pop, v1, v2, v3, v4};
690 size_t length = msg.length() + 1;
692 MemCopy(zone_buffer, msg.c_str(), length);
701 int input_count,
Node*
const* inputs) {
710 Node*
const* inputs) {
718 int input_count,
Node*
const* inputs) {
729enum FunctionDescriptorMode { kHasFunctionDescriptor, kNoFunctionDescriptor };
731Node* CallCFunctionImpl(
732 RawMachineAssembler* rasm, Node* function,
733 std::optional<MachineType> return_type,
734 std::initializer_list<RawMachineAssembler::CFunctionArg>
args,
736 FunctionDescriptorMode no_function_descriptor) {
737 static constexpr std::size_t kNumCArgs = 10;
742 builder.AddReturn(*return_type);
744 for (
const auto& arg :
args) builder.AddParam(arg.first);
746 bool caller_saved_fp_regs =
752 auto call_descriptor =
758 args.begin(),
args.end(), std::next(nodes.begin()),
761 auto common = rasm->common();
762 return rasm->AddNode(common->Call(call_descriptor),
763 static_cast<int>(nodes.size()), nodes.begin());
769 Node* function, std::optional<MachineType> return_type,
770 std::initializer_list<RawMachineAssembler::CFunctionArg>
args) {
771 return CallCFunctionImpl(
this, function, return_type,
args,
false,
776 Node* function, MachineType return_type,
777 std::initializer_list<RawMachineAssembler::CFunctionArg>
args) {
778 return CallCFunctionImpl(
this, function, return_type,
args,
false,
784 std::initializer_list<RawMachineAssembler::CFunctionArg>
args) {
785 return CallCFunctionImpl(
this, function, return_type,
args,
true, mode,
786 kHasFunctionDescriptor);
795 if (
label->block_ ==
nullptr) {
798 return label->block_;
804 label->bound_ =
true;
813 std::stringstream str;
814 str <<
"Binding label without closing previous block:"
815 <<
"\n# label: " << info
817 FATAL(
"%s", str.str().c_str());
823void RawMachineAssembler::PrintCurrentBlock(std::ostream& os) {
827void RawMachineAssembler::SetInitialDebugInformation(
828 AssemblerDebugInfo debug_info) {
841 Node*
const* inputs) {
843 std::copy(inputs, inputs + input_count, buffer);
851 phi->InsertInput(
zone(), phi->InputCount() - 1, new_input);
856 Node*
const* inputs) {
865 Node*
const* inputs) {
874 std::stringstream str;
876 str <<
"A label has been bound but it's not used."
877 <<
"\n# label: " << *
block_;
879 str <<
"A label has been used but it's not bound.";
881 FATAL(
"%s", str.str().c_str());
int LookupOrAddExternallyCompiledFilename(const char *filename)
const char * GetExternallyCompiledFilename(int index) const
int ExternalFileId() const
static SourcePosition External(int line, int file_id)
T * AllocateArray(size_t length)
Node * NodeAt(size_t index)
void set_deferred(bool deferred)
BasicBlock * SuccessorAt(size_t index)
int32_t rpo_number() const
void RemoveNode(iterator it)
BasicBlock * PredecessorAt(size_t index)
void set_control(Control control)
size_t PredecessorCount() const
size_t ParameterCount() const
bool IsJSFunctionCall() const
bool NeedsFrameState() const
base::Flags< Flag > Flags
@ kCallerSavedFPRegisters
const Operator * End(size_t control_input_count)
const Operator * IfFalse()
const Operator * ResizeMergeOrPhi(const Operator *op, int size)
const Operator * IfTrue()
const Operator * Start(int value_output_count)
int32_t comparison_order() const
static bool IsPhiOpcode(Value value)
static bool IsIfProjectionOpcode(Value value)
static CallDescriptor * GetSimplifiedCDescriptor(Zone *zone, const MachineSignature *sig, CallDescriptor::Flags flags=CallDescriptor::kNoFlags, Operator::Properties properties=Operator::kNoThrow)
static void ChangeOp(Node *node, const Operator *new_op)
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static void ReplaceControlInput(Node *node, Node *control, int index=0)
static void MergeControlToEnd(TFGraph *graph, CommonOperatorBuilder *common, Node *node)
static Node * GetValueInput(Node *node, int index)
static void ReplaceValueInput(Node *node, Node *value, int index)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
const Operator * op() const
void ReplaceInput(int index, Node *new_to)
Node * HeapConstant(Handle< HeapObject > object)
RawMachineAssembler(Isolate *isolate, TFGraph *graph, CallDescriptor *call_descriptor, MachineRepresentation word=MachineType::PointerRepresentation(), MachineOperatorBuilder::Flags flags=MachineOperatorBuilder::Flag::kNoFlags, MachineOperatorBuilder::AlignmentRequirements alignment_requirements=MachineOperatorBuilder::AlignmentRequirements::FullUnalignedAccessSupport())
Node * RelocatableInt32Constant(int32_t value, RelocInfo::Mode rmode)
void AbortCSADcheck(Node *message)
std::pair< MachineType, Node * > CFunctionArg
BasicBlock * CurrentBlock()
Node * OptimizedAllocate(Node *size, AllocationType allocation)
CommonOperatorBuilder common_
static void OptimizeControlFlow(Schedule *schedule, TFGraph *graph, CommonOperatorBuilder *common)
Node * Int32Constant(int32_t value)
void Branch(Node *condition, RawMachineLabel *true_val, RawMachineLabel *false_val, BranchHint branch_hint=BranchHint::kNone)
void Continuations(Node *call, RawMachineLabel *if_success, RawMachineLabel *if_exception)
Node * AddNode(const Operator *op, int input_count, Node *const *inputs)
Isolate * isolate() const
Node * Phi(MachineRepresentation rep, Node *n1, Node *n2)
Schedule * ExportForTest()
MachineOperatorBuilder * machine()
void Goto(RawMachineLabel *label)
BasicBlock * current_block_
SimplifiedOperatorBuilder * simplified()
CommonOperatorBuilder * common()
void Comment(const std::string &msg)
CallDescriptor * call_descriptor() const
SourcePositionTable * source_positions_
void Bind(RawMachineLabel *label)
size_t parameter_count() const
Node * RelocatableInt64Constant(int64_t value, RelocInfo::Mode rmode)
Node * RelocatableIntPtrConstant(intptr_t value, RelocInfo::Mode rmode)
void AppendPhiInput(Node *phi, Node *new_input)
void MarkControlDeferred(Node *control_input)
Node * CallNWithFrameState(CallDescriptor *call_descriptor, int input_count, Node *const *inputs)
void TailCallN(CallDescriptor *call_descriptor, int input_count, Node *const *inputs)
void SetCurrentExternalSourcePosition(FileAndLine file_and_line)
FileAndLine GetCurrentExternalSourcePosition() const
Node * MakeNode(const Operator *op, int input_count, Node *const *inputs)
Node * CallCFunctionWithCallerSavedRegisters(Node *function, MachineType return_type, SaveFPRegsMode mode, CArgs... cargs)
void Switch(Node *index, RawMachineLabel *default_label, const int32_t *case_values, RawMachineLabel **case_labels, size_t case_count)
BasicBlock * Use(RawMachineLabel *label)
BasicBlock * EnsureBlock(RawMachineLabel *label)
Node * CreateNodeFromPredecessors(const std::vector< BasicBlock * > &predecessors, const std::vector< Node * > &sidetable, const Operator *op, const std::vector< Node * > &additional_inputs)
Node * CallCFunction(Node *function, std::optional< MachineType > return_type, CArgs... cargs)
void MakePhiBinary(Node *phi, int split_point, Node *left_control, Node *right_control)
SourcePositionTable * source_positions()
Node * UndefinedConstant()
TFGraph * ExportForOptimization()
Node * CallN(CallDescriptor *call_descriptor, int input_count, Node *const *inputs)
void StaticAssert(Node *value, const char *source)
void PopAndReturn(Node *pop, Node *value)
Node * Parameter(size_t index)
Node * CallCFunctionWithoutFunctionDescriptor(Node *function, MachineType return_type, CArgs... cargs)
BasicBlockVector * rpo_order()
void SetBlockForNode(BasicBlock *block, Node *node)
void AddThrow(BasicBlock *block, Node *input)
const BasicBlockVector * all_blocks() const
void MoveSuccessors(BasicBlock *from, BasicBlock *to)
void AddGoto(BasicBlock *block, BasicBlock *succ)
void AddTailCall(BasicBlock *block, Node *input)
void PropagateDeferredMark()
void AddReturn(BasicBlock *block, Node *input)
BasicBlockVector all_blocks_
void AddCall(BasicBlock *block, Node *call, BasicBlock *success_block, BasicBlock *exception_block)
void ClearBlockById(BasicBlock::Id block_id)
BasicBlock * NewBasicBlock()
void AddBranch(BasicBlock *block, Node *branch, BasicBlock *tblock, BasicBlock *fblock)
void AddNode(BasicBlock *block, Node *node)
void EnsureCFGWellFormedness()
void AddSwitch(BasicBlock *block, Node *sw, BasicBlock **succ_blocks, size_t succ_count)
void GenerateDominatorTree()
static BasicBlockVector * ComputeSpecialRPO(Zone *zone, Schedule *schedule)
SourcePosition GetCurrentPosition() const
void SetCurrentPosition(const SourcePosition &pos)
Node * NewNodeUnchecked(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
base::Vector< const DirectHandle< Object > > args
Schedule const *const schedule_
BasicBlock * current_block_
IfValueParameters const & IfValueParametersOf(const Operator *op)
BranchHint BranchHintOf(const Operator *const op)
MachineRepresentation PhiRepresentationOf(const Operator *const op)
void PrintF(const char *format,...)
constexpr int kSystemPointerSize
void Terminate(Isolate *isolate)
V8_EXPORT_PRIVATE FlagValues v8_flags
void MemCopy(void *dest, const void *src, size_t size)
std::pair< const char *, int > FileAndLine
#define DCHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)