11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/compiler/raw-machine-assembler.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/small-vector.h"
81cb0ef41Sopenharmony_ci#include "src/compiler/compiler-source-position-table.h"
91cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
101cb0ef41Sopenharmony_ci#include "src/compiler/pipeline.h"
111cb0ef41Sopenharmony_ci#include "src/compiler/scheduler.h"
121cb0ef41Sopenharmony_ci#include "src/heap/factory-inl.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_cinamespace compiler {
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciRawMachineAssembler::RawMachineAssembler(
191cb0ef41Sopenharmony_ci    Isolate* isolate, Graph* graph, CallDescriptor* call_descriptor,
201cb0ef41Sopenharmony_ci    MachineRepresentation word, MachineOperatorBuilder::Flags flags,
211cb0ef41Sopenharmony_ci    MachineOperatorBuilder::AlignmentRequirements alignment_requirements)
221cb0ef41Sopenharmony_ci    : isolate_(isolate),
231cb0ef41Sopenharmony_ci      graph_(graph),
241cb0ef41Sopenharmony_ci      schedule_(zone()->New<Schedule>(zone())),
251cb0ef41Sopenharmony_ci      source_positions_(zone()->New<SourcePositionTable>(graph)),
261cb0ef41Sopenharmony_ci      machine_(zone(), word, flags, alignment_requirements),
271cb0ef41Sopenharmony_ci      common_(zone()),
281cb0ef41Sopenharmony_ci      simplified_(zone()),
291cb0ef41Sopenharmony_ci      call_descriptor_(call_descriptor),
301cb0ef41Sopenharmony_ci      target_parameter_(nullptr),
311cb0ef41Sopenharmony_ci      parameters_(parameter_count(), zone()),
321cb0ef41Sopenharmony_ci      current_block_(schedule()->start()) {
331cb0ef41Sopenharmony_ci  int param_count = static_cast<int>(parameter_count());
341cb0ef41Sopenharmony_ci  // Add an extra input for the JSFunction parameter to the start node.
351cb0ef41Sopenharmony_ci  graph->SetStart(graph->NewNode(common_.Start(param_count + 1)));
361cb0ef41Sopenharmony_ci  if (call_descriptor->IsJSFunctionCall()) {
371cb0ef41Sopenharmony_ci    target_parameter_ = AddNode(
381cb0ef41Sopenharmony_ci        common()->Parameter(Linkage::kJSCallClosureParamIndex), graph->start());
391cb0ef41Sopenharmony_ci  }
401cb0ef41Sopenharmony_ci  for (size_t i = 0; i < parameter_count(); ++i) {
411cb0ef41Sopenharmony_ci    parameters_[i] =
421cb0ef41Sopenharmony_ci        AddNode(common()->Parameter(static_cast<int>(i)), graph->start());
431cb0ef41Sopenharmony_ci  }
441cb0ef41Sopenharmony_ci  graph->SetEnd(graph->NewNode(common_.End(0)));
451cb0ef41Sopenharmony_ci  source_positions_->AddDecorator();
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_civoid RawMachineAssembler::SetCurrentExternalSourcePosition(
491cb0ef41Sopenharmony_ci    FileAndLine file_and_line) {
501cb0ef41Sopenharmony_ci  int file_id =
511cb0ef41Sopenharmony_ci      isolate()->LookupOrAddExternallyCompiledFilename(file_and_line.first);
521cb0ef41Sopenharmony_ci  SourcePosition p = SourcePosition::External(file_and_line.second, file_id);
531cb0ef41Sopenharmony_ci  DCHECK(p.ExternalLine() == file_and_line.second);
541cb0ef41Sopenharmony_ci  source_positions()->SetCurrentPosition(p);
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ciFileAndLine RawMachineAssembler::GetCurrentExternalSourcePosition() const {
581cb0ef41Sopenharmony_ci  SourcePosition p = source_positions_->GetCurrentPosition();
591cb0ef41Sopenharmony_ci  if (!p.IsKnown()) return {nullptr, -1};
601cb0ef41Sopenharmony_ci  int file_id = p.ExternalFileId();
611cb0ef41Sopenharmony_ci  const char* file_name = isolate()->GetExternallyCompiledFilename(file_id);
621cb0ef41Sopenharmony_ci  int line = p.ExternalLine();
631cb0ef41Sopenharmony_ci  return {file_name, line};
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciNode* RawMachineAssembler::NullConstant() {
671cb0ef41Sopenharmony_ci  return HeapConstant(isolate()->factory()->null_value());
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ciNode* RawMachineAssembler::UndefinedConstant() {
711cb0ef41Sopenharmony_ci  return HeapConstant(isolate()->factory()->undefined_value());
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciNode* RawMachineAssembler::RelocatableIntPtrConstant(intptr_t value,
751cb0ef41Sopenharmony_ci                                                     RelocInfo::Mode rmode) {
761cb0ef41Sopenharmony_ci  return kSystemPointerSize == 8
771cb0ef41Sopenharmony_ci             ? RelocatableInt64Constant(value, rmode)
781cb0ef41Sopenharmony_ci             : RelocatableInt32Constant(static_cast<int>(value), rmode);
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ciNode* RawMachineAssembler::OptimizedAllocate(
821cb0ef41Sopenharmony_ci    Node* size, AllocationType allocation,
831cb0ef41Sopenharmony_ci    AllowLargeObjects allow_large_objects) {
841cb0ef41Sopenharmony_ci  return AddNode(
851cb0ef41Sopenharmony_ci      simplified()->AllocateRaw(Type::Any(), allocation, allow_large_objects),
861cb0ef41Sopenharmony_ci      size);
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciSchedule* RawMachineAssembler::ExportForTest() {
901cb0ef41Sopenharmony_ci  // Compute the correct codegen order.
911cb0ef41Sopenharmony_ci  DCHECK(schedule_->rpo_order()->empty());
921cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
931cb0ef41Sopenharmony_ci    PrintF("--- RAW SCHEDULE -------------------------------------------\n");
941cb0ef41Sopenharmony_ci    StdoutStream{} << *schedule_;
951cb0ef41Sopenharmony_ci  }
961cb0ef41Sopenharmony_ci  schedule_->EnsureCFGWellFormedness();
971cb0ef41Sopenharmony_ci  Scheduler::ComputeSpecialRPO(zone(), schedule_);
981cb0ef41Sopenharmony_ci  Scheduler::GenerateDominatorTree(schedule_);
991cb0ef41Sopenharmony_ci  schedule_->PropagateDeferredMark();
1001cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
1011cb0ef41Sopenharmony_ci    PrintF("--- EDGE SPLIT AND PROPAGATED DEFERRED SCHEDULE ------------\n");
1021cb0ef41Sopenharmony_ci    StdoutStream{} << *schedule_;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci  // Invalidate RawMachineAssembler.
1051cb0ef41Sopenharmony_ci  source_positions_->RemoveDecorator();
1061cb0ef41Sopenharmony_ci  Schedule* schedule = schedule_;
1071cb0ef41Sopenharmony_ci  schedule_ = nullptr;
1081cb0ef41Sopenharmony_ci  return schedule;
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ciGraph* RawMachineAssembler::ExportForOptimization() {
1121cb0ef41Sopenharmony_ci  // Compute the correct codegen order.
1131cb0ef41Sopenharmony_ci  DCHECK(schedule_->rpo_order()->empty());
1141cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
1151cb0ef41Sopenharmony_ci    PrintF("--- RAW SCHEDULE -------------------------------------------\n");
1161cb0ef41Sopenharmony_ci    StdoutStream{} << *schedule_;
1171cb0ef41Sopenharmony_ci  }
1181cb0ef41Sopenharmony_ci  schedule_->EnsureCFGWellFormedness();
1191cb0ef41Sopenharmony_ci  OptimizeControlFlow(schedule_, graph(), common());
1201cb0ef41Sopenharmony_ci  Scheduler::ComputeSpecialRPO(zone(), schedule_);
1211cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
1221cb0ef41Sopenharmony_ci    PrintF("--- SCHEDULE BEFORE GRAPH CREATION -------------------------\n");
1231cb0ef41Sopenharmony_ci    StdoutStream{} << *schedule_;
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci  MakeReschedulable();
1261cb0ef41Sopenharmony_ci  // Invalidate RawMachineAssembler.
1271cb0ef41Sopenharmony_ci  schedule_ = nullptr;
1281cb0ef41Sopenharmony_ci  return graph();
1291cb0ef41Sopenharmony_ci}
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_civoid RawMachineAssembler::OptimizeControlFlow(Schedule* schedule, Graph* graph,
1321cb0ef41Sopenharmony_ci                                              CommonOperatorBuilder* common) {
1331cb0ef41Sopenharmony_ci  for (bool changed = true; changed;) {
1341cb0ef41Sopenharmony_ci    changed = false;
1351cb0ef41Sopenharmony_ci    for (size_t i = 0; i < schedule->all_blocks()->size(); ++i) {
1361cb0ef41Sopenharmony_ci      BasicBlock* block = (*schedule->all_blocks())[i];
1371cb0ef41Sopenharmony_ci      if (block == nullptr) continue;
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci      // Short-circuit a goto if the succeeding block is not a control-flow
1401cb0ef41Sopenharmony_ci      // merge. This is not really useful on it's own since graph construction
1411cb0ef41Sopenharmony_ci      // has the same effect, but combining blocks improves the pattern-match on
1421cb0ef41Sopenharmony_ci      // their structure below.
1431cb0ef41Sopenharmony_ci      if (block->control() == BasicBlock::kGoto) {
1441cb0ef41Sopenharmony_ci        DCHECK_EQ(block->SuccessorCount(), 1);
1451cb0ef41Sopenharmony_ci        BasicBlock* successor = block->SuccessorAt(0);
1461cb0ef41Sopenharmony_ci        if (successor->PredecessorCount() == 1) {
1471cb0ef41Sopenharmony_ci          DCHECK_EQ(successor->PredecessorAt(0), block);
1481cb0ef41Sopenharmony_ci          for (Node* node : *successor) {
1491cb0ef41Sopenharmony_ci            schedule->SetBlockForNode(nullptr, node);
1501cb0ef41Sopenharmony_ci            schedule->AddNode(block, node);
1511cb0ef41Sopenharmony_ci          }
1521cb0ef41Sopenharmony_ci          block->set_control(successor->control());
1531cb0ef41Sopenharmony_ci          Node* control_input = successor->control_input();
1541cb0ef41Sopenharmony_ci          block->set_control_input(control_input);
1551cb0ef41Sopenharmony_ci          if (control_input) {
1561cb0ef41Sopenharmony_ci            schedule->SetBlockForNode(block, control_input);
1571cb0ef41Sopenharmony_ci          }
1581cb0ef41Sopenharmony_ci          if (successor->deferred()) block->set_deferred(true);
1591cb0ef41Sopenharmony_ci          block->ClearSuccessors();
1601cb0ef41Sopenharmony_ci          schedule->MoveSuccessors(successor, block);
1611cb0ef41Sopenharmony_ci          schedule->ClearBlockById(successor->id());
1621cb0ef41Sopenharmony_ci          changed = true;
1631cb0ef41Sopenharmony_ci          --i;
1641cb0ef41Sopenharmony_ci          continue;
1651cb0ef41Sopenharmony_ci        }
1661cb0ef41Sopenharmony_ci      }
1671cb0ef41Sopenharmony_ci      // Block-cloning in the simple case where a block consists only of a phi
1681cb0ef41Sopenharmony_ci      // node and a branch on that phi. This just duplicates the branch block
1691cb0ef41Sopenharmony_ci      // for each predecessor, replacing the phi node with the corresponding phi
1701cb0ef41Sopenharmony_ci      // input.
1711cb0ef41Sopenharmony_ci      if (block->control() == BasicBlock::kBranch && block->NodeCount() == 1) {
1721cb0ef41Sopenharmony_ci        Node* phi = block->NodeAt(0);
1731cb0ef41Sopenharmony_ci        if (phi->opcode() != IrOpcode::kPhi) continue;
1741cb0ef41Sopenharmony_ci        Node* branch = block->control_input();
1751cb0ef41Sopenharmony_ci        DCHECK_EQ(branch->opcode(), IrOpcode::kBranch);
1761cb0ef41Sopenharmony_ci        if (NodeProperties::GetValueInput(branch, 0) != phi) continue;
1771cb0ef41Sopenharmony_ci        if (phi->UseCount() != 1) continue;
1781cb0ef41Sopenharmony_ci        DCHECK_EQ(phi->op()->ValueInputCount(), block->PredecessorCount());
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci        // Turn projection blocks into normal blocks.
1811cb0ef41Sopenharmony_ci        DCHECK_EQ(block->SuccessorCount(), 2);
1821cb0ef41Sopenharmony_ci        BasicBlock* true_block = block->SuccessorAt(0);
1831cb0ef41Sopenharmony_ci        BasicBlock* false_block = block->SuccessorAt(1);
1841cb0ef41Sopenharmony_ci        DCHECK_EQ(true_block->NodeAt(0)->opcode(), IrOpcode::kIfTrue);
1851cb0ef41Sopenharmony_ci        DCHECK_EQ(false_block->NodeAt(0)->opcode(), IrOpcode::kIfFalse);
1861cb0ef41Sopenharmony_ci        (*true_block->begin())->Kill();
1871cb0ef41Sopenharmony_ci        true_block->RemoveNode(true_block->begin());
1881cb0ef41Sopenharmony_ci        (*false_block->begin())->Kill();
1891cb0ef41Sopenharmony_ci        false_block->RemoveNode(false_block->begin());
1901cb0ef41Sopenharmony_ci        true_block->ClearPredecessors();
1911cb0ef41Sopenharmony_ci        false_block->ClearPredecessors();
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci        size_t arity = block->PredecessorCount();
1941cb0ef41Sopenharmony_ci        for (size_t j = 0; j < arity; ++j) {
1951cb0ef41Sopenharmony_ci          BasicBlock* predecessor = block->PredecessorAt(j);
1961cb0ef41Sopenharmony_ci          predecessor->ClearSuccessors();
1971cb0ef41Sopenharmony_ci          if (block->deferred()) predecessor->set_deferred(true);
1981cb0ef41Sopenharmony_ci          Node* branch_clone = graph->CloneNode(branch);
1991cb0ef41Sopenharmony_ci          int phi_input = static_cast<int>(j);
2001cb0ef41Sopenharmony_ci          NodeProperties::ReplaceValueInput(
2011cb0ef41Sopenharmony_ci              branch_clone, NodeProperties::GetValueInput(phi, phi_input), 0);
2021cb0ef41Sopenharmony_ci          BasicBlock* new_true_block = schedule->NewBasicBlock();
2031cb0ef41Sopenharmony_ci          BasicBlock* new_false_block = schedule->NewBasicBlock();
2041cb0ef41Sopenharmony_ci          new_true_block->AddNode(
2051cb0ef41Sopenharmony_ci              graph->NewNode(common->IfTrue(), branch_clone));
2061cb0ef41Sopenharmony_ci          new_false_block->AddNode(
2071cb0ef41Sopenharmony_ci              graph->NewNode(common->IfFalse(), branch_clone));
2081cb0ef41Sopenharmony_ci          schedule->AddGoto(new_true_block, true_block);
2091cb0ef41Sopenharmony_ci          schedule->AddGoto(new_false_block, false_block);
2101cb0ef41Sopenharmony_ci          DCHECK_EQ(predecessor->control(), BasicBlock::kGoto);
2111cb0ef41Sopenharmony_ci          predecessor->set_control(BasicBlock::kNone);
2121cb0ef41Sopenharmony_ci          schedule->AddBranch(predecessor, branch_clone, new_true_block,
2131cb0ef41Sopenharmony_ci                              new_false_block);
2141cb0ef41Sopenharmony_ci        }
2151cb0ef41Sopenharmony_ci        branch->Kill();
2161cb0ef41Sopenharmony_ci        schedule->ClearBlockById(block->id());
2171cb0ef41Sopenharmony_ci        changed = true;
2181cb0ef41Sopenharmony_ci        continue;
2191cb0ef41Sopenharmony_ci      }
2201cb0ef41Sopenharmony_ci    }
2211cb0ef41Sopenharmony_ci  }
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_civoid RawMachineAssembler::MakeReschedulable() {
2251cb0ef41Sopenharmony_ci  std::vector<Node*> block_final_control(schedule_->all_blocks_.size());
2261cb0ef41Sopenharmony_ci  std::vector<Node*> block_final_effect(schedule_->all_blocks_.size());
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  struct LoopHeader {
2291cb0ef41Sopenharmony_ci    BasicBlock* block;
2301cb0ef41Sopenharmony_ci    Node* loop_node;
2311cb0ef41Sopenharmony_ci    Node* effect_phi;
2321cb0ef41Sopenharmony_ci  };
2331cb0ef41Sopenharmony_ci  std::vector<LoopHeader> loop_headers;
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  // These are hoisted outside of the loop to avoid re-allocation.
2361cb0ef41Sopenharmony_ci  std::vector<Node*> merge_inputs;
2371cb0ef41Sopenharmony_ci  std::vector<Node*> effect_phi_inputs;
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  for (BasicBlock* block : *schedule_->rpo_order()) {
2401cb0ef41Sopenharmony_ci    Node* current_control;
2411cb0ef41Sopenharmony_ci    Node* current_effect;
2421cb0ef41Sopenharmony_ci    if (block == schedule_->start()) {
2431cb0ef41Sopenharmony_ci      current_control = current_effect = graph()->start();
2441cb0ef41Sopenharmony_ci    } else if (block == schedule_->end()) {
2451cb0ef41Sopenharmony_ci      for (size_t i = 0; i < block->PredecessorCount(); ++i) {
2461cb0ef41Sopenharmony_ci        NodeProperties::MergeControlToEnd(
2471cb0ef41Sopenharmony_ci            graph(), common(), block->PredecessorAt(i)->control_input());
2481cb0ef41Sopenharmony_ci      }
2491cb0ef41Sopenharmony_ci    } else if (block->IsLoopHeader()) {
2501cb0ef41Sopenharmony_ci      // The graph()->start() inputs are just placeholders until we computed the
2511cb0ef41Sopenharmony_ci      // real back-edges and re-structure the control flow so the loop has
2521cb0ef41Sopenharmony_ci      // exactly two predecessors.
2531cb0ef41Sopenharmony_ci      current_control = graph()->NewNode(common()->Loop(2), graph()->start(),
2541cb0ef41Sopenharmony_ci                                         graph()->start());
2551cb0ef41Sopenharmony_ci      current_effect =
2561cb0ef41Sopenharmony_ci          graph()->NewNode(common()->EffectPhi(2), graph()->start(),
2571cb0ef41Sopenharmony_ci                           graph()->start(), current_control);
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci      Node* terminate = graph()->NewNode(common()->Terminate(), current_effect,
2601cb0ef41Sopenharmony_ci                                         current_control);
2611cb0ef41Sopenharmony_ci      NodeProperties::MergeControlToEnd(graph(), common(), terminate);
2621cb0ef41Sopenharmony_ci      loop_headers.push_back(
2631cb0ef41Sopenharmony_ci          LoopHeader{block, current_control, current_effect});
2641cb0ef41Sopenharmony_ci    } else if (block->PredecessorCount() == 1) {
2651cb0ef41Sopenharmony_ci      BasicBlock* predecessor = block->PredecessorAt(0);
2661cb0ef41Sopenharmony_ci      DCHECK_LT(predecessor->rpo_number(), block->rpo_number());
2671cb0ef41Sopenharmony_ci      current_effect = block_final_effect[predecessor->id().ToSize()];
2681cb0ef41Sopenharmony_ci      current_control = block_final_control[predecessor->id().ToSize()];
2691cb0ef41Sopenharmony_ci    } else {
2701cb0ef41Sopenharmony_ci      // Create control merge nodes and effect phis for all predecessor blocks.
2711cb0ef41Sopenharmony_ci      merge_inputs.clear();
2721cb0ef41Sopenharmony_ci      effect_phi_inputs.clear();
2731cb0ef41Sopenharmony_ci      int predecessor_count = static_cast<int>(block->PredecessorCount());
2741cb0ef41Sopenharmony_ci      for (int i = 0; i < predecessor_count; ++i) {
2751cb0ef41Sopenharmony_ci        BasicBlock* predecessor = block->PredecessorAt(i);
2761cb0ef41Sopenharmony_ci        DCHECK_LT(predecessor->rpo_number(), block->rpo_number());
2771cb0ef41Sopenharmony_ci        merge_inputs.push_back(block_final_control[predecessor->id().ToSize()]);
2781cb0ef41Sopenharmony_ci        effect_phi_inputs.push_back(
2791cb0ef41Sopenharmony_ci            block_final_effect[predecessor->id().ToSize()]);
2801cb0ef41Sopenharmony_ci      }
2811cb0ef41Sopenharmony_ci      current_control = graph()->NewNode(common()->Merge(predecessor_count),
2821cb0ef41Sopenharmony_ci                                         static_cast<int>(merge_inputs.size()),
2831cb0ef41Sopenharmony_ci                                         merge_inputs.data());
2841cb0ef41Sopenharmony_ci      effect_phi_inputs.push_back(current_control);
2851cb0ef41Sopenharmony_ci      current_effect = graph()->NewNode(
2861cb0ef41Sopenharmony_ci          common()->EffectPhi(predecessor_count),
2871cb0ef41Sopenharmony_ci          static_cast<int>(effect_phi_inputs.size()), effect_phi_inputs.data());
2881cb0ef41Sopenharmony_ci    }
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci    auto update_current_control_and_effect = [&](Node* node) {
2911cb0ef41Sopenharmony_ci      bool existing_effect_and_control =
2921cb0ef41Sopenharmony_ci          IrOpcode::IsIfProjectionOpcode(node->opcode()) ||
2931cb0ef41Sopenharmony_ci          IrOpcode::IsPhiOpcode(node->opcode());
2941cb0ef41Sopenharmony_ci      if (node->op()->EffectInputCount() > 0) {
2951cb0ef41Sopenharmony_ci        DCHECK_EQ(1, node->op()->EffectInputCount());
2961cb0ef41Sopenharmony_ci        if (existing_effect_and_control) {
2971cb0ef41Sopenharmony_ci          NodeProperties::ReplaceEffectInput(node, current_effect);
2981cb0ef41Sopenharmony_ci        } else {
2991cb0ef41Sopenharmony_ci          node->AppendInput(graph()->zone(), current_effect);
3001cb0ef41Sopenharmony_ci        }
3011cb0ef41Sopenharmony_ci      }
3021cb0ef41Sopenharmony_ci      if (node->op()->ControlInputCount() > 0) {
3031cb0ef41Sopenharmony_ci        DCHECK_EQ(1, node->op()->ControlInputCount());
3041cb0ef41Sopenharmony_ci        if (existing_effect_and_control) {
3051cb0ef41Sopenharmony_ci          NodeProperties::ReplaceControlInput(node, current_control);
3061cb0ef41Sopenharmony_ci        } else {
3071cb0ef41Sopenharmony_ci          node->AppendInput(graph()->zone(), current_control);
3081cb0ef41Sopenharmony_ci        }
3091cb0ef41Sopenharmony_ci      }
3101cb0ef41Sopenharmony_ci      if (node->op()->EffectOutputCount() > 0) {
3111cb0ef41Sopenharmony_ci        DCHECK_EQ(1, node->op()->EffectOutputCount());
3121cb0ef41Sopenharmony_ci        current_effect = node;
3131cb0ef41Sopenharmony_ci      }
3141cb0ef41Sopenharmony_ci      if (node->op()->ControlOutputCount() > 0) {
3151cb0ef41Sopenharmony_ci        current_control = node;
3161cb0ef41Sopenharmony_ci      }
3171cb0ef41Sopenharmony_ci    };
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci    for (Node* node : *block) {
3201cb0ef41Sopenharmony_ci      update_current_control_and_effect(node);
3211cb0ef41Sopenharmony_ci    }
3221cb0ef41Sopenharmony_ci    if (block->deferred()) MarkControlDeferred(current_control);
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci    if (Node* block_terminator = block->control_input()) {
3251cb0ef41Sopenharmony_ci      update_current_control_and_effect(block_terminator);
3261cb0ef41Sopenharmony_ci    }
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci    block_final_effect[block->id().ToSize()] = current_effect;
3291cb0ef41Sopenharmony_ci    block_final_control[block->id().ToSize()] = current_control;
3301cb0ef41Sopenharmony_ci  }
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  // Fix-up loop backedges and re-structure control flow so that loop nodes have
3331cb0ef41Sopenharmony_ci  // exactly two control predecessors.
3341cb0ef41Sopenharmony_ci  for (const LoopHeader& loop_header : loop_headers) {
3351cb0ef41Sopenharmony_ci    BasicBlock* block = loop_header.block;
3361cb0ef41Sopenharmony_ci    std::vector<BasicBlock*> loop_entries;
3371cb0ef41Sopenharmony_ci    std::vector<BasicBlock*> loop_backedges;
3381cb0ef41Sopenharmony_ci    for (size_t i = 0; i < block->PredecessorCount(); ++i) {
3391cb0ef41Sopenharmony_ci      BasicBlock* predecessor = block->PredecessorAt(i);
3401cb0ef41Sopenharmony_ci      if (block->LoopContains(predecessor)) {
3411cb0ef41Sopenharmony_ci        loop_backedges.push_back(predecessor);
3421cb0ef41Sopenharmony_ci      } else {
3431cb0ef41Sopenharmony_ci        DCHECK(loop_backedges.empty());
3441cb0ef41Sopenharmony_ci        loop_entries.push_back(predecessor);
3451cb0ef41Sopenharmony_ci      }
3461cb0ef41Sopenharmony_ci    }
3471cb0ef41Sopenharmony_ci    DCHECK(!loop_entries.empty());
3481cb0ef41Sopenharmony_ci    DCHECK(!loop_backedges.empty());
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci    int entrance_count = static_cast<int>(loop_entries.size());
3511cb0ef41Sopenharmony_ci    int backedge_count = static_cast<int>(loop_backedges.size());
3521cb0ef41Sopenharmony_ci    Node* control_loop_entry = CreateNodeFromPredecessors(
3531cb0ef41Sopenharmony_ci        loop_entries, block_final_control, common()->Merge(entrance_count), {});
3541cb0ef41Sopenharmony_ci    Node* control_backedge =
3551cb0ef41Sopenharmony_ci        CreateNodeFromPredecessors(loop_backedges, block_final_control,
3561cb0ef41Sopenharmony_ci                                   common()->Merge(backedge_count), {});
3571cb0ef41Sopenharmony_ci    Node* effect_loop_entry = CreateNodeFromPredecessors(
3581cb0ef41Sopenharmony_ci        loop_entries, block_final_effect, common()->EffectPhi(entrance_count),
3591cb0ef41Sopenharmony_ci        {control_loop_entry});
3601cb0ef41Sopenharmony_ci    Node* effect_backedge = CreateNodeFromPredecessors(
3611cb0ef41Sopenharmony_ci        loop_backedges, block_final_effect, common()->EffectPhi(backedge_count),
3621cb0ef41Sopenharmony_ci        {control_backedge});
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci    loop_header.loop_node->ReplaceInput(0, control_loop_entry);
3651cb0ef41Sopenharmony_ci    loop_header.loop_node->ReplaceInput(1, control_backedge);
3661cb0ef41Sopenharmony_ci    loop_header.effect_phi->ReplaceInput(0, effect_loop_entry);
3671cb0ef41Sopenharmony_ci    loop_header.effect_phi->ReplaceInput(1, effect_backedge);
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci    for (Node* node : *block) {
3701cb0ef41Sopenharmony_ci      if (node->opcode() == IrOpcode::kPhi) {
3711cb0ef41Sopenharmony_ci        MakePhiBinary(node, static_cast<int>(loop_entries.size()),
3721cb0ef41Sopenharmony_ci                      control_loop_entry, control_backedge);
3731cb0ef41Sopenharmony_ci      }
3741cb0ef41Sopenharmony_ci    }
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci}
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CreateNodeFromPredecessors(
3791cb0ef41Sopenharmony_ci    const std::vector<BasicBlock*>& predecessors,
3801cb0ef41Sopenharmony_ci    const std::vector<Node*>& sidetable, const Operator* op,
3811cb0ef41Sopenharmony_ci    const std::vector<Node*>& additional_inputs) {
3821cb0ef41Sopenharmony_ci  if (predecessors.size() == 1) {
3831cb0ef41Sopenharmony_ci    return sidetable[predecessors.front()->id().ToSize()];
3841cb0ef41Sopenharmony_ci  }
3851cb0ef41Sopenharmony_ci  std::vector<Node*> inputs;
3861cb0ef41Sopenharmony_ci  inputs.reserve(predecessors.size());
3871cb0ef41Sopenharmony_ci  for (BasicBlock* predecessor : predecessors) {
3881cb0ef41Sopenharmony_ci    inputs.push_back(sidetable[predecessor->id().ToSize()]);
3891cb0ef41Sopenharmony_ci  }
3901cb0ef41Sopenharmony_ci  for (Node* additional_input : additional_inputs) {
3911cb0ef41Sopenharmony_ci    inputs.push_back(additional_input);
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci  return graph()->NewNode(op, static_cast<int>(inputs.size()), inputs.data());
3941cb0ef41Sopenharmony_ci}
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_civoid RawMachineAssembler::MakePhiBinary(Node* phi, int split_point,
3971cb0ef41Sopenharmony_ci                                        Node* left_control,
3981cb0ef41Sopenharmony_ci                                        Node* right_control) {
3991cb0ef41Sopenharmony_ci  int value_count = phi->op()->ValueInputCount();
4001cb0ef41Sopenharmony_ci  if (value_count == 2) return;
4011cb0ef41Sopenharmony_ci  DCHECK_LT(split_point, value_count);
4021cb0ef41Sopenharmony_ci  DCHECK_GT(split_point, 0);
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  MachineRepresentation rep = PhiRepresentationOf(phi->op());
4051cb0ef41Sopenharmony_ci  int left_input_count = split_point;
4061cb0ef41Sopenharmony_ci  int right_input_count = value_count - split_point;
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  Node* left_input;
4091cb0ef41Sopenharmony_ci  if (left_input_count == 1) {
4101cb0ef41Sopenharmony_ci    left_input = NodeProperties::GetValueInput(phi, 0);
4111cb0ef41Sopenharmony_ci  } else {
4121cb0ef41Sopenharmony_ci    std::vector<Node*> inputs;
4131cb0ef41Sopenharmony_ci    inputs.reserve(left_input_count);
4141cb0ef41Sopenharmony_ci    for (int i = 0; i < left_input_count; ++i) {
4151cb0ef41Sopenharmony_ci      inputs.push_back(NodeProperties::GetValueInput(phi, i));
4161cb0ef41Sopenharmony_ci    }
4171cb0ef41Sopenharmony_ci    inputs.push_back(left_control);
4181cb0ef41Sopenharmony_ci    left_input =
4191cb0ef41Sopenharmony_ci        graph()->NewNode(common()->Phi(rep, static_cast<int>(left_input_count)),
4201cb0ef41Sopenharmony_ci                         static_cast<int>(inputs.size()), inputs.data());
4211cb0ef41Sopenharmony_ci  }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  Node* right_input;
4241cb0ef41Sopenharmony_ci  if (right_input_count == 1) {
4251cb0ef41Sopenharmony_ci    right_input = NodeProperties::GetValueInput(phi, split_point);
4261cb0ef41Sopenharmony_ci  } else {
4271cb0ef41Sopenharmony_ci    std::vector<Node*> inputs;
4281cb0ef41Sopenharmony_ci    for (int i = split_point; i < value_count; ++i) {
4291cb0ef41Sopenharmony_ci      inputs.push_back(NodeProperties::GetValueInput(phi, i));
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci    inputs.push_back(right_control);
4321cb0ef41Sopenharmony_ci    right_input = graph()->NewNode(
4331cb0ef41Sopenharmony_ci        common()->Phi(rep, static_cast<int>(right_input_count)),
4341cb0ef41Sopenharmony_ci        static_cast<int>(inputs.size()), inputs.data());
4351cb0ef41Sopenharmony_ci  }
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci  Node* control = NodeProperties::GetControlInput(phi);
4381cb0ef41Sopenharmony_ci  phi->TrimInputCount(3);
4391cb0ef41Sopenharmony_ci  phi->ReplaceInput(0, left_input);
4401cb0ef41Sopenharmony_ci  phi->ReplaceInput(1, right_input);
4411cb0ef41Sopenharmony_ci  phi->ReplaceInput(2, control);
4421cb0ef41Sopenharmony_ci  NodeProperties::ChangeOp(phi, common()->Phi(rep, 2));
4431cb0ef41Sopenharmony_ci}
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_civoid RawMachineAssembler::MarkControlDeferred(Node* control_node) {
4461cb0ef41Sopenharmony_ci  BranchHint new_branch_hint;
4471cb0ef41Sopenharmony_ci  Node* responsible_branch = nullptr;
4481cb0ef41Sopenharmony_ci  while (responsible_branch == nullptr) {
4491cb0ef41Sopenharmony_ci    switch (control_node->opcode()) {
4501cb0ef41Sopenharmony_ci      case IrOpcode::kIfException:
4511cb0ef41Sopenharmony_ci        // IfException projections are deferred by default.
4521cb0ef41Sopenharmony_ci        return;
4531cb0ef41Sopenharmony_ci      case IrOpcode::kIfSuccess:
4541cb0ef41Sopenharmony_ci        control_node = NodeProperties::GetControlInput(control_node);
4551cb0ef41Sopenharmony_ci        continue;
4561cb0ef41Sopenharmony_ci      case IrOpcode::kIfValue: {
4571cb0ef41Sopenharmony_ci        IfValueParameters parameters = IfValueParametersOf(control_node->op());
4581cb0ef41Sopenharmony_ci        if (parameters.hint() != BranchHint::kFalse) {
4591cb0ef41Sopenharmony_ci          NodeProperties::ChangeOp(
4601cb0ef41Sopenharmony_ci              control_node, common()->IfValue(parameters.value(),
4611cb0ef41Sopenharmony_ci                                              parameters.comparison_order(),
4621cb0ef41Sopenharmony_ci                                              BranchHint::kFalse));
4631cb0ef41Sopenharmony_ci        }
4641cb0ef41Sopenharmony_ci        return;
4651cb0ef41Sopenharmony_ci      }
4661cb0ef41Sopenharmony_ci      case IrOpcode::kIfDefault:
4671cb0ef41Sopenharmony_ci        if (BranchHintOf(control_node->op()) != BranchHint::kFalse) {
4681cb0ef41Sopenharmony_ci          NodeProperties::ChangeOp(control_node,
4691cb0ef41Sopenharmony_ci                                   common()->IfDefault(BranchHint::kFalse));
4701cb0ef41Sopenharmony_ci        }
4711cb0ef41Sopenharmony_ci        return;
4721cb0ef41Sopenharmony_ci      case IrOpcode::kIfTrue: {
4731cb0ef41Sopenharmony_ci        Node* branch = NodeProperties::GetControlInput(control_node);
4741cb0ef41Sopenharmony_ci        BranchHint hint = BranchHintOf(branch->op());
4751cb0ef41Sopenharmony_ci        if (hint == BranchHint::kTrue) {
4761cb0ef41Sopenharmony_ci          // The other possibility is also deferred, so the responsible branch
4771cb0ef41Sopenharmony_ci          // has to be before.
4781cb0ef41Sopenharmony_ci          control_node = NodeProperties::GetControlInput(branch);
4791cb0ef41Sopenharmony_ci          continue;
4801cb0ef41Sopenharmony_ci        }
4811cb0ef41Sopenharmony_ci        new_branch_hint = BranchHint::kFalse;
4821cb0ef41Sopenharmony_ci        responsible_branch = branch;
4831cb0ef41Sopenharmony_ci        break;
4841cb0ef41Sopenharmony_ci      }
4851cb0ef41Sopenharmony_ci      case IrOpcode::kIfFalse: {
4861cb0ef41Sopenharmony_ci        Node* branch = NodeProperties::GetControlInput(control_node);
4871cb0ef41Sopenharmony_ci        BranchHint hint = BranchHintOf(branch->op());
4881cb0ef41Sopenharmony_ci        if (hint == BranchHint::kFalse) {
4891cb0ef41Sopenharmony_ci          // The other possibility is also deferred, so the responsible branch
4901cb0ef41Sopenharmony_ci          // has to be before.
4911cb0ef41Sopenharmony_ci          control_node = NodeProperties::GetControlInput(branch);
4921cb0ef41Sopenharmony_ci          continue;
4931cb0ef41Sopenharmony_ci        }
4941cb0ef41Sopenharmony_ci        new_branch_hint = BranchHint::kTrue;
4951cb0ef41Sopenharmony_ci        responsible_branch = branch;
4961cb0ef41Sopenharmony_ci        break;
4971cb0ef41Sopenharmony_ci      }
4981cb0ef41Sopenharmony_ci      case IrOpcode::kMerge:
4991cb0ef41Sopenharmony_ci        for (int i = 0; i < control_node->op()->ControlInputCount(); ++i) {
5001cb0ef41Sopenharmony_ci          MarkControlDeferred(NodeProperties::GetControlInput(control_node, i));
5011cb0ef41Sopenharmony_ci        }
5021cb0ef41Sopenharmony_ci        return;
5031cb0ef41Sopenharmony_ci      case IrOpcode::kLoop:
5041cb0ef41Sopenharmony_ci        control_node = NodeProperties::GetControlInput(control_node, 0);
5051cb0ef41Sopenharmony_ci        continue;
5061cb0ef41Sopenharmony_ci      case IrOpcode::kBranch:
5071cb0ef41Sopenharmony_ci      case IrOpcode::kSwitch:
5081cb0ef41Sopenharmony_ci        UNREACHABLE();
5091cb0ef41Sopenharmony_ci      case IrOpcode::kStart:
5101cb0ef41Sopenharmony_ci        return;
5111cb0ef41Sopenharmony_ci      default:
5121cb0ef41Sopenharmony_ci        DCHECK_EQ(1, control_node->op()->ControlInputCount());
5131cb0ef41Sopenharmony_ci        control_node = NodeProperties::GetControlInput(control_node);
5141cb0ef41Sopenharmony_ci        continue;
5151cb0ef41Sopenharmony_ci    }
5161cb0ef41Sopenharmony_ci  }
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ci  BranchHint hint = BranchHintOf(responsible_branch->op());
5191cb0ef41Sopenharmony_ci  if (hint == new_branch_hint) return;
5201cb0ef41Sopenharmony_ci  NodeProperties::ChangeOp(responsible_branch,
5211cb0ef41Sopenharmony_ci                           common()->Branch(new_branch_hint));
5221cb0ef41Sopenharmony_ci}
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ciNode* RawMachineAssembler::TargetParameter() {
5251cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(target_parameter_);
5261cb0ef41Sopenharmony_ci  return target_parameter_;
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ciNode* RawMachineAssembler::Parameter(size_t index) {
5301cb0ef41Sopenharmony_ci  DCHECK_LT(index, parameter_count());
5311cb0ef41Sopenharmony_ci  return parameters_[index];
5321cb0ef41Sopenharmony_ci}
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci
5351cb0ef41Sopenharmony_civoid RawMachineAssembler::Goto(RawMachineLabel* label) {
5361cb0ef41Sopenharmony_ci  DCHECK(current_block_ != schedule()->end());
5371cb0ef41Sopenharmony_ci  schedule()->AddGoto(CurrentBlock(), Use(label));
5381cb0ef41Sopenharmony_ci  current_block_ = nullptr;
5391cb0ef41Sopenharmony_ci}
5401cb0ef41Sopenharmony_ci
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_civoid RawMachineAssembler::Branch(Node* condition, RawMachineLabel* true_val,
5431cb0ef41Sopenharmony_ci                                 RawMachineLabel* false_val) {
5441cb0ef41Sopenharmony_ci  DCHECK(current_block_ != schedule()->end());
5451cb0ef41Sopenharmony_ci  Node* branch = MakeNode(common()->Branch(BranchHint::kNone), 1, &condition);
5461cb0ef41Sopenharmony_ci  BasicBlock* true_block = schedule()->NewBasicBlock();
5471cb0ef41Sopenharmony_ci  BasicBlock* false_block = schedule()->NewBasicBlock();
5481cb0ef41Sopenharmony_ci  schedule()->AddBranch(CurrentBlock(), branch, true_block, false_block);
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci  true_block->AddNode(MakeNode(common()->IfTrue(), 1, &branch));
5511cb0ef41Sopenharmony_ci  schedule()->AddGoto(true_block, Use(true_val));
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci  false_block->AddNode(MakeNode(common()->IfFalse(), 1, &branch));
5541cb0ef41Sopenharmony_ci  schedule()->AddGoto(false_block, Use(false_val));
5551cb0ef41Sopenharmony_ci
5561cb0ef41Sopenharmony_ci  current_block_ = nullptr;
5571cb0ef41Sopenharmony_ci}
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_civoid RawMachineAssembler::Continuations(Node* call, RawMachineLabel* if_success,
5601cb0ef41Sopenharmony_ci                                        RawMachineLabel* if_exception) {
5611cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(schedule_);
5621cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(current_block_);
5631cb0ef41Sopenharmony_ci  schedule()->AddCall(CurrentBlock(), call, Use(if_success), Use(if_exception));
5641cb0ef41Sopenharmony_ci  current_block_ = nullptr;
5651cb0ef41Sopenharmony_ci}
5661cb0ef41Sopenharmony_ci
5671cb0ef41Sopenharmony_civoid RawMachineAssembler::Switch(Node* index, RawMachineLabel* default_label,
5681cb0ef41Sopenharmony_ci                                 const int32_t* case_values,
5691cb0ef41Sopenharmony_ci                                 RawMachineLabel** case_labels,
5701cb0ef41Sopenharmony_ci                                 size_t case_count) {
5711cb0ef41Sopenharmony_ci  DCHECK_NE(schedule()->end(), current_block_);
5721cb0ef41Sopenharmony_ci  size_t succ_count = case_count + 1;
5731cb0ef41Sopenharmony_ci  Node* switch_node = MakeNode(common()->Switch(succ_count), 1, &index);
5741cb0ef41Sopenharmony_ci  BasicBlock** succ_blocks = zone()->NewArray<BasicBlock*>(succ_count);
5751cb0ef41Sopenharmony_ci  for (size_t i = 0; i < case_count; ++i) {
5761cb0ef41Sopenharmony_ci    int32_t case_value = case_values[i];
5771cb0ef41Sopenharmony_ci    BasicBlock* case_block = schedule()->NewBasicBlock();
5781cb0ef41Sopenharmony_ci    Node* case_node =
5791cb0ef41Sopenharmony_ci        graph()->NewNode(common()->IfValue(case_value), switch_node);
5801cb0ef41Sopenharmony_ci    schedule()->AddNode(case_block, case_node);
5811cb0ef41Sopenharmony_ci    schedule()->AddGoto(case_block, Use(case_labels[i]));
5821cb0ef41Sopenharmony_ci    succ_blocks[i] = case_block;
5831cb0ef41Sopenharmony_ci  }
5841cb0ef41Sopenharmony_ci  BasicBlock* default_block = schedule()->NewBasicBlock();
5851cb0ef41Sopenharmony_ci  Node* default_node = graph()->NewNode(common()->IfDefault(), switch_node);
5861cb0ef41Sopenharmony_ci  schedule()->AddNode(default_block, default_node);
5871cb0ef41Sopenharmony_ci  schedule()->AddGoto(default_block, Use(default_label));
5881cb0ef41Sopenharmony_ci  succ_blocks[case_count] = default_block;
5891cb0ef41Sopenharmony_ci  schedule()->AddSwitch(CurrentBlock(), switch_node, succ_blocks, succ_count);
5901cb0ef41Sopenharmony_ci  current_block_ = nullptr;
5911cb0ef41Sopenharmony_ci}
5921cb0ef41Sopenharmony_ci
5931cb0ef41Sopenharmony_civoid RawMachineAssembler::Return(Node* value) {
5941cb0ef41Sopenharmony_ci  Node* values[] = {Int32Constant(0), value};
5951cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(1), 2, values);
5961cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
5971cb0ef41Sopenharmony_ci  current_block_ = nullptr;
5981cb0ef41Sopenharmony_ci}
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_civoid RawMachineAssembler::Return(Node* v1, Node* v2) {
6011cb0ef41Sopenharmony_ci  Node* values[] = {Int32Constant(0), v1, v2};
6021cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(2), 3, values);
6031cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6041cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6051cb0ef41Sopenharmony_ci}
6061cb0ef41Sopenharmony_ci
6071cb0ef41Sopenharmony_civoid RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3) {
6081cb0ef41Sopenharmony_ci  Node* values[] = {Int32Constant(0), v1, v2, v3};
6091cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(3), 4, values);
6101cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6111cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6121cb0ef41Sopenharmony_ci}
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_civoid RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3, Node* v4) {
6151cb0ef41Sopenharmony_ci  Node* values[] = {Int32Constant(0), v1, v2, v3, v4};
6161cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(4), 5, values);
6171cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6181cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6191cb0ef41Sopenharmony_ci}
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_civoid RawMachineAssembler::Return(int count, Node* vs[]) {
6221cb0ef41Sopenharmony_ci  using Node_ptr = Node*;
6231cb0ef41Sopenharmony_ci  Node** values = new Node_ptr[count + 1];
6241cb0ef41Sopenharmony_ci  values[0] = Int32Constant(0);
6251cb0ef41Sopenharmony_ci  for (int i = 0; i < count; ++i) values[i + 1] = vs[i];
6261cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(count), count + 1, values);
6271cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6281cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6291cb0ef41Sopenharmony_ci  delete[] values;
6301cb0ef41Sopenharmony_ci}
6311cb0ef41Sopenharmony_ci
6321cb0ef41Sopenharmony_civoid RawMachineAssembler::PopAndReturn(Node* pop, Node* value) {
6331cb0ef41Sopenharmony_ci  // PopAndReturn is supposed to be using ONLY in CSA/Torque builtins for
6341cb0ef41Sopenharmony_ci  // dropping ALL JS arguments that are currently located on the stack.
6351cb0ef41Sopenharmony_ci  // The check below ensures that there are no directly accessible stack
6361cb0ef41Sopenharmony_ci  // parameters from current builtin, which implies that the builtin with
6371cb0ef41Sopenharmony_ci  // JS calling convention (TFJ) was created with kDontAdaptArgumentsSentinel.
6381cb0ef41Sopenharmony_ci  // This simplifies semantics of this instruction because in case of presence
6391cb0ef41Sopenharmony_ci  // of directly accessible stack parameters it's impossible to distinguish
6401cb0ef41Sopenharmony_ci  // the following cases:
6411cb0ef41Sopenharmony_ci  // 1) stack parameter is included in JS arguments (and therefore it will be
6421cb0ef41Sopenharmony_ci  //    dropped as a part of 'pop' number of arguments),
6431cb0ef41Sopenharmony_ci  // 2) stack parameter is NOT included in JS arguments (and therefore it should
6441cb0ef41Sopenharmony_ci  //    be dropped in ADDITION to the 'pop' number of arguments).
6451cb0ef41Sopenharmony_ci  // Additionally, in order to simplify assembly code, PopAndReturn is also
6461cb0ef41Sopenharmony_ci  // not allowed in builtins with stub linkage and parameters on stack.
6471cb0ef41Sopenharmony_ci  CHECK_EQ(call_descriptor()->ParameterSlotCount(), 0);
6481cb0ef41Sopenharmony_ci  Node* values[] = {pop, value};
6491cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(1), 2, values);
6501cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6511cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6521cb0ef41Sopenharmony_ci}
6531cb0ef41Sopenharmony_ci
6541cb0ef41Sopenharmony_civoid RawMachineAssembler::PopAndReturn(Node* pop, Node* v1, Node* v2) {
6551cb0ef41Sopenharmony_ci  Node* values[] = {pop, v1, v2};
6561cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(2), 3, values);
6571cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6581cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6591cb0ef41Sopenharmony_ci}
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_civoid RawMachineAssembler::PopAndReturn(Node* pop, Node* v1, Node* v2,
6621cb0ef41Sopenharmony_ci                                       Node* v3) {
6631cb0ef41Sopenharmony_ci  Node* values[] = {pop, v1, v2, v3};
6641cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(3), 4, values);
6651cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6661cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6671cb0ef41Sopenharmony_ci}
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_civoid RawMachineAssembler::PopAndReturn(Node* pop, Node* v1, Node* v2, Node* v3,
6701cb0ef41Sopenharmony_ci                                       Node* v4) {
6711cb0ef41Sopenharmony_ci  Node* values[] = {pop, v1, v2, v3, v4};
6721cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Return(4), 5, values);
6731cb0ef41Sopenharmony_ci  schedule()->AddReturn(CurrentBlock(), ret);
6741cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6751cb0ef41Sopenharmony_ci}
6761cb0ef41Sopenharmony_ci
6771cb0ef41Sopenharmony_civoid RawMachineAssembler::AbortCSADcheck(Node* message) {
6781cb0ef41Sopenharmony_ci  AddNode(machine()->AbortCSADcheck(), message);
6791cb0ef41Sopenharmony_ci}
6801cb0ef41Sopenharmony_ci
6811cb0ef41Sopenharmony_civoid RawMachineAssembler::DebugBreak() { AddNode(machine()->DebugBreak()); }
6821cb0ef41Sopenharmony_ci
6831cb0ef41Sopenharmony_civoid RawMachineAssembler::Unreachable() {
6841cb0ef41Sopenharmony_ci  Node* ret = MakeNode(common()->Throw(), 0, nullptr);
6851cb0ef41Sopenharmony_ci  schedule()->AddThrow(CurrentBlock(), ret);
6861cb0ef41Sopenharmony_ci  current_block_ = nullptr;
6871cb0ef41Sopenharmony_ci}
6881cb0ef41Sopenharmony_ci
6891cb0ef41Sopenharmony_civoid RawMachineAssembler::Comment(const std::string& msg) {
6901cb0ef41Sopenharmony_ci  size_t length = msg.length() + 1;
6911cb0ef41Sopenharmony_ci  char* zone_buffer = zone()->NewArray<char>(length);
6921cb0ef41Sopenharmony_ci  MemCopy(zone_buffer, msg.c_str(), length);
6931cb0ef41Sopenharmony_ci  AddNode(machine()->Comment(zone_buffer));
6941cb0ef41Sopenharmony_ci}
6951cb0ef41Sopenharmony_ci
6961cb0ef41Sopenharmony_civoid RawMachineAssembler::StaticAssert(Node* value, const char* source) {
6971cb0ef41Sopenharmony_ci  AddNode(common()->StaticAssert(source), value);
6981cb0ef41Sopenharmony_ci}
6991cb0ef41Sopenharmony_ci
7001cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CallN(CallDescriptor* call_descriptor,
7011cb0ef41Sopenharmony_ci                                 int input_count, Node* const* inputs) {
7021cb0ef41Sopenharmony_ci  DCHECK(!call_descriptor->NeedsFrameState());
7031cb0ef41Sopenharmony_ci  // +1 is for target.
7041cb0ef41Sopenharmony_ci  DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 1);
7051cb0ef41Sopenharmony_ci  return AddNode(common()->Call(call_descriptor), input_count, inputs);
7061cb0ef41Sopenharmony_ci}
7071cb0ef41Sopenharmony_ci
7081cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CallNWithFrameState(CallDescriptor* call_descriptor,
7091cb0ef41Sopenharmony_ci                                               int input_count,
7101cb0ef41Sopenharmony_ci                                               Node* const* inputs) {
7111cb0ef41Sopenharmony_ci  DCHECK(call_descriptor->NeedsFrameState());
7121cb0ef41Sopenharmony_ci  // +2 is for target and frame state.
7131cb0ef41Sopenharmony_ci  DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 2);
7141cb0ef41Sopenharmony_ci  return AddNode(common()->Call(call_descriptor), input_count, inputs);
7151cb0ef41Sopenharmony_ci}
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_civoid RawMachineAssembler::TailCallN(CallDescriptor* call_descriptor,
7181cb0ef41Sopenharmony_ci                                    int input_count, Node* const* inputs) {
7191cb0ef41Sopenharmony_ci  // +1 is for target.
7201cb0ef41Sopenharmony_ci  DCHECK_EQ(input_count, call_descriptor->ParameterCount() + 1);
7211cb0ef41Sopenharmony_ci  Node* tail_call =
7221cb0ef41Sopenharmony_ci      MakeNode(common()->TailCall(call_descriptor), input_count, inputs);
7231cb0ef41Sopenharmony_ci  schedule()->AddTailCall(CurrentBlock(), tail_call);
7241cb0ef41Sopenharmony_ci  current_block_ = nullptr;
7251cb0ef41Sopenharmony_ci}
7261cb0ef41Sopenharmony_ci
7271cb0ef41Sopenharmony_cinamespace {
7281cb0ef41Sopenharmony_ci
7291cb0ef41Sopenharmony_cienum FunctionDescriptorMode { kHasFunctionDescriptor, kNoFunctionDescriptor };
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ciNode* CallCFunctionImpl(
7321cb0ef41Sopenharmony_ci    RawMachineAssembler* rasm, Node* function,
7331cb0ef41Sopenharmony_ci    base::Optional<MachineType> return_type,
7341cb0ef41Sopenharmony_ci    std::initializer_list<RawMachineAssembler::CFunctionArg> args,
7351cb0ef41Sopenharmony_ci    bool caller_saved_regs, SaveFPRegsMode mode,
7361cb0ef41Sopenharmony_ci    FunctionDescriptorMode no_function_descriptor) {
7371cb0ef41Sopenharmony_ci  static constexpr std::size_t kNumCArgs = 10;
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci  MachineSignature::Builder builder(rasm->zone(), return_type ? 1 : 0,
7401cb0ef41Sopenharmony_ci                                    args.size());
7411cb0ef41Sopenharmony_ci  if (return_type) {
7421cb0ef41Sopenharmony_ci    builder.AddReturn(*return_type);
7431cb0ef41Sopenharmony_ci  }
7441cb0ef41Sopenharmony_ci  for (const auto& arg : args) builder.AddParam(arg.first);
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci  bool caller_saved_fp_regs =
7471cb0ef41Sopenharmony_ci      caller_saved_regs && (mode == SaveFPRegsMode::kSave);
7481cb0ef41Sopenharmony_ci  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
7491cb0ef41Sopenharmony_ci  if (caller_saved_regs) flags |= CallDescriptor::kCallerSavedRegisters;
7501cb0ef41Sopenharmony_ci  if (caller_saved_fp_regs) flags |= CallDescriptor::kCallerSavedFPRegisters;
7511cb0ef41Sopenharmony_ci  if (no_function_descriptor) flags |= CallDescriptor::kNoFunctionDescriptor;
7521cb0ef41Sopenharmony_ci  auto call_descriptor =
7531cb0ef41Sopenharmony_ci      Linkage::GetSimplifiedCDescriptor(rasm->zone(), builder.Build(), flags);
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci  base::SmallVector<Node*, kNumCArgs> nodes(args.size() + 1);
7561cb0ef41Sopenharmony_ci  nodes[0] = function;
7571cb0ef41Sopenharmony_ci  std::transform(
7581cb0ef41Sopenharmony_ci      args.begin(), args.end(), std::next(nodes.begin()),
7591cb0ef41Sopenharmony_ci      [](const RawMachineAssembler::CFunctionArg& arg) { return arg.second; });
7601cb0ef41Sopenharmony_ci
7611cb0ef41Sopenharmony_ci  auto common = rasm->common();
7621cb0ef41Sopenharmony_ci  return rasm->AddNode(common->Call(call_descriptor),
7631cb0ef41Sopenharmony_ci                       static_cast<int>(nodes.size()), nodes.begin());
7641cb0ef41Sopenharmony_ci}
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci}  // namespace
7671cb0ef41Sopenharmony_ci
7681cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CallCFunction(
7691cb0ef41Sopenharmony_ci    Node* function, base::Optional<MachineType> return_type,
7701cb0ef41Sopenharmony_ci    std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
7711cb0ef41Sopenharmony_ci  return CallCFunctionImpl(this, function, return_type, args, false,
7721cb0ef41Sopenharmony_ci                           SaveFPRegsMode::kIgnore, kHasFunctionDescriptor);
7731cb0ef41Sopenharmony_ci}
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CallCFunctionWithoutFunctionDescriptor(
7761cb0ef41Sopenharmony_ci    Node* function, MachineType return_type,
7771cb0ef41Sopenharmony_ci    std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
7781cb0ef41Sopenharmony_ci  return CallCFunctionImpl(this, function, return_type, args, false,
7791cb0ef41Sopenharmony_ci                           SaveFPRegsMode::kIgnore, kNoFunctionDescriptor);
7801cb0ef41Sopenharmony_ci}
7811cb0ef41Sopenharmony_ci
7821cb0ef41Sopenharmony_ciNode* RawMachineAssembler::CallCFunctionWithCallerSavedRegisters(
7831cb0ef41Sopenharmony_ci    Node* function, MachineType return_type, SaveFPRegsMode mode,
7841cb0ef41Sopenharmony_ci    std::initializer_list<RawMachineAssembler::CFunctionArg> args) {
7851cb0ef41Sopenharmony_ci  return CallCFunctionImpl(this, function, return_type, args, true, mode,
7861cb0ef41Sopenharmony_ci                           kHasFunctionDescriptor);
7871cb0ef41Sopenharmony_ci}
7881cb0ef41Sopenharmony_ci
7891cb0ef41Sopenharmony_ciBasicBlock* RawMachineAssembler::Use(RawMachineLabel* label) {
7901cb0ef41Sopenharmony_ci  label->used_ = true;
7911cb0ef41Sopenharmony_ci  return EnsureBlock(label);
7921cb0ef41Sopenharmony_ci}
7931cb0ef41Sopenharmony_ci
7941cb0ef41Sopenharmony_ciBasicBlock* RawMachineAssembler::EnsureBlock(RawMachineLabel* label) {
7951cb0ef41Sopenharmony_ci  if (label->block_ == nullptr) {
7961cb0ef41Sopenharmony_ci    label->block_ = schedule()->NewBasicBlock();
7971cb0ef41Sopenharmony_ci  }
7981cb0ef41Sopenharmony_ci  return label->block_;
7991cb0ef41Sopenharmony_ci}
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_civoid RawMachineAssembler::Bind(RawMachineLabel* label) {
8021cb0ef41Sopenharmony_ci  DCHECK_NULL(current_block_);
8031cb0ef41Sopenharmony_ci  DCHECK(!label->bound_);
8041cb0ef41Sopenharmony_ci  label->bound_ = true;
8051cb0ef41Sopenharmony_ci  current_block_ = EnsureBlock(label);
8061cb0ef41Sopenharmony_ci  current_block_->set_deferred(label->deferred_);
8071cb0ef41Sopenharmony_ci}
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci#if DEBUG
8101cb0ef41Sopenharmony_civoid RawMachineAssembler::Bind(RawMachineLabel* label,
8111cb0ef41Sopenharmony_ci                               AssemblerDebugInfo info) {
8121cb0ef41Sopenharmony_ci  if (current_block_ != nullptr) {
8131cb0ef41Sopenharmony_ci    std::stringstream str;
8141cb0ef41Sopenharmony_ci    str << "Binding label without closing previous block:"
8151cb0ef41Sopenharmony_ci        << "\n#    label:          " << info
8161cb0ef41Sopenharmony_ci        << "\n#    previous block: " << *current_block_;
8171cb0ef41Sopenharmony_ci    FATAL("%s", str.str().c_str());
8181cb0ef41Sopenharmony_ci  }
8191cb0ef41Sopenharmony_ci  Bind(label);
8201cb0ef41Sopenharmony_ci  current_block_->set_debug_info(info);
8211cb0ef41Sopenharmony_ci}
8221cb0ef41Sopenharmony_ci
8231cb0ef41Sopenharmony_civoid RawMachineAssembler::PrintCurrentBlock(std::ostream& os) {
8241cb0ef41Sopenharmony_ci  os << CurrentBlock();
8251cb0ef41Sopenharmony_ci}
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_civoid RawMachineAssembler::SetInitialDebugInformation(
8281cb0ef41Sopenharmony_ci    AssemblerDebugInfo debug_info) {
8291cb0ef41Sopenharmony_ci  CurrentBlock()->set_debug_info(debug_info);
8301cb0ef41Sopenharmony_ci}
8311cb0ef41Sopenharmony_ci#endif  // DEBUG
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_cibool RawMachineAssembler::InsideBlock() { return current_block_ != nullptr; }
8341cb0ef41Sopenharmony_ci
8351cb0ef41Sopenharmony_ciBasicBlock* RawMachineAssembler::CurrentBlock() {
8361cb0ef41Sopenharmony_ci  DCHECK(current_block_);
8371cb0ef41Sopenharmony_ci  return current_block_;
8381cb0ef41Sopenharmony_ci}
8391cb0ef41Sopenharmony_ci
8401cb0ef41Sopenharmony_ciNode* RawMachineAssembler::Phi(MachineRepresentation rep, int input_count,
8411cb0ef41Sopenharmony_ci                               Node* const* inputs) {
8421cb0ef41Sopenharmony_ci  Node** buffer = zone()->NewArray<Node*>(input_count + 1);
8431cb0ef41Sopenharmony_ci  std::copy(inputs, inputs + input_count, buffer);
8441cb0ef41Sopenharmony_ci  buffer[input_count] = graph()->start();
8451cb0ef41Sopenharmony_ci  return AddNode(common()->Phi(rep, input_count), input_count + 1, buffer);
8461cb0ef41Sopenharmony_ci}
8471cb0ef41Sopenharmony_ci
8481cb0ef41Sopenharmony_civoid RawMachineAssembler::AppendPhiInput(Node* phi, Node* new_input) {
8491cb0ef41Sopenharmony_ci  const Operator* op = phi->op();
8501cb0ef41Sopenharmony_ci  const Operator* new_op = common()->ResizeMergeOrPhi(op, phi->InputCount());
8511cb0ef41Sopenharmony_ci  phi->InsertInput(zone(), phi->InputCount() - 1, new_input);
8521cb0ef41Sopenharmony_ci  NodeProperties::ChangeOp(phi, new_op);
8531cb0ef41Sopenharmony_ci}
8541cb0ef41Sopenharmony_ci
8551cb0ef41Sopenharmony_ciNode* RawMachineAssembler::AddNode(const Operator* op, int input_count,
8561cb0ef41Sopenharmony_ci                                   Node* const* inputs) {
8571cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(schedule_);
8581cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(current_block_);
8591cb0ef41Sopenharmony_ci  Node* node = MakeNode(op, input_count, inputs);
8601cb0ef41Sopenharmony_ci  schedule()->AddNode(CurrentBlock(), node);
8611cb0ef41Sopenharmony_ci  return node;
8621cb0ef41Sopenharmony_ci}
8631cb0ef41Sopenharmony_ci
8641cb0ef41Sopenharmony_ciNode* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
8651cb0ef41Sopenharmony_ci                                    Node* const* inputs) {
8661cb0ef41Sopenharmony_ci  // The raw machine assembler nodes do not have effect and control inputs,
8671cb0ef41Sopenharmony_ci  // so we disable checking input counts here.
8681cb0ef41Sopenharmony_ci  return graph()->NewNodeUnchecked(op, input_count, inputs);
8691cb0ef41Sopenharmony_ci}
8701cb0ef41Sopenharmony_ci
8711cb0ef41Sopenharmony_ciRawMachineLabel::~RawMachineLabel() {
8721cb0ef41Sopenharmony_ci#if DEBUG
8731cb0ef41Sopenharmony_ci  if (bound_ == used_) return;
8741cb0ef41Sopenharmony_ci  std::stringstream str;
8751cb0ef41Sopenharmony_ci  if (bound_) {
8761cb0ef41Sopenharmony_ci    str << "A label has been bound but it's not used."
8771cb0ef41Sopenharmony_ci        << "\n#    label: " << *block_;
8781cb0ef41Sopenharmony_ci  } else {
8791cb0ef41Sopenharmony_ci    str << "A label has been used but it's not bound.";
8801cb0ef41Sopenharmony_ci  }
8811cb0ef41Sopenharmony_ci  FATAL("%s", str.str().c_str());
8821cb0ef41Sopenharmony_ci#endif  // DEBUG
8831cb0ef41Sopenharmony_ci}
8841cb0ef41Sopenharmony_ci
8851cb0ef41Sopenharmony_ci}  // namespace compiler
8861cb0ef41Sopenharmony_ci}  // namespace internal
8871cb0ef41Sopenharmony_ci}  // namespace v8
888