11cb0ef41Sopenharmony_ci// Copyright 2018 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/torque/cfg.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/torque/type-oracle.h"
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_cinamespace v8 {
101cb0ef41Sopenharmony_cinamespace internal {
111cb0ef41Sopenharmony_cinamespace torque {
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_civoid Block::SetInputTypes(const Stack<const Type*>& input_types) {
141cb0ef41Sopenharmony_ci  if (!input_types_) {
151cb0ef41Sopenharmony_ci    input_types_ = input_types;
161cb0ef41Sopenharmony_ci    return;
171cb0ef41Sopenharmony_ci  } else if (*input_types_ == input_types) {
181cb0ef41Sopenharmony_ci    return;
191cb0ef41Sopenharmony_ci  }
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci  DCHECK_EQ(input_types.Size(), input_types_->Size());
221cb0ef41Sopenharmony_ci  Stack<const Type*> merged_types;
231cb0ef41Sopenharmony_ci  bool widened = false;
241cb0ef41Sopenharmony_ci  auto c2_iterator = input_types.begin();
251cb0ef41Sopenharmony_ci  for (const Type* c1 : *input_types_) {
261cb0ef41Sopenharmony_ci    const Type* merged_type = TypeOracle::GetUnionType(c1, *c2_iterator++);
271cb0ef41Sopenharmony_ci    if (!merged_type->IsSubtypeOf(c1)) {
281cb0ef41Sopenharmony_ci      widened = true;
291cb0ef41Sopenharmony_ci    }
301cb0ef41Sopenharmony_ci    merged_types.Push(merged_type);
311cb0ef41Sopenharmony_ci  }
321cb0ef41Sopenharmony_ci  if (merged_types.Size() == input_types_->Size()) {
331cb0ef41Sopenharmony_ci    if (widened) {
341cb0ef41Sopenharmony_ci      input_types_ = merged_types;
351cb0ef41Sopenharmony_ci      Retype();
361cb0ef41Sopenharmony_ci    }
371cb0ef41Sopenharmony_ci    return;
381cb0ef41Sopenharmony_ci  }
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  std::stringstream error;
411cb0ef41Sopenharmony_ci  error << "incompatible types at branch:\n";
421cb0ef41Sopenharmony_ci  for (intptr_t i = std::max(input_types_->Size(), input_types.Size()) - 1;
431cb0ef41Sopenharmony_ci       i >= 0; --i) {
441cb0ef41Sopenharmony_ci    base::Optional<const Type*> left;
451cb0ef41Sopenharmony_ci    base::Optional<const Type*> right;
461cb0ef41Sopenharmony_ci    if (static_cast<size_t>(i) < input_types.Size()) {
471cb0ef41Sopenharmony_ci      left = input_types.Peek(BottomOffset{static_cast<size_t>(i)});
481cb0ef41Sopenharmony_ci    }
491cb0ef41Sopenharmony_ci    if (static_cast<size_t>(i) < input_types_->Size()) {
501cb0ef41Sopenharmony_ci      right = input_types_->Peek(BottomOffset{static_cast<size_t>(i)});
511cb0ef41Sopenharmony_ci    }
521cb0ef41Sopenharmony_ci    if (left && right && *left == *right) {
531cb0ef41Sopenharmony_ci      error << **left << "\n";
541cb0ef41Sopenharmony_ci    } else {
551cb0ef41Sopenharmony_ci      if (left) {
561cb0ef41Sopenharmony_ci        error << **left;
571cb0ef41Sopenharmony_ci      } else {
581cb0ef41Sopenharmony_ci        error << "/*missing*/";
591cb0ef41Sopenharmony_ci      }
601cb0ef41Sopenharmony_ci      error << "   =>   ";
611cb0ef41Sopenharmony_ci      if (right) {
621cb0ef41Sopenharmony_ci        error << **right;
631cb0ef41Sopenharmony_ci      } else {
641cb0ef41Sopenharmony_ci        error << "/*missing*/";
651cb0ef41Sopenharmony_ci      }
661cb0ef41Sopenharmony_ci      error << "\n";
671cb0ef41Sopenharmony_ci    }
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci  ReportError(error.str());
701cb0ef41Sopenharmony_ci}
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_civoid CfgAssembler::Bind(Block* block) {
731cb0ef41Sopenharmony_ci  DCHECK(current_block_->IsComplete());
741cb0ef41Sopenharmony_ci  DCHECK(block->instructions().empty());
751cb0ef41Sopenharmony_ci  DCHECK(block->HasInputTypes());
761cb0ef41Sopenharmony_ci  current_block_ = block;
771cb0ef41Sopenharmony_ci  current_stack_ = block->InputTypes();
781cb0ef41Sopenharmony_ci  cfg_.PlaceBlock(block);
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_civoid CfgAssembler::Goto(Block* block) {
821cb0ef41Sopenharmony_ci  if (block->HasInputTypes()) {
831cb0ef41Sopenharmony_ci    DropTo(block->InputTypes().AboveTop());
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci  Emit(GotoInstruction{block});
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciStackRange CfgAssembler::Goto(Block* block, size_t preserved_slots) {
891cb0ef41Sopenharmony_ci  DCHECK(block->HasInputTypes());
901cb0ef41Sopenharmony_ci  DCHECK_GE(CurrentStack().Size(), block->InputTypes().Size());
911cb0ef41Sopenharmony_ci  Emit(DeleteRangeInstruction{
921cb0ef41Sopenharmony_ci      StackRange{block->InputTypes().AboveTop() - preserved_slots,
931cb0ef41Sopenharmony_ci                 CurrentStack().AboveTop() - preserved_slots}});
941cb0ef41Sopenharmony_ci  StackRange preserved_slot_range = TopRange(preserved_slots);
951cb0ef41Sopenharmony_ci  Emit(GotoInstruction{block});
961cb0ef41Sopenharmony_ci  return preserved_slot_range;
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_civoid CfgAssembler::Branch(Block* if_true, Block* if_false) {
1001cb0ef41Sopenharmony_ci  Emit(BranchInstruction{if_true, if_false});
1011cb0ef41Sopenharmony_ci}
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci// Delete the specified range of slots, moving upper slots to fill the gap.
1041cb0ef41Sopenharmony_civoid CfgAssembler::DeleteRange(StackRange range) {
1051cb0ef41Sopenharmony_ci  DCHECK_LE(range.end(), current_stack_.AboveTop());
1061cb0ef41Sopenharmony_ci  if (range.Size() == 0) return;
1071cb0ef41Sopenharmony_ci  Emit(DeleteRangeInstruction{range});
1081cb0ef41Sopenharmony_ci}
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_civoid CfgAssembler::DropTo(BottomOffset new_level) {
1111cb0ef41Sopenharmony_ci  DeleteRange(StackRange{new_level, CurrentStack().AboveTop()});
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ciStackRange CfgAssembler::Peek(StackRange range,
1151cb0ef41Sopenharmony_ci                              base::Optional<const Type*> type) {
1161cb0ef41Sopenharmony_ci  std::vector<const Type*> lowered_types;
1171cb0ef41Sopenharmony_ci  if (type) {
1181cb0ef41Sopenharmony_ci    lowered_types = LowerType(*type);
1191cb0ef41Sopenharmony_ci    DCHECK_EQ(lowered_types.size(), range.Size());
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci  for (size_t i = 0; i < range.Size(); ++i) {
1221cb0ef41Sopenharmony_ci    Emit(PeekInstruction{
1231cb0ef41Sopenharmony_ci        range.begin() + i,
1241cb0ef41Sopenharmony_ci        type ? lowered_types[i] : base::Optional<const Type*>{}});
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci  return TopRange(range.Size());
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_civoid CfgAssembler::Poke(StackRange destination, StackRange origin,
1301cb0ef41Sopenharmony_ci                        base::Optional<const Type*> type) {
1311cb0ef41Sopenharmony_ci  DCHECK_EQ(destination.Size(), origin.Size());
1321cb0ef41Sopenharmony_ci  DCHECK_LE(destination.end(), origin.begin());
1331cb0ef41Sopenharmony_ci  DCHECK_EQ(origin.end(), CurrentStack().AboveTop());
1341cb0ef41Sopenharmony_ci  std::vector<const Type*> lowered_types;
1351cb0ef41Sopenharmony_ci  if (type) {
1361cb0ef41Sopenharmony_ci    lowered_types = LowerType(*type);
1371cb0ef41Sopenharmony_ci    DCHECK_EQ(lowered_types.size(), origin.Size());
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci  for (intptr_t i = origin.Size() - 1; i >= 0; --i) {
1401cb0ef41Sopenharmony_ci    Emit(PokeInstruction{
1411cb0ef41Sopenharmony_ci        destination.begin() + i,
1421cb0ef41Sopenharmony_ci        type ? lowered_types[i] : base::Optional<const Type*>{}});
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_civoid CfgAssembler::Print(std::string s) {
1471cb0ef41Sopenharmony_ci  Emit(PrintConstantStringInstruction{std::move(s)});
1481cb0ef41Sopenharmony_ci}
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_civoid CfgAssembler::AssertionFailure(std::string message) {
1511cb0ef41Sopenharmony_ci  Emit(AbortInstruction{AbortInstruction::Kind::kAssertionFailure,
1521cb0ef41Sopenharmony_ci                        std::move(message)});
1531cb0ef41Sopenharmony_ci}
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_civoid CfgAssembler::Unreachable() {
1561cb0ef41Sopenharmony_ci  Emit(AbortInstruction{AbortInstruction::Kind::kUnreachable});
1571cb0ef41Sopenharmony_ci}
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_civoid CfgAssembler::DebugBreak() {
1601cb0ef41Sopenharmony_ci  Emit(AbortInstruction{AbortInstruction::Kind::kDebugBreak});
1611cb0ef41Sopenharmony_ci}
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_cistd::vector<std::size_t> CountBlockPredecessors(const ControlFlowGraph& cfg) {
1641cb0ef41Sopenharmony_ci  std::vector<std::size_t> count(cfg.NumberOfBlockIds(), 0);
1651cb0ef41Sopenharmony_ci  count[cfg.start()->id()] = 1;
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  for (const Block* block : cfg.blocks()) {
1681cb0ef41Sopenharmony_ci    std::vector<Block*> successors;
1691cb0ef41Sopenharmony_ci    for (const auto& instruction : block->instructions()) {
1701cb0ef41Sopenharmony_ci      instruction->AppendSuccessorBlocks(&successors);
1711cb0ef41Sopenharmony_ci    }
1721cb0ef41Sopenharmony_ci    for (Block* successor : successors) {
1731cb0ef41Sopenharmony_ci      DCHECK_LT(successor->id(), count.size());
1741cb0ef41Sopenharmony_ci      ++count[successor->id()];
1751cb0ef41Sopenharmony_ci    }
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  return count;
1791cb0ef41Sopenharmony_ci}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_civoid CfgAssembler::OptimizeCfg() {
1821cb0ef41Sopenharmony_ci  auto predecessor_count = CountBlockPredecessors(cfg_);
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  for (Block* block : cfg_.blocks()) {
1851cb0ef41Sopenharmony_ci    if (cfg_.end() && *cfg_.end() == block) continue;
1861cb0ef41Sopenharmony_ci    if (predecessor_count[block->id()] == 0) continue;
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci    while (!block->instructions().empty()) {
1891cb0ef41Sopenharmony_ci      const auto& instruction = block->instructions().back();
1901cb0ef41Sopenharmony_ci      if (!instruction.Is<GotoInstruction>()) break;
1911cb0ef41Sopenharmony_ci      Block* destination = instruction.Cast<GotoInstruction>().destination;
1921cb0ef41Sopenharmony_ci      if (destination == block) break;
1931cb0ef41Sopenharmony_ci      if (cfg_.end() && *cfg_.end() == destination) break;
1941cb0ef41Sopenharmony_ci      DCHECK_GT(predecessor_count[destination->id()], 0);
1951cb0ef41Sopenharmony_ci      if (predecessor_count[destination->id()] != 1) break;
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci      DCHECK_GT(destination->instructions().size(), 0);
1981cb0ef41Sopenharmony_ci      block->instructions().pop_back();
1991cb0ef41Sopenharmony_ci      block->instructions().insert(block->instructions().end(),
2001cb0ef41Sopenharmony_ci                                   destination->instructions().begin(),
2011cb0ef41Sopenharmony_ci                                   destination->instructions().end());
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci      --predecessor_count[destination->id()];
2041cb0ef41Sopenharmony_ci      DCHECK_EQ(predecessor_count[destination->id()], 0);
2051cb0ef41Sopenharmony_ci    }
2061cb0ef41Sopenharmony_ci  }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  cfg_.UnplaceBlockIf(
2091cb0ef41Sopenharmony_ci      [&](Block* b) { return predecessor_count[b->id()] == 0; });
2101cb0ef41Sopenharmony_ci}
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_civoid CfgAssembler::ComputeInputDefinitions() {
2131cb0ef41Sopenharmony_ci  Worklist<Block*> worklist;
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  // Setup start block.
2161cb0ef41Sopenharmony_ci  Stack<DefinitionLocation> parameter_defs;
2171cb0ef41Sopenharmony_ci  for (std::size_t i = 0; i < cfg_.ParameterCount(); ++i) {
2181cb0ef41Sopenharmony_ci    parameter_defs.Push(DefinitionLocation::Parameter(i));
2191cb0ef41Sopenharmony_ci  }
2201cb0ef41Sopenharmony_ci  cfg_.start()->MergeInputDefinitions(parameter_defs, &worklist);
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  // Run fixpoint algorithm.
2231cb0ef41Sopenharmony_ci  while (!worklist.IsEmpty()) {
2241cb0ef41Sopenharmony_ci    Block* block = worklist.Dequeue();
2251cb0ef41Sopenharmony_ci    Stack<DefinitionLocation> definitions = block->InputDefinitions();
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci    // Propagate through block's instructions.
2281cb0ef41Sopenharmony_ci    for (const auto& instruction : block->instructions()) {
2291cb0ef41Sopenharmony_ci      instruction.RecomputeDefinitionLocations(&definitions, &worklist);
2301cb0ef41Sopenharmony_ci    }
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  for (Block* block : cfg_.blocks()) {
2341cb0ef41Sopenharmony_ci    DCHECK_IMPLIES(!block->IsDead(), block->InputDefinitions().Size() ==
2351cb0ef41Sopenharmony_ci                                         block->InputTypes().Size());
2361cb0ef41Sopenharmony_ci    USE(block);
2371cb0ef41Sopenharmony_ci  }
2381cb0ef41Sopenharmony_ci}
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci}  // namespace torque
2411cb0ef41Sopenharmony_ci}  // namespace internal
2421cb0ef41Sopenharmony_ci}  // namespace v8
243