11cb0ef41Sopenharmony_ci// Copyright 2020 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/cc-generator.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/common/globals.h"
81cb0ef41Sopenharmony_ci#include "src/torque/global-context.h"
91cb0ef41Sopenharmony_ci#include "src/torque/type-oracle.h"
101cb0ef41Sopenharmony_ci#include "src/torque/types.h"
111cb0ef41Sopenharmony_ci#include "src/torque/utils.h"
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace v8 {
141cb0ef41Sopenharmony_cinamespace internal {
151cb0ef41Sopenharmony_cinamespace torque {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cibase::Optional<Stack<std::string>> CCGenerator::EmitGraph(
181cb0ef41Sopenharmony_ci    Stack<std::string> parameters) {
191cb0ef41Sopenharmony_ci  for (BottomOffset i = {0}; i < parameters.AboveTop(); ++i) {
201cb0ef41Sopenharmony_ci    SetDefinitionVariable(DefinitionLocation::Parameter(i.offset),
211cb0ef41Sopenharmony_ci                          parameters.Peek(i));
221cb0ef41Sopenharmony_ci  }
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  // Redirect the output of non-declarations into a buffer and only output
251cb0ef41Sopenharmony_ci  // declarations right away.
261cb0ef41Sopenharmony_ci  std::stringstream out_buffer;
271cb0ef41Sopenharmony_ci  std::ostream* old_out = out_;
281cb0ef41Sopenharmony_ci  out_ = &out_buffer;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  EmitInstruction(GotoInstruction{cfg_.start()}, &parameters);
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  for (Block* block : cfg_.blocks()) {
331cb0ef41Sopenharmony_ci    if (cfg_.end() && *cfg_.end() == block) continue;
341cb0ef41Sopenharmony_ci    if (block->IsDead()) continue;
351cb0ef41Sopenharmony_ci    EmitBlock(block);
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  base::Optional<Stack<std::string>> result;
391cb0ef41Sopenharmony_ci  if (cfg_.end()) {
401cb0ef41Sopenharmony_ci    result = EmitBlock(*cfg_.end());
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  // All declarations have been printed now, so we can append the buffered
441cb0ef41Sopenharmony_ci  // output and redirect back to the original output stream.
451cb0ef41Sopenharmony_ci  out_ = old_out;
461cb0ef41Sopenharmony_ci  out() << out_buffer.str();
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  return result;
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciStack<std::string> CCGenerator::EmitBlock(const Block* block) {
521cb0ef41Sopenharmony_ci  out() << "\n";
531cb0ef41Sopenharmony_ci  out() << "  " << BlockName(block) << ":\n";
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  Stack<std::string> stack;
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  for (BottomOffset i = {0}; i < block->InputTypes().AboveTop(); ++i) {
581cb0ef41Sopenharmony_ci    const auto& def = block->InputDefinitions().Peek(i);
591cb0ef41Sopenharmony_ci    stack.Push(DefinitionToVariable(def));
601cb0ef41Sopenharmony_ci    if (def.IsPhiFromBlock(block)) {
611cb0ef41Sopenharmony_ci      decls() << "  "
621cb0ef41Sopenharmony_ci              << (is_cc_debug_ ? block->InputTypes().Peek(i)->GetDebugType()
631cb0ef41Sopenharmony_ci                               : block->InputTypes().Peek(i)->GetRuntimeType())
641cb0ef41Sopenharmony_ci              << " " << stack.Top() << "{}; USE(" << stack.Top() << ");\n";
651cb0ef41Sopenharmony_ci    }
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  for (const Instruction& instruction : block->instructions()) {
691cb0ef41Sopenharmony_ci    TorqueCodeGenerator::EmitInstruction(instruction, &stack);
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci  return stack;
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_civoid CCGenerator::EmitSourcePosition(SourcePosition pos, bool always_emit) {
751cb0ef41Sopenharmony_ci  const std::string& file = SourceFileMap::AbsolutePath(pos.source);
761cb0ef41Sopenharmony_ci  if (always_emit || !previous_position_.CompareStartIgnoreColumn(pos)) {
771cb0ef41Sopenharmony_ci    // Lines in Torque SourcePositions are zero-based, while the
781cb0ef41Sopenharmony_ci    // CodeStubAssembler and downwind systems are one-based.
791cb0ef41Sopenharmony_ci    out() << "  // " << file << ":" << (pos.start.line + 1) << "\n";
801cb0ef41Sopenharmony_ci    previous_position_ = pos;
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci}
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
851cb0ef41Sopenharmony_ci    const PushUninitializedInstruction& instruction,
861cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
871cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: PushUninitialized");
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
911cb0ef41Sopenharmony_ci    const PushBuiltinPointerInstruction& instruction,
921cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
931cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: PushBuiltinPointer");
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
971cb0ef41Sopenharmony_ci    const NamespaceConstantInstruction& instruction,
981cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
991cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: NamespaceConstantInstruction");
1001cb0ef41Sopenharmony_ci}
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_cistd::vector<std::string> CCGenerator::ProcessArgumentsCommon(
1031cb0ef41Sopenharmony_ci    const TypeVector& parameter_types,
1041cb0ef41Sopenharmony_ci    std::vector<std::string> constexpr_arguments, Stack<std::string>* stack) {
1051cb0ef41Sopenharmony_ci  std::vector<std::string> args;
1061cb0ef41Sopenharmony_ci  for (auto it = parameter_types.rbegin(); it != parameter_types.rend(); ++it) {
1071cb0ef41Sopenharmony_ci    const Type* type = *it;
1081cb0ef41Sopenharmony_ci    if (type->IsConstexpr()) {
1091cb0ef41Sopenharmony_ci      args.push_back(std::move(constexpr_arguments.back()));
1101cb0ef41Sopenharmony_ci      constexpr_arguments.pop_back();
1111cb0ef41Sopenharmony_ci    } else {
1121cb0ef41Sopenharmony_ci      std::stringstream s;
1131cb0ef41Sopenharmony_ci      size_t slot_count = LoweredSlotCount(type);
1141cb0ef41Sopenharmony_ci      VisitResult arg = VisitResult(type, stack->TopRange(slot_count));
1151cb0ef41Sopenharmony_ci      EmitCCValue(arg, *stack, s);
1161cb0ef41Sopenharmony_ci      args.push_back(s.str());
1171cb0ef41Sopenharmony_ci      stack->PopMany(slot_count);
1181cb0ef41Sopenharmony_ci    }
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci  std::reverse(args.begin(), args.end());
1211cb0ef41Sopenharmony_ci  return args;
1221cb0ef41Sopenharmony_ci}
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
1251cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
1261cb0ef41Sopenharmony_ci  TypeVector parameter_types =
1271cb0ef41Sopenharmony_ci      instruction.intrinsic->signature().parameter_types.types;
1281cb0ef41Sopenharmony_ci  std::vector<std::string> args = ProcessArgumentsCommon(
1291cb0ef41Sopenharmony_ci      parameter_types, instruction.constexpr_arguments, stack);
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  Stack<std::string> pre_call_stack = *stack;
1321cb0ef41Sopenharmony_ci  const Type* return_type = instruction.intrinsic->signature().return_type;
1331cb0ef41Sopenharmony_ci  std::vector<std::string> results;
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  const auto lowered = LowerType(return_type);
1361cb0ef41Sopenharmony_ci  for (std::size_t i = 0; i < lowered.size(); ++i) {
1371cb0ef41Sopenharmony_ci    results.push_back(DefinitionToVariable(instruction.GetValueDefinition(i)));
1381cb0ef41Sopenharmony_ci    stack->Push(results.back());
1391cb0ef41Sopenharmony_ci    decls() << "  "
1401cb0ef41Sopenharmony_ci            << (is_cc_debug_ ? lowered[i]->GetDebugType()
1411cb0ef41Sopenharmony_ci                             : lowered[i]->GetRuntimeType())
1421cb0ef41Sopenharmony_ci            << " " << stack->Top() << "{}; USE(" << stack->Top() << ");\n";
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  out() << "  ";
1461cb0ef41Sopenharmony_ci  if (return_type->StructSupertype()) {
1471cb0ef41Sopenharmony_ci    out() << "std::tie(";
1481cb0ef41Sopenharmony_ci    PrintCommaSeparatedList(out(), results);
1491cb0ef41Sopenharmony_ci    out() << ") = ";
1501cb0ef41Sopenharmony_ci  } else {
1511cb0ef41Sopenharmony_ci    if (results.size() == 1) {
1521cb0ef41Sopenharmony_ci      out() << results[0] << " = ";
1531cb0ef41Sopenharmony_ci    }
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  if (instruction.intrinsic->ExternalName() == "%RawDownCast") {
1571cb0ef41Sopenharmony_ci    if (parameter_types.size() != 1) {
1581cb0ef41Sopenharmony_ci      ReportError("%RawDownCast must take a single parameter");
1591cb0ef41Sopenharmony_ci    }
1601cb0ef41Sopenharmony_ci    const Type* original_type = parameter_types[0];
1611cb0ef41Sopenharmony_ci    bool is_subtype =
1621cb0ef41Sopenharmony_ci        return_type->IsSubtypeOf(original_type) ||
1631cb0ef41Sopenharmony_ci        (original_type == TypeOracle::GetUninitializedHeapObjectType() &&
1641cb0ef41Sopenharmony_ci         return_type->IsSubtypeOf(TypeOracle::GetHeapObjectType()));
1651cb0ef41Sopenharmony_ci    if (!is_subtype) {
1661cb0ef41Sopenharmony_ci      ReportError("%RawDownCast error: ", *return_type, " is not a subtype of ",
1671cb0ef41Sopenharmony_ci                  *original_type);
1681cb0ef41Sopenharmony_ci    }
1691cb0ef41Sopenharmony_ci    if (!original_type->StructSupertype() &&
1701cb0ef41Sopenharmony_ci        return_type->GetRuntimeType() != original_type->GetRuntimeType()) {
1711cb0ef41Sopenharmony_ci      out() << "static_cast<" << return_type->GetRuntimeType() << ">";
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci  } else if (instruction.intrinsic->ExternalName() == "%GetClassMapConstant") {
1741cb0ef41Sopenharmony_ci    ReportError("C++ generator doesn't yet support %GetClassMapConstant");
1751cb0ef41Sopenharmony_ci  } else if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
1761cb0ef41Sopenharmony_ci    if (parameter_types.size() != 1 || !parameter_types[0]->IsConstexpr()) {
1771cb0ef41Sopenharmony_ci      ReportError(
1781cb0ef41Sopenharmony_ci          "%FromConstexpr must take a single parameter with constexpr "
1791cb0ef41Sopenharmony_ci          "type");
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci    if (return_type->IsConstexpr()) {
1821cb0ef41Sopenharmony_ci      ReportError("%FromConstexpr must return a non-constexpr type");
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci    if (return_type->IsSubtypeOf(TypeOracle::GetSmiType())) {
1851cb0ef41Sopenharmony_ci      if (is_cc_debug_) {
1861cb0ef41Sopenharmony_ci        out() << "Internals::IntToSmi";
1871cb0ef41Sopenharmony_ci      } else {
1881cb0ef41Sopenharmony_ci        out() << "Smi::FromInt";
1891cb0ef41Sopenharmony_ci      }
1901cb0ef41Sopenharmony_ci    }
1911cb0ef41Sopenharmony_ci    // Wrap the raw constexpr value in a static_cast to ensure that
1921cb0ef41Sopenharmony_ci    // enums get properly casted to their backing integral value.
1931cb0ef41Sopenharmony_ci    out() << "(CastToUnderlyingTypeIfEnum";
1941cb0ef41Sopenharmony_ci  } else {
1951cb0ef41Sopenharmony_ci    ReportError("no built in intrinsic with name " +
1961cb0ef41Sopenharmony_ci                instruction.intrinsic->ExternalName());
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  out() << "(";
2001cb0ef41Sopenharmony_ci  PrintCommaSeparatedList(out(), args);
2011cb0ef41Sopenharmony_ci  if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
2021cb0ef41Sopenharmony_ci    out() << ")";
2031cb0ef41Sopenharmony_ci  }
2041cb0ef41Sopenharmony_ci  out() << ");\n";
2051cb0ef41Sopenharmony_ci}
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
2081cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2091cb0ef41Sopenharmony_ci  TypeVector parameter_types =
2101cb0ef41Sopenharmony_ci      instruction.macro->signature().parameter_types.types;
2111cb0ef41Sopenharmony_ci  std::vector<std::string> args = ProcessArgumentsCommon(
2121cb0ef41Sopenharmony_ci      parameter_types, instruction.constexpr_arguments, stack);
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  Stack<std::string> pre_call_stack = *stack;
2151cb0ef41Sopenharmony_ci  const Type* return_type = instruction.macro->signature().return_type;
2161cb0ef41Sopenharmony_ci  std::vector<std::string> results;
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci  const auto lowered = LowerType(return_type);
2191cb0ef41Sopenharmony_ci  for (std::size_t i = 0; i < lowered.size(); ++i) {
2201cb0ef41Sopenharmony_ci    results.push_back(DefinitionToVariable(instruction.GetValueDefinition(i)));
2211cb0ef41Sopenharmony_ci    stack->Push(results.back());
2221cb0ef41Sopenharmony_ci    decls() << "  "
2231cb0ef41Sopenharmony_ci            << (is_cc_debug_ ? lowered[i]->GetDebugType()
2241cb0ef41Sopenharmony_ci                             : lowered[i]->GetRuntimeType())
2251cb0ef41Sopenharmony_ci            << " " << stack->Top() << "{}; USE(" << stack->Top() << ");\n";
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  // We should have inlined any calls requiring complex control flow.
2291cb0ef41Sopenharmony_ci  CHECK(!instruction.catch_block);
2301cb0ef41Sopenharmony_ci  out() << (is_cc_debug_ ? "  ASSIGN_OR_RETURN(" : "  ");
2311cb0ef41Sopenharmony_ci  if (return_type->StructSupertype().has_value()) {
2321cb0ef41Sopenharmony_ci    out() << "std::tie(";
2331cb0ef41Sopenharmony_ci    PrintCommaSeparatedList(out(), results);
2341cb0ef41Sopenharmony_ci    out() << (is_cc_debug_ ? "), " : ") = ");
2351cb0ef41Sopenharmony_ci  } else {
2361cb0ef41Sopenharmony_ci    if (results.size() == 1) {
2371cb0ef41Sopenharmony_ci      out() << results[0] << (is_cc_debug_ ? ", " : " = ");
2381cb0ef41Sopenharmony_ci    } else {
2391cb0ef41Sopenharmony_ci      DCHECK_EQ(0, results.size());
2401cb0ef41Sopenharmony_ci    }
2411cb0ef41Sopenharmony_ci  }
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci  if (is_cc_debug_) {
2441cb0ef41Sopenharmony_ci    out() << instruction.macro->CCDebugName() << "(accessor";
2451cb0ef41Sopenharmony_ci    if (!args.empty()) out() << ", ";
2461cb0ef41Sopenharmony_ci  } else {
2471cb0ef41Sopenharmony_ci    out() << instruction.macro->CCName() << "(";
2481cb0ef41Sopenharmony_ci  }
2491cb0ef41Sopenharmony_ci  PrintCommaSeparatedList(out(), args);
2501cb0ef41Sopenharmony_ci  if (is_cc_debug_) {
2511cb0ef41Sopenharmony_ci    out() << "));\n";
2521cb0ef41Sopenharmony_ci  } else {
2531cb0ef41Sopenharmony_ci    out() << ");\n";
2541cb0ef41Sopenharmony_ci  }
2551cb0ef41Sopenharmony_ci}
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
2581cb0ef41Sopenharmony_ci    const CallCsaMacroAndBranchInstruction& instruction,
2591cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
2601cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: CallCsaMacroAndBranch");
2611cb0ef41Sopenharmony_ci}
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const MakeLazyNodeInstruction& instruction,
2641cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2651cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: MakeLazyNode");
2661cb0ef41Sopenharmony_ci}
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const CallBuiltinInstruction& instruction,
2691cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2701cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: CallBuiltin");
2711cb0ef41Sopenharmony_ci}
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
2741cb0ef41Sopenharmony_ci    const CallBuiltinPointerInstruction& instruction,
2751cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
2761cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: CallBuiltinPointer");
2771cb0ef41Sopenharmony_ci}
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
2801cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2811cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: CallRuntime");
2821cb0ef41Sopenharmony_ci}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const BranchInstruction& instruction,
2851cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2861cb0ef41Sopenharmony_ci  out() << "  if (" << stack->Pop() << ") {\n";
2871cb0ef41Sopenharmony_ci  EmitGoto(instruction.if_true, stack, "    ");
2881cb0ef41Sopenharmony_ci  out() << "  } else {\n";
2891cb0ef41Sopenharmony_ci  EmitGoto(instruction.if_false, stack, "    ");
2901cb0ef41Sopenharmony_ci  out() << "  }\n";
2911cb0ef41Sopenharmony_ci}
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const ConstexprBranchInstruction& instruction,
2941cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
2951cb0ef41Sopenharmony_ci  out() << "  if ((" << instruction.condition << ")) {\n";
2961cb0ef41Sopenharmony_ci  EmitGoto(instruction.if_true, stack, "    ");
2971cb0ef41Sopenharmony_ci  out() << "  } else {\n";
2981cb0ef41Sopenharmony_ci  EmitGoto(instruction.if_false, stack, "    ");
2991cb0ef41Sopenharmony_ci  out() << "  }\n";
3001cb0ef41Sopenharmony_ci}
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_civoid CCGenerator::EmitGoto(const Block* destination, Stack<std::string>* stack,
3031cb0ef41Sopenharmony_ci                           std::string indentation) {
3041cb0ef41Sopenharmony_ci  const auto& destination_definitions = destination->InputDefinitions();
3051cb0ef41Sopenharmony_ci  DCHECK_EQ(stack->Size(), destination_definitions.Size());
3061cb0ef41Sopenharmony_ci  for (BottomOffset i = {0}; i < stack->AboveTop(); ++i) {
3071cb0ef41Sopenharmony_ci    DefinitionLocation def = destination_definitions.Peek(i);
3081cb0ef41Sopenharmony_ci    if (def.IsPhiFromBlock(destination)) {
3091cb0ef41Sopenharmony_ci      out() << indentation << DefinitionToVariable(def) << " = "
3101cb0ef41Sopenharmony_ci            << stack->Peek(i) << ";\n";
3111cb0ef41Sopenharmony_ci    }
3121cb0ef41Sopenharmony_ci  }
3131cb0ef41Sopenharmony_ci  out() << indentation << "goto " << BlockName(destination) << ";\n";
3141cb0ef41Sopenharmony_ci}
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const GotoInstruction& instruction,
3171cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3181cb0ef41Sopenharmony_ci  EmitGoto(instruction.destination, stack, "  ");
3191cb0ef41Sopenharmony_ci}
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const GotoExternalInstruction& instruction,
3221cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3231cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: GotoExternal");
3241cb0ef41Sopenharmony_ci}
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const ReturnInstruction& instruction,
3271cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3281cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: Return");
3291cb0ef41Sopenharmony_ci}
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(
3321cb0ef41Sopenharmony_ci    const PrintConstantStringInstruction& instruction,
3331cb0ef41Sopenharmony_ci    Stack<std::string>* stack) {
3341cb0ef41Sopenharmony_ci  out() << "  std::cout << " << StringLiteralQuote(instruction.message)
3351cb0ef41Sopenharmony_ci        << ";\n";
3361cb0ef41Sopenharmony_ci}
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const AbortInstruction& instruction,
3391cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3401cb0ef41Sopenharmony_ci  switch (instruction.kind) {
3411cb0ef41Sopenharmony_ci    case AbortInstruction::Kind::kUnreachable:
3421cb0ef41Sopenharmony_ci      DCHECK(instruction.message.empty());
3431cb0ef41Sopenharmony_ci      out() << "  UNREACHABLE();\n";
3441cb0ef41Sopenharmony_ci      break;
3451cb0ef41Sopenharmony_ci    case AbortInstruction::Kind::kDebugBreak:
3461cb0ef41Sopenharmony_ci      DCHECK(instruction.message.empty());
3471cb0ef41Sopenharmony_ci      out() << "  base::OS::DebugBreak();\n";
3481cb0ef41Sopenharmony_ci      break;
3491cb0ef41Sopenharmony_ci    case AbortInstruction::Kind::kAssertionFailure: {
3501cb0ef41Sopenharmony_ci      std::string file = StringLiteralQuote(
3511cb0ef41Sopenharmony_ci          SourceFileMap::PathFromV8Root(instruction.pos.source));
3521cb0ef41Sopenharmony_ci      out() << "  CHECK(false, \"Failed Torque assertion: '\""
3531cb0ef41Sopenharmony_ci            << StringLiteralQuote(instruction.message) << "\"' at \"" << file
3541cb0ef41Sopenharmony_ci            << "\":\""
3551cb0ef41Sopenharmony_ci            << StringLiteralQuote(
3561cb0ef41Sopenharmony_ci                   std::to_string(instruction.pos.start.line + 1))
3571cb0ef41Sopenharmony_ci            << ");\n";
3581cb0ef41Sopenharmony_ci      break;
3591cb0ef41Sopenharmony_ci    }
3601cb0ef41Sopenharmony_ci  }
3611cb0ef41Sopenharmony_ci}
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const UnsafeCastInstruction& instruction,
3641cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3651cb0ef41Sopenharmony_ci  const std::string str = "static_cast<" +
3661cb0ef41Sopenharmony_ci                          instruction.destination_type->GetRuntimeType() +
3671cb0ef41Sopenharmony_ci                          ">(" + stack->Top() + ")";
3681cb0ef41Sopenharmony_ci  stack->Poke(stack->AboveTop() - 1, str);
3691cb0ef41Sopenharmony_ci  SetDefinitionVariable(instruction.GetValueDefinition(), str);
3701cb0ef41Sopenharmony_ci}
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const LoadReferenceInstruction& instruction,
3731cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
3741cb0ef41Sopenharmony_ci  std::string result_name =
3751cb0ef41Sopenharmony_ci      DefinitionToVariable(instruction.GetValueDefinition());
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci  std::string offset = stack->Pop();
3781cb0ef41Sopenharmony_ci  std::string object = stack->Pop();
3791cb0ef41Sopenharmony_ci  stack->Push(result_name);
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  if (!is_cc_debug_) {
3821cb0ef41Sopenharmony_ci    std::string result_type = instruction.type->GetRuntimeType();
3831cb0ef41Sopenharmony_ci    decls() << "  " << result_type << " " << result_name << "{}; USE("
3841cb0ef41Sopenharmony_ci            << result_name << ");\n";
3851cb0ef41Sopenharmony_ci    out() << "  " << result_name << " = ";
3861cb0ef41Sopenharmony_ci    if (instruction.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
3871cb0ef41Sopenharmony_ci      // Currently, all of the tagged loads we emit are for smi values, so there
3881cb0ef41Sopenharmony_ci      // is no point in providing an PtrComprCageBase. If at some point we start
3891cb0ef41Sopenharmony_ci      // emitting loads for tagged fields which might be HeapObjects, then we
3901cb0ef41Sopenharmony_ci      // should plumb an PtrComprCageBase through the generated functions that
3911cb0ef41Sopenharmony_ci      // need it.
3921cb0ef41Sopenharmony_ci      if (!instruction.type->IsSubtypeOf(TypeOracle::GetSmiType())) {
3931cb0ef41Sopenharmony_ci        Error(
3941cb0ef41Sopenharmony_ci            "Not supported in C++ output: LoadReference on non-smi tagged "
3951cb0ef41Sopenharmony_ci            "value");
3961cb0ef41Sopenharmony_ci      }
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci      // References and slices can cause some values to have the Torque type
3991cb0ef41Sopenharmony_ci      // HeapObject|TaggedZeroPattern, which is output as "Object". TaggedField
4001cb0ef41Sopenharmony_ci      // requires HeapObject, so we need a cast.
4011cb0ef41Sopenharmony_ci      out() << "TaggedField<" << result_type
4021cb0ef41Sopenharmony_ci            << ">::load(*static_cast<HeapObject*>(&" << object
4031cb0ef41Sopenharmony_ci            << "), static_cast<int>(" << offset << "));\n";
4041cb0ef41Sopenharmony_ci    } else {
4051cb0ef41Sopenharmony_ci      out() << "(" << object << ").ReadField<" << result_type << ">(" << offset
4061cb0ef41Sopenharmony_ci            << ");\n";
4071cb0ef41Sopenharmony_ci    }
4081cb0ef41Sopenharmony_ci  } else {
4091cb0ef41Sopenharmony_ci    std::string result_type = instruction.type->GetDebugType();
4101cb0ef41Sopenharmony_ci    decls() << "  " << result_type << " " << result_name << "{}; USE("
4111cb0ef41Sopenharmony_ci            << result_name << ");\n";
4121cb0ef41Sopenharmony_ci    if (instruction.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
4131cb0ef41Sopenharmony_ci      out() << "  READ_TAGGED_FIELD_OR_FAIL(" << result_name << ", accessor, "
4141cb0ef41Sopenharmony_ci            << object << ", static_cast<int>(" << offset << "));\n";
4151cb0ef41Sopenharmony_ci    } else {
4161cb0ef41Sopenharmony_ci      out() << "  READ_FIELD_OR_FAIL(" << result_type << ", " << result_name
4171cb0ef41Sopenharmony_ci            << ", accessor, " << object << ", " << offset << ");\n";
4181cb0ef41Sopenharmony_ci    }
4191cb0ef41Sopenharmony_ci  }
4201cb0ef41Sopenharmony_ci}
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const StoreReferenceInstruction& instruction,
4231cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
4241cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: StoreReference");
4251cb0ef41Sopenharmony_ci}
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_cinamespace {
4281cb0ef41Sopenharmony_cistd::string GetBitFieldSpecialization(const Type* container,
4291cb0ef41Sopenharmony_ci                                      const BitField& field) {
4301cb0ef41Sopenharmony_ci  std::stringstream stream;
4311cb0ef41Sopenharmony_ci  stream << "base::BitField<"
4321cb0ef41Sopenharmony_ci         << field.name_and_type.type->GetConstexprGeneratedTypeName() << ", "
4331cb0ef41Sopenharmony_ci         << field.offset << ", " << field.num_bits << ", "
4341cb0ef41Sopenharmony_ci         << container->GetConstexprGeneratedTypeName() << ">";
4351cb0ef41Sopenharmony_ci  return stream.str();
4361cb0ef41Sopenharmony_ci}
4371cb0ef41Sopenharmony_ci}  // namespace
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const LoadBitFieldInstruction& instruction,
4401cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
4411cb0ef41Sopenharmony_ci  std::string result_name =
4421cb0ef41Sopenharmony_ci      DefinitionToVariable(instruction.GetValueDefinition());
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci  std::string bit_field_struct = stack->Pop();
4451cb0ef41Sopenharmony_ci  stack->Push(result_name);
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci  const Type* struct_type = instruction.bit_field_struct_type;
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  decls() << "  " << instruction.bit_field.name_and_type.type->GetRuntimeType()
4501cb0ef41Sopenharmony_ci          << " " << result_name << "{}; USE(" << result_name << ");\n";
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_ci  base::Optional<const Type*> smi_tagged_type =
4531cb0ef41Sopenharmony_ci      Type::MatchUnaryGeneric(struct_type, TypeOracle::GetSmiTaggedGeneric());
4541cb0ef41Sopenharmony_ci  if (smi_tagged_type) {
4551cb0ef41Sopenharmony_ci    // Get the untagged value and its type.
4561cb0ef41Sopenharmony_ci    if (is_cc_debug_) {
4571cb0ef41Sopenharmony_ci      bit_field_struct = "Internals::SmiValue(" + bit_field_struct + ")";
4581cb0ef41Sopenharmony_ci    } else {
4591cb0ef41Sopenharmony_ci      bit_field_struct = bit_field_struct + ".value()";
4601cb0ef41Sopenharmony_ci    }
4611cb0ef41Sopenharmony_ci    struct_type = *smi_tagged_type;
4621cb0ef41Sopenharmony_ci  }
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  out() << "  " << result_name << " = CastToUnderlyingTypeIfEnum("
4651cb0ef41Sopenharmony_ci        << GetBitFieldSpecialization(struct_type, instruction.bit_field)
4661cb0ef41Sopenharmony_ci        << "::decode(" << bit_field_struct << "));\n";
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_civoid CCGenerator::EmitInstruction(const StoreBitFieldInstruction& instruction,
4701cb0ef41Sopenharmony_ci                                  Stack<std::string>* stack) {
4711cb0ef41Sopenharmony_ci  ReportError("Not supported in C++ output: StoreBitField");
4721cb0ef41Sopenharmony_ci}
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_cinamespace {
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_civoid CollectAllFields(const VisitResult& result,
4771cb0ef41Sopenharmony_ci                      const Stack<std::string>& values,
4781cb0ef41Sopenharmony_ci                      std::vector<std::string>& all_fields) {
4791cb0ef41Sopenharmony_ci  if (!result.IsOnStack()) {
4801cb0ef41Sopenharmony_ci    all_fields.push_back(result.constexpr_value());
4811cb0ef41Sopenharmony_ci  } else if (auto struct_type = result.type()->StructSupertype()) {
4821cb0ef41Sopenharmony_ci    for (const Field& field : (*struct_type)->fields()) {
4831cb0ef41Sopenharmony_ci      CollectAllFields(ProjectStructField(result, field.name_and_type.name),
4841cb0ef41Sopenharmony_ci                       values, all_fields);
4851cb0ef41Sopenharmony_ci    }
4861cb0ef41Sopenharmony_ci  } else {
4871cb0ef41Sopenharmony_ci    DCHECK_EQ(1, result.stack_range().Size());
4881cb0ef41Sopenharmony_ci    all_fields.push_back(values.Peek(result.stack_range().begin()));
4891cb0ef41Sopenharmony_ci  }
4901cb0ef41Sopenharmony_ci}
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci}  // namespace
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci// static
4951cb0ef41Sopenharmony_civoid CCGenerator::EmitCCValue(VisitResult result,
4961cb0ef41Sopenharmony_ci                              const Stack<std::string>& values,
4971cb0ef41Sopenharmony_ci                              std::ostream& out) {
4981cb0ef41Sopenharmony_ci  std::vector<std::string> all_fields;
4991cb0ef41Sopenharmony_ci  CollectAllFields(result, values, all_fields);
5001cb0ef41Sopenharmony_ci  if (all_fields.size() == 1) {
5011cb0ef41Sopenharmony_ci    out << all_fields[0];
5021cb0ef41Sopenharmony_ci  } else {
5031cb0ef41Sopenharmony_ci    out << "std::make_tuple(";
5041cb0ef41Sopenharmony_ci    PrintCommaSeparatedList(out, all_fields);
5051cb0ef41Sopenharmony_ci    out << ")";
5061cb0ef41Sopenharmony_ci  }
5071cb0ef41Sopenharmony_ci}
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci}  // namespace torque
5101cb0ef41Sopenharmony_ci}  // namespace internal
5111cb0ef41Sopenharmony_ci}  // namespace v8
512