v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
raw-machine-assembler.cc
Go to the documentation of this file.
1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <optional>
8
14
15namespace v8 {
16namespace internal {
17namespace compiler {
18
20 Isolate* isolate, TFGraph* graph, CallDescriptor* call_descriptor,
23 : isolate_(isolate),
24 graph_(graph),
25 schedule_(zone()->New<Schedule>(zone())),
26 source_positions_(zone()->New<SourcePositionTable>(graph)),
27 machine_(zone(), word, flags, alignment_requirements),
28 common_(zone()),
29 simplified_(zone()),
30 call_descriptor_(call_descriptor),
31 dynamic_js_parameter_count_(nullptr),
32 target_parameter_(nullptr),
35 int param_count = static_cast<int>(parameter_count());
36 // Add an extra input for the JSFunction parameter to the start node.
37 graph->SetStart(graph->NewNode(common_.Start(param_count + 1)));
39 target_parameter_ = AddNode(
40 common()->Parameter(Linkage::kJSCallClosureParamIndex), graph->start());
41 }
42 for (size_t i = 0; i < parameter_count(); ++i) {
43 parameters_[i] =
44 AddNode(common()->Parameter(static_cast<int>(i)), graph->start());
45 }
46 graph->SetEnd(graph->NewNode(common_.End(0)));
48}
49
51 FileAndLine file_and_line) {
52 int file_id =
53 isolate()->LookupOrAddExternallyCompiledFilename(file_and_line.first);
54 SourcePosition p = SourcePosition::External(file_and_line.second, file_id);
55 DCHECK_EQ(p.ExternalLine(), file_and_line.second);
57}
58
61 if (!p.IsKnown()) return {nullptr, -1};
62 int file_id = p.ExternalFileId();
63 const char* file_name = isolate()->GetExternallyCompiledFilename(file_id);
64 int line = p.ExternalLine();
65 return {file_name, line};
66}
67
69 return HeapConstant(isolate()->factory()->null_value());
70}
71
73 return HeapConstant(isolate()->factory()->undefined_value());
74}
75
77 RelocInfo::Mode rmode) {
78 return kSystemPointerSize == 8
79 ? RelocatableInt64Constant(value, rmode)
80 : RelocatableInt32Constant(static_cast<int>(value), rmode);
81}
82
84 AllocationType allocation) {
85 return AddNode(simplified()->AllocateRaw(Type::Any(), allocation), size);
86}
87
89 // Compute the correct codegen order.
91 if (v8_flags.trace_turbo_scheduler) {
92 PrintF("--- RAW SCHEDULE -------------------------------------------\n");
94 }
99 if (v8_flags.trace_turbo_scheduler) {
100 PrintF("--- EDGE SPLIT AND PROPAGATED DEFERRED SCHEDULE ------------\n");
102 }
103 // Invalidate RawMachineAssembler.
106 schedule_ = nullptr;
107 return schedule;
108}
109
111 // Compute the correct codegen order.
113 if (v8_flags.trace_turbo_scheduler) {
114 PrintF("--- RAW SCHEDULE -------------------------------------------\n");
116 }
120 if (v8_flags.trace_turbo_scheduler) {
121 PrintF("--- SCHEDULE BEFORE GRAPH CREATION -------------------------\n");
123 }
125 // Invalidate RawMachineAssembler.
126 schedule_ = nullptr;
127 return graph();
128}
129
131 TFGraph* graph,
132 CommonOperatorBuilder* common) {
133 for (bool changed = true; changed;) {
134 changed = false;
135 for (size_t i = 0; i < schedule->all_blocks()->size(); ++i) {
136 BasicBlock* block = (*schedule->all_blocks())[i];
137 if (block == nullptr) continue;
138
139 // Short-circuit a goto if the succeeding block is not a control-flow
140 // merge. This is not really useful on it's own since graph construction
141 // has the same effect, but combining blocks improves the pattern-match on
142 // their structure below.
143 if (block->control() == BasicBlock::kGoto) {
144 DCHECK_EQ(block->SuccessorCount(), 1);
145 BasicBlock* successor = block->SuccessorAt(0);
146 if (successor->PredecessorCount() == 1) {
147 DCHECK_EQ(successor->PredecessorAt(0), block);
148 for (Node* node : *successor) {
149 schedule->SetBlockForNode(nullptr, node);
150 schedule->AddNode(block, node);
151 }
152 block->set_control(successor->control());
153 Node* control_input = successor->control_input();
154 block->set_control_input(control_input);
155 if (control_input) {
156 schedule->SetBlockForNode(block, control_input);
157 }
158 if (successor->deferred()) block->set_deferred(true);
159 block->ClearSuccessors();
160 schedule->MoveSuccessors(successor, block);
161 schedule->ClearBlockById(successor->id());
162 changed = true;
163 --i;
164 continue;
165 }
166 }
167 // Block-cloning in the simple case where a block consists only of a phi
168 // node and a branch on that phi. This just duplicates the branch block
169 // for each predecessor, replacing the phi node with the corresponding phi
170 // input.
171 if (block->control() == BasicBlock::kBranch && block->NodeCount() == 1) {
172 Node* phi = block->NodeAt(0);
173 if (phi->opcode() != IrOpcode::kPhi) continue;
174 Node* branch = block->control_input();
175 DCHECK_EQ(branch->opcode(), IrOpcode::kBranch);
176 if (NodeProperties::GetValueInput(branch, 0) != phi) continue;
177 if (phi->UseCount() != 1) continue;
178 DCHECK_EQ(phi->op()->ValueInputCount(), block->PredecessorCount());
179
180 // Turn projection blocks into normal blocks.
181 DCHECK_EQ(block->SuccessorCount(), 2);
182 BasicBlock* true_block = block->SuccessorAt(0);
183 BasicBlock* false_block = block->SuccessorAt(1);
184 DCHECK_EQ(true_block->NodeAt(0)->opcode(), IrOpcode::kIfTrue);
185 DCHECK_EQ(false_block->NodeAt(0)->opcode(), IrOpcode::kIfFalse);
186 (*true_block->begin())->Kill();
187 true_block->RemoveNode(true_block->begin());
188 (*false_block->begin())->Kill();
189 false_block->RemoveNode(false_block->begin());
190 true_block->ClearPredecessors();
191 false_block->ClearPredecessors();
192
193 size_t arity = block->PredecessorCount();
194 for (size_t j = 0; j < arity; ++j) {
195 BasicBlock* predecessor = block->PredecessorAt(j);
196 predecessor->ClearSuccessors();
197 if (block->deferred()) predecessor->set_deferred(true);
198 Node* branch_clone = graph->CloneNode(branch);
199 int phi_input = static_cast<int>(j);
201 branch_clone, NodeProperties::GetValueInput(phi, phi_input), 0);
202 BasicBlock* new_true_block = schedule->NewBasicBlock();
203 BasicBlock* new_false_block = schedule->NewBasicBlock();
204 new_true_block->AddNode(
205 graph->NewNode(common->IfTrue(), branch_clone));
206 new_false_block->AddNode(
207 graph->NewNode(common->IfFalse(), branch_clone));
208 schedule->AddGoto(new_true_block, true_block);
209 schedule->AddGoto(new_false_block, false_block);
210 DCHECK_EQ(predecessor->control(), BasicBlock::kGoto);
211 predecessor->set_control(BasicBlock::kNone);
212 schedule->AddBranch(predecessor, branch_clone, new_true_block,
213 new_false_block);
214 }
215 branch->Kill();
216 schedule->ClearBlockById(block->id());
217 changed = true;
218 continue;
219 }
220 }
221 }
222}
223
225 std::vector<Node*> block_final_control(schedule_->all_blocks_.size());
226 std::vector<Node*> block_final_effect(schedule_->all_blocks_.size());
227
228 struct LoopHeader {
230 Node* loop_node;
231 Node* effect_phi;
232 };
233 std::vector<LoopHeader> loop_headers;
234
235 // These are hoisted outside of the loop to avoid re-allocation.
236 std::vector<Node*> merge_inputs;
237 std::vector<Node*> effect_phi_inputs;
238
239 for (BasicBlock* block : *schedule_->rpo_order()) {
240 Node* current_control;
241 Node* current_effect;
242 if (block == schedule_->start()) {
243 current_control = current_effect = graph()->start();
244 } else if (block == schedule_->end()) {
245 for (size_t i = 0; i < block->PredecessorCount(); ++i) {
247 graph(), common(), block->PredecessorAt(i)->control_input());
248 }
249 } else if (block->IsLoopHeader()) {
250 // The graph()->start() inputs are just placeholders until we computed the
251 // real back-edges and re-structure the control flow so the loop has
252 // exactly two predecessors.
253 current_control = graph()->NewNode(common()->Loop(2), graph()->start(),
254 graph()->start());
255 current_effect =
256 graph()->NewNode(common()->EffectPhi(2), graph()->start(),
257 graph()->start(), current_control);
258
259 Node* terminate = graph()->NewNode(common()->Terminate(), current_effect,
260 current_control);
262 loop_headers.push_back(
263 LoopHeader{block, current_control, current_effect});
264 } else if (block->PredecessorCount() == 1) {
265 BasicBlock* predecessor = block->PredecessorAt(0);
266 DCHECK_LT(predecessor->rpo_number(), block->rpo_number());
267 current_effect = block_final_effect[predecessor->id().ToSize()];
268 current_control = block_final_control[predecessor->id().ToSize()];
269 } else {
270 // Create control merge nodes and effect phis for all predecessor blocks.
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) {
275 BasicBlock* predecessor = block->PredecessorAt(i);
276 DCHECK_LT(predecessor->rpo_number(), block->rpo_number());
277 merge_inputs.push_back(block_final_control[predecessor->id().ToSize()]);
278 effect_phi_inputs.push_back(
279 block_final_effect[predecessor->id().ToSize()]);
280 }
281 current_control = graph()->NewNode(common()->Merge(predecessor_count),
282 static_cast<int>(merge_inputs.size()),
283 merge_inputs.data());
284 effect_phi_inputs.push_back(current_control);
285 current_effect = graph()->NewNode(
286 common()->EffectPhi(predecessor_count),
287 static_cast<int>(effect_phi_inputs.size()), effect_phi_inputs.data());
288 }
289
290 auto update_current_control_and_effect = [&](Node* node) {
291 bool existing_effect_and_control =
292 IrOpcode::IsIfProjectionOpcode(node->opcode()) ||
293 IrOpcode::IsPhiOpcode(node->opcode());
294 if (node->op()->EffectInputCount() > 0) {
295 DCHECK_EQ(1, node->op()->EffectInputCount());
296 if (existing_effect_and_control) {
297 NodeProperties::ReplaceEffectInput(node, current_effect);
298 } else {
299 node->AppendInput(graph()->zone(), current_effect);
300 }
301 }
302 if (node->op()->ControlInputCount() > 0) {
303 DCHECK_EQ(1, node->op()->ControlInputCount());
304 if (existing_effect_and_control) {
305 NodeProperties::ReplaceControlInput(node, current_control);
306 } else {
307 node->AppendInput(graph()->zone(), current_control);
308 }
309 }
310 if (node->op()->EffectOutputCount() > 0) {
311 DCHECK_EQ(1, node->op()->EffectOutputCount());
312 current_effect = node;
313 }
314 if (node->op()->ControlOutputCount() > 0) {
315 current_control = node;
316 }
317 };
318
319 for (Node* node : *block) {
320 update_current_control_and_effect(node);
321 }
322 if (block->deferred()) MarkControlDeferred(current_control);
323
324 if (Node* block_terminator = block->control_input()) {
325 update_current_control_and_effect(block_terminator);
326 }
327
328 block_final_effect[block->id().ToSize()] = current_effect;
329 block_final_control[block->id().ToSize()] = current_control;
330 }
331
332 // Fix-up loop backedges and re-structure control flow so that loop nodes have
333 // exactly two control predecessors.
334 for (const LoopHeader& loop_header : loop_headers) {
335 BasicBlock* block = loop_header.block;
336 std::vector<BasicBlock*> loop_entries;
337 std::vector<BasicBlock*> loop_backedges;
338 for (size_t i = 0; i < block->PredecessorCount(); ++i) {
339 BasicBlock* predecessor = block->PredecessorAt(i);
340 if (block->LoopContains(predecessor)) {
341 loop_backedges.push_back(predecessor);
342 } else {
343 DCHECK(loop_backedges.empty());
344 loop_entries.push_back(predecessor);
345 }
346 }
347 DCHECK(!loop_entries.empty());
348 DCHECK(!loop_backedges.empty());
349
350 int entrance_count = static_cast<int>(loop_entries.size());
351 int backedge_count = static_cast<int>(loop_backedges.size());
352 Node* control_loop_entry = CreateNodeFromPredecessors(
353 loop_entries, block_final_control, common()->Merge(entrance_count), {});
354 Node* control_backedge =
355 CreateNodeFromPredecessors(loop_backedges, block_final_control,
356 common()->Merge(backedge_count), {});
357 Node* effect_loop_entry = CreateNodeFromPredecessors(
358 loop_entries, block_final_effect, common()->EffectPhi(entrance_count),
359 {control_loop_entry});
360 Node* effect_backedge = CreateNodeFromPredecessors(
361 loop_backedges, block_final_effect, common()->EffectPhi(backedge_count),
362 {control_backedge});
363
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);
368
369 for (Node* node : *block) {
370 if (node->opcode() == IrOpcode::kPhi) {
371 MakePhiBinary(node, static_cast<int>(loop_entries.size()),
372 control_loop_entry, control_backedge);
373 }
374 }
375 }
376}
377
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()];
384 }
385 std::vector<Node*> inputs;
386 inputs.reserve(predecessors.size());
387 for (BasicBlock* predecessor : predecessors) {
388 inputs.push_back(sidetable[predecessor->id().ToSize()]);
389 }
390 for (Node* additional_input : additional_inputs) {
391 inputs.push_back(additional_input);
392 }
393 return graph()->NewNode(op, static_cast<int>(inputs.size()), inputs.data());
394}
395
396void RawMachineAssembler::MakePhiBinary(Node* phi, int split_point,
397 Node* left_control,
398 Node* right_control) {
399 int value_count = phi->op()->ValueInputCount();
400 if (value_count == 2) return;
401 DCHECK_LT(split_point, value_count);
402 DCHECK_GT(split_point, 0);
403
405 int left_input_count = split_point;
406 int right_input_count = value_count - split_point;
407
408 Node* left_input;
409 if (left_input_count == 1) {
410 left_input = NodeProperties::GetValueInput(phi, 0);
411 } else {
412 std::vector<Node*> inputs;
413 inputs.reserve(left_input_count);
414 for (int i = 0; i < left_input_count; ++i) {
415 inputs.push_back(NodeProperties::GetValueInput(phi, i));
416 }
417 inputs.push_back(left_control);
418 left_input =
419 graph()->NewNode(common()->Phi(rep, static_cast<int>(left_input_count)),
420 static_cast<int>(inputs.size()), inputs.data());
421 }
422
423 Node* right_input;
424 if (right_input_count == 1) {
425 right_input = NodeProperties::GetValueInput(phi, split_point);
426 } else {
427 std::vector<Node*> inputs;
428 for (int i = split_point; i < value_count; ++i) {
429 inputs.push_back(NodeProperties::GetValueInput(phi, i));
430 }
431 inputs.push_back(right_control);
432 right_input = graph()->NewNode(
433 common()->Phi(rep, static_cast<int>(right_input_count)),
434 static_cast<int>(inputs.size()), inputs.data());
435 }
436
438 phi->TrimInputCount(3);
439 phi->ReplaceInput(0, left_input);
440 phi->ReplaceInput(1, right_input);
441 phi->ReplaceInput(2, control);
442 NodeProperties::ChangeOp(phi, common()->Phi(rep, 2));
443}
444
446 BranchHint new_branch_hint;
447 Node* responsible_branch = nullptr;
448 while (responsible_branch == nullptr) {
449 switch (control_node->opcode()) {
450 case IrOpcode::kIfException:
451 // IfException projections are deferred by default.
452 return;
453 case IrOpcode::kIfSuccess:
454 control_node = NodeProperties::GetControlInput(control_node);
455 continue;
456 case IrOpcode::kIfValue: {
457 IfValueParameters parameters = IfValueParametersOf(control_node->op());
458 if (parameters.hint() != BranchHint::kFalse) {
460 control_node, common()->IfValue(parameters.value(),
461 parameters.comparison_order(),
463 }
464 return;
465 }
466 case IrOpcode::kIfDefault:
467 if (BranchHintOf(control_node->op()) != BranchHint::kFalse) {
468 NodeProperties::ChangeOp(control_node,
469 common()->IfDefault(BranchHint::kFalse));
470 }
471 return;
472 case IrOpcode::kIfTrue: {
473 Node* branch = NodeProperties::GetControlInput(control_node);
474 BranchHint hint = BranchHintOf(branch->op());
475 if (hint == BranchHint::kTrue) {
476 // The other possibility is also deferred, so the responsible branch
477 // has to be before.
478 control_node = NodeProperties::GetControlInput(branch);
479 continue;
480 }
481 new_branch_hint = BranchHint::kFalse;
482 responsible_branch = branch;
483 break;
484 }
485 case IrOpcode::kIfFalse: {
486 Node* branch = NodeProperties::GetControlInput(control_node);
487 BranchHint hint = BranchHintOf(branch->op());
488 if (hint == BranchHint::kFalse) {
489 // The other possibility is also deferred, so the responsible branch
490 // has to be before.
491 control_node = NodeProperties::GetControlInput(branch);
492 continue;
493 }
494 new_branch_hint = BranchHint::kTrue;
495 responsible_branch = branch;
496 break;
497 }
498 case IrOpcode::kMerge:
499 for (int i = 0; i < control_node->op()->ControlInputCount(); ++i) {
501 }
502 return;
503 case IrOpcode::kLoop:
504 control_node = NodeProperties::GetControlInput(control_node, 0);
505 continue;
506 case IrOpcode::kBranch:
507 case IrOpcode::kSwitch:
508 UNREACHABLE();
509 case IrOpcode::kStart:
510 return;
511 default:
512 DCHECK_EQ(1, control_node->op()->ControlInputCount());
513 control_node = NodeProperties::GetControlInput(control_node);
514 continue;
515 }
516 }
517
518 BranchHint hint = BranchHintOf(responsible_branch->op());
519 if (hint == new_branch_hint) return;
520 NodeProperties::ChangeOp(responsible_branch,
521 common()->Branch(new_branch_hint));
522}
523
528
530 DCHECK_LT(index, parameter_count());
531 return parameters_[index];
532}
533
534
540
542 RawMachineLabel* false_val,
543 BranchHint branch_hint) {
545 Node* branch = MakeNode(common()->Branch(branch_hint), 1, &condition);
546 BasicBlock* true_block = schedule()->NewBasicBlock();
547 BasicBlock* false_block = schedule()->NewBasicBlock();
548 schedule()->AddBranch(CurrentBlock(), branch, true_block, false_block);
549
550 true_block->AddNode(MakeNode(common()->IfTrue(), 1, &branch));
551 schedule()->AddGoto(true_block, Use(true_val));
552
553 false_block->AddNode(MakeNode(common()->IfFalse(), 1, &branch));
554 schedule()->AddGoto(false_block, Use(false_val));
555
556 current_block_ = nullptr;
557}
558
560 RawMachineLabel* if_exception) {
563 schedule()->AddCall(CurrentBlock(), call, Use(if_success), Use(if_exception));
564 current_block_ = nullptr;
565}
566
568 const int32_t* case_values,
569 RawMachineLabel** case_labels,
570 size_t case_count) {
572 size_t succ_count = case_count + 1;
573 Node* switch_node = MakeNode(common()->Switch(succ_count), 1, &index);
574 BasicBlock** succ_blocks = zone()->AllocateArray<BasicBlock*>(succ_count);
575 for (size_t i = 0; i < case_count; ++i) {
576 int32_t case_value = case_values[i];
577 BasicBlock* case_block = schedule()->NewBasicBlock();
578 Node* case_node =
579 graph()->NewNode(common()->IfValue(case_value), switch_node);
580 schedule()->AddNode(case_block, case_node);
581 schedule()->AddGoto(case_block, Use(case_labels[i]));
582 succ_blocks[i] = case_block;
583 }
584 BasicBlock* default_block = schedule()->NewBasicBlock();
585 Node* default_node = graph()->NewNode(common()->IfDefault(), switch_node);
586 schedule()->AddNode(default_block, default_node);
587 schedule()->AddGoto(default_block, Use(default_label));
588 succ_blocks[case_count] = default_block;
589 schedule()->AddSwitch(CurrentBlock(), switch_node, succ_blocks, succ_count);
590 current_block_ = nullptr;
591}
592
594 Node* values[] = {Int32Constant(0), value};
595 Node* ret = MakeNode(common()->Return(1), 2, values);
597 current_block_ = nullptr;
598}
599
601 Node* values[] = {Int32Constant(0), v1, v2};
602 Node* ret = MakeNode(common()->Return(2), 3, values);
604 current_block_ = nullptr;
605}
606
608 Node* values[] = {Int32Constant(0), v1, v2, v3};
609 Node* ret = MakeNode(common()->Return(3), 4, values);
611 current_block_ = nullptr;
612}
613
615 Node* values[] = {Int32Constant(0), v1, v2, v3, v4};
616 Node* ret = MakeNode(common()->Return(4), 5, values);
618 current_block_ = nullptr;
619}
620
622 using Node_ptr = Node*;
623 Node** values = new Node_ptr[count + 1];
624 values[0] = Int32Constant(0);
625 for (int i = 0; i < count; ++i) values[i + 1] = vs[i];
626 Node* ret = MakeNode(common()->Return(count), count + 1, values);
628 current_block_ = nullptr;
629 delete[] values;
630}
631
633 // PopAndReturn is supposed to be used ONLY in CSA/Torque builtins for
634 // dropping ALL JS arguments that are currently located on the stack.
635 // The check below ensures that there are no directly accessible stack
636 // parameters from current builtin, which implies that the builtin with
637 // JS calling convention (TFJ) was created with kDontAdaptArgumentsSentinel.
638 // This simplifies semantics of this instruction because in case of presence
639 // of directly accessible stack parameters it's impossible to distinguish
640 // the following cases:
641 // 1) stack parameter is included in JS arguments (and therefore it will be
642 // dropped as a part of 'pop' number of arguments),
643 // 2) stack parameter is NOT included in JS arguments (and therefore it should
644 // be dropped in ADDITION to the 'pop' number of arguments).
645 // Additionally, in order to simplify assembly code, PopAndReturn is also
646 // not allowed in builtins with stub linkage and parameters on stack.
647 CHECK_EQ(call_descriptor()->ParameterSlotCount(), 0);
648 Node* values[] = {pop, value};
649 Node* ret = MakeNode(common()->Return(1), 2, values);
651 current_block_ = nullptr;
652}
653
655 Node* values[] = {pop, v1, v2};
656 Node* ret = MakeNode(common()->Return(2), 3, values);
658 current_block_ = nullptr;
659}
660
662 Node* v3) {
663 Node* values[] = {pop, v1, v2, v3};
664 Node* ret = MakeNode(common()->Return(3), 4, values);
666 current_block_ = nullptr;
667}
668
670 Node* v4) {
671 Node* values[] = {pop, v1, v2, v3, v4};
672 Node* ret = MakeNode(common()->Return(4), 5, values);
674 current_block_ = nullptr;
675}
676
680
682
684 Node* ret = MakeNode(common()->Throw(), 0, nullptr);
685 schedule()->AddThrow(CurrentBlock(), ret);
686 current_block_ = nullptr;
687}
688
689void RawMachineAssembler::Comment(const std::string& msg) {
690 size_t length = msg.length() + 1;
691 char* zone_buffer = zone()->AllocateArray<char>(length);
692 MemCopy(zone_buffer, msg.c_str(), length);
693 AddNode(machine()->Comment(zone_buffer));
694}
695
696void RawMachineAssembler::StaticAssert(Node* value, const char* source) {
697 AddNode(common()->StaticAssert(source), value);
698}
699
701 int input_count, Node* const* inputs) {
703 // +1 is for target.
704 DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 1);
705 return AddNode(common()->Call(call_descriptor), input_count, inputs);
706}
707
709 int input_count,
710 Node* const* inputs) {
712 // +2 is for target and frame state.
713 DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 2);
714 return AddNode(common()->Call(call_descriptor), input_count, inputs);
715}
716
718 int input_count, Node* const* inputs) {
719 // +1 is for target.
720 DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 1);
721 Node* tail_call =
722 MakeNode(common()->TailCall(call_descriptor), input_count, inputs);
723 schedule()->AddTailCall(CurrentBlock(), tail_call);
724 current_block_ = nullptr;
725}
726
727namespace {
728
729enum FunctionDescriptorMode { kHasFunctionDescriptor, kNoFunctionDescriptor };
730
731Node* CallCFunctionImpl(
732 RawMachineAssembler* rasm, Node* function,
733 std::optional<MachineType> return_type,
734 std::initializer_list<RawMachineAssembler::CFunctionArg> args,
735 bool caller_saved_regs, SaveFPRegsMode mode,
736 FunctionDescriptorMode no_function_descriptor) {
737 static constexpr std::size_t kNumCArgs = 10;
738
739 MachineSignature::Builder builder(rasm->zone(), return_type ? 1 : 0,
740 args.size());
741 if (return_type) {
742 builder.AddReturn(*return_type);
743 }
744 for (const auto& arg : args) builder.AddParam(arg.first);
745
746 bool caller_saved_fp_regs =
747 caller_saved_regs && (mode == SaveFPRegsMode::kSave);
749 if (caller_saved_regs) flags |= CallDescriptor::kCallerSavedRegisters;
750 if (caller_saved_fp_regs) flags |= CallDescriptor::kCallerSavedFPRegisters;
751 if (no_function_descriptor) flags |= CallDescriptor::kNoFunctionDescriptor;
752 auto call_descriptor =
753 Linkage::GetSimplifiedCDescriptor(rasm->zone(), builder.Get(), flags);
754
756 nodes[0] = function;
757 std::transform(
758 args.begin(), args.end(), std::next(nodes.begin()),
759 [](const RawMachineAssembler::CFunctionArg& arg) { return arg.second; });
760
761 auto common = rasm->common();
762 return rasm->AddNode(common->Call(call_descriptor),
763 static_cast<int>(nodes.size()), nodes.begin());
764}
765
766} // namespace
767
769 Node* function, std::optional<MachineType> return_type,
770 std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
771 return CallCFunctionImpl(this, function, return_type, args, false,
772 SaveFPRegsMode::kIgnore, kHasFunctionDescriptor);
773}
774
776 Node* function, MachineType return_type,
777 std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
778 return CallCFunctionImpl(this, function, return_type, args, false,
779 SaveFPRegsMode::kIgnore, kNoFunctionDescriptor);
780}
781
783 Node* function, MachineType return_type, SaveFPRegsMode mode,
784 std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
785 return CallCFunctionImpl(this, function, return_type, args, true, mode,
786 kHasFunctionDescriptor);
787}
788
793
795 if (label->block_ == nullptr) {
796 label->block_ = schedule()->NewBasicBlock();
797 }
798 return label->block_;
799}
800
808
809#if DEBUG
811 AssemblerDebugInfo info) {
812 if (current_block_ != nullptr) {
813 std::stringstream str;
814 str << "Binding label without closing previous block:"
815 << "\n# label: " << info
816 << "\n# previous block: " << *current_block_;
817 FATAL("%s", str.str().c_str());
818 }
819 Bind(label);
820 current_block_->set_debug_info(info);
821}
822
823void RawMachineAssembler::PrintCurrentBlock(std::ostream& os) {
824 os << CurrentBlock();
825}
826
827void RawMachineAssembler::SetInitialDebugInformation(
828 AssemblerDebugInfo debug_info) {
829 CurrentBlock()->set_debug_info(debug_info);
830}
831#endif // DEBUG
832
834
839
841 Node* const* inputs) {
842 Node** buffer = zone()->AllocateArray<Node*>(input_count + 1);
843 std::copy(inputs, inputs + input_count, buffer);
844 buffer[input_count] = graph()->start();
845 return AddNode(common()->Phi(rep, input_count), input_count + 1, buffer);
846}
847
849 const Operator* op = phi->op();
850 const Operator* new_op = common()->ResizeMergeOrPhi(op, phi->InputCount());
851 phi->InsertInput(zone(), phi->InputCount() - 1, new_input);
852 NodeProperties::ChangeOp(phi, new_op);
853}
854
855Node* RawMachineAssembler::AddNode(const Operator* op, int input_count,
856 Node* const* inputs) {
859 Node* node = MakeNode(op, input_count, inputs);
860 schedule()->AddNode(CurrentBlock(), node);
861 return node;
862}
863
864Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
865 Node* const* inputs) {
866 // The raw machine assembler nodes do not have effect and control inputs,
867 // so we disable checking input counts here.
868 return graph()->NewNodeUnchecked(op, input_count, inputs);
869}
870
872#if DEBUG
873 if (bound_ == used_) return;
874 std::stringstream str;
875 if (bound_) {
876 str << "A label has been bound but it's not used."
877 << "\n# label: " << *block_;
878 } else {
879 str << "A label has been used but it's not bound.";
880 }
881 FATAL("%s", str.str().c_str());
882#endif // DEBUG
883}
884
885} // namespace compiler
886} // namespace internal
887} // namespace v8
Schedule * schedule
Isolate * isolate_
int16_t parameter_count
Definition builtins.cc:67
int LookupOrAddExternallyCompiledFilename(const char *filename)
Definition isolate.cc:6758
const char * GetExternallyCompiledFilename(int index) const
Definition isolate.cc:6766
static SourcePosition External(int line, int file_id)
T * AllocateArray(size_t length)
Definition zone.h:127
Node * NodeAt(size_t index)
Definition schedule.h:93
void set_deferred(bool deferred)
Definition schedule.h:133
BasicBlock * SuccessorAt(size_t index)
Definition schedule.h:85
BasicBlock * PredecessorAt(size_t index)
Definition schedule.h:76
void set_control(Control control)
Definition schedule.cc:62
const Operator * End(size_t control_input_count)
const Operator * ResizeMergeOrPhi(const Operator *op, int size)
const Operator * Start(int value_output_count)
static bool IsPhiOpcode(Value value)
Definition opcodes.h:1400
static bool IsIfProjectionOpcode(Value value)
Definition opcodes.h:1408
static CallDescriptor * GetSimplifiedCDescriptor(Zone *zone, const MachineSignature *sig, CallDescriptor::Flags flags=CallDescriptor::kNoFlags, Operator::Properties properties=Operator::kNoThrow)
Definition c-linkage.cc:269
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
Definition node.h:52
const Operator * op() const
Definition node.h:50
void ReplaceInput(int index, Node *new_to)
Definition node.h:76
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)
Node * OptimizedAllocate(Node *size, AllocationType allocation)
static void OptimizeControlFlow(Schedule *schedule, TFGraph *graph, CommonOperatorBuilder *common)
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)
Node * Phi(MachineRepresentation rep, Node *n1, Node *n2)
Node * RelocatableInt64Constant(int64_t value, RelocInfo::Mode rmode)
Node * RelocatableIntPtrConstant(intptr_t value, RelocInfo::Mode rmode)
void AppendPhiInput(Node *phi, Node *new_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)
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)
Node * CallN(CallDescriptor *call_descriptor, int input_count, Node *const *inputs)
void StaticAssert(Node *value, const char *source)
Node * CallCFunctionWithoutFunctionDescriptor(Node *function, MachineType return_type, CArgs... cargs)
BasicBlockVector * rpo_order()
Definition schedule.h:280
void SetBlockForNode(BasicBlock *block, Node *node)
Definition schedule.cc:456
void AddThrow(BasicBlock *block, Node *input)
Definition schedule.cc:300
const BasicBlockVector * all_blocks() const
Definition schedule.h:279
void MoveSuccessors(BasicBlock *from, BasicBlock *to)
Definition schedule.cc:441
void AddGoto(BasicBlock *block, BasicBlock *succ)
Definition schedule.cc:223
void AddTailCall(BasicBlock *block, Node *input)
Definition schedule.cc:279
void AddReturn(BasicBlock *block, Node *input)
Definition schedule.cc:286
void AddCall(BasicBlock *block, Node *call, BasicBlock *success_block, BasicBlock *exception_block)
Definition schedule.cc:248
void ClearBlockById(BasicBlock::Id block_id)
Definition schedule.cc:186
void AddBranch(BasicBlock *block, Node *branch, BasicBlock *tblock, BasicBlock *fblock)
Definition schedule.cc:258
void AddNode(BasicBlock *block, Node *node)
Definition schedule.cc:213
void AddSwitch(BasicBlock *block, Node *sw, BasicBlock **succ_blocks, size_t succ_count)
Definition schedule.cc:268
static BasicBlockVector * ComputeSpecialRPO(Zone *zone, Schedule *schedule)
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)
int start
uint32_t count
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Label label
Node * node
RpoNumber block
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,...)
Definition utils.cc:39
constexpr int kSystemPointerSize
Definition globals.h:410
void Terminate(Isolate *isolate)
Definition bigint.cc:1187
V8_EXPORT_PRIVATE FlagValues v8_flags
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
std::pair< const char *, int > FileAndLine
Definition globals.h:2481
#define FATAL(...)
Definition logging.h:47
#define DCHECK_NULL(val)
Definition logging.h:491
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
TFGraph * graph_
Node ** parameters_