11cb0ef41Sopenharmony_ci// Copyright (c) 1994-2006 Sun Microsystems Inc.
21cb0ef41Sopenharmony_ci// All Rights Reserved.
31cb0ef41Sopenharmony_ci//
41cb0ef41Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
51cb0ef41Sopenharmony_ci// modification, are permitted provided that the following conditions
61cb0ef41Sopenharmony_ci// are met:
71cb0ef41Sopenharmony_ci//
81cb0ef41Sopenharmony_ci// - Redistributions of source code must retain the above copyright notice,
91cb0ef41Sopenharmony_ci// this list of conditions and the following disclaimer.
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// - Redistribution in binary form must reproduce the above copyright
121cb0ef41Sopenharmony_ci// notice, this list of conditions and the following disclaimer in the
131cb0ef41Sopenharmony_ci// documentation and/or other materials provided with the
141cb0ef41Sopenharmony_ci// distribution.
151cb0ef41Sopenharmony_ci//
161cb0ef41Sopenharmony_ci// - Neither the name of Sun Microsystems or the names of contributors may
171cb0ef41Sopenharmony_ci// be used to endorse or promote products derived from this software without
181cb0ef41Sopenharmony_ci// specific prior written permission.
191cb0ef41Sopenharmony_ci//
201cb0ef41Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
211cb0ef41Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
221cb0ef41Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
231cb0ef41Sopenharmony_ci// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
241cb0ef41Sopenharmony_ci// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
251cb0ef41Sopenharmony_ci// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
261cb0ef41Sopenharmony_ci// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
271cb0ef41Sopenharmony_ci// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281cb0ef41Sopenharmony_ci// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
291cb0ef41Sopenharmony_ci// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
301cb0ef41Sopenharmony_ci// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
311cb0ef41Sopenharmony_ci// OF THE POSSIBILITY OF SUCH DAMAGE.
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci// The original source code covered by the above license above has been
341cb0ef41Sopenharmony_ci// modified significantly by Google Inc.
351cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci#include "src/codegen/s390/assembler-s390.h"
381cb0ef41Sopenharmony_ci#include <set>
391cb0ef41Sopenharmony_ci#include <string>
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_S390
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_S390
441cb0ef41Sopenharmony_ci#include <elf.h>  // Required for auxv checks for STFLE support
451cb0ef41Sopenharmony_ci#include <sys/auxv.h>
461cb0ef41Sopenharmony_ci#endif
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci#include "src/base/bits.h"
491cb0ef41Sopenharmony_ci#include "src/base/cpu.h"
501cb0ef41Sopenharmony_ci#include "src/codegen/macro-assembler.h"
511cb0ef41Sopenharmony_ci#include "src/codegen/s390/assembler-s390-inl.h"
521cb0ef41Sopenharmony_ci#include "src/codegen/string-constants.h"
531cb0ef41Sopenharmony_ci#include "src/deoptimizer/deoptimizer.h"
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cinamespace v8 {
561cb0ef41Sopenharmony_cinamespace internal {
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci// Get the CPU features enabled by the build.
591cb0ef41Sopenharmony_cistatic unsigned CpuFeaturesImpliedByCompiler() {
601cb0ef41Sopenharmony_ci  unsigned answer = 0;
611cb0ef41Sopenharmony_ci  return answer;
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cistatic bool supportsCPUFeature(const char* feature) {
651cb0ef41Sopenharmony_ci  static std::set<std::string>& features = *new std::set<std::string>();
661cb0ef41Sopenharmony_ci  static std::set<std::string>& all_available_features =
671cb0ef41Sopenharmony_ci      *new std::set<std::string>({"iesan3", "zarch", "stfle", "msa", "ldisp",
681cb0ef41Sopenharmony_ci                                  "eimm", "dfp", "etf3eh", "highgprs", "te",
691cb0ef41Sopenharmony_ci                                  "vx"});
701cb0ef41Sopenharmony_ci  if (features.empty()) {
711cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_S390
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci#ifndef HWCAP_S390_VX
741cb0ef41Sopenharmony_ci#define HWCAP_S390_VX 2048
751cb0ef41Sopenharmony_ci#endif
761cb0ef41Sopenharmony_ci#define CHECK_AVAILABILITY_FOR(mask, value) \
771cb0ef41Sopenharmony_ci  if (f & mask) features.insert(value);
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    // initialize feature vector
801cb0ef41Sopenharmony_ci    uint64_t f = getauxval(AT_HWCAP);
811cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_ESAN3, "iesan3")
821cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_ZARCH, "zarch")
831cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_STFLE, "stfle")
841cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_MSA, "msa")
851cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_LDISP, "ldisp")
861cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_EIMM, "eimm")
871cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_DFP, "dfp")
881cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_ETF3EH, "etf3eh")
891cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_HIGH_GPRS, "highgprs")
901cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_TE, "te")
911cb0ef41Sopenharmony_ci    CHECK_AVAILABILITY_FOR(HWCAP_S390_VX, "vx")
921cb0ef41Sopenharmony_ci#else
931cb0ef41Sopenharmony_ci    // import all features
941cb0ef41Sopenharmony_ci    features.insert(all_available_features.begin(),
951cb0ef41Sopenharmony_ci                    all_available_features.end());
961cb0ef41Sopenharmony_ci#endif
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci  USE(all_available_features);
991cb0ef41Sopenharmony_ci  return features.find(feature) != features.end();
1001cb0ef41Sopenharmony_ci}
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci#undef CHECK_AVAILABILITY_FOR
1031cb0ef41Sopenharmony_ci#undef HWCAP_S390_VX
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci// Check whether Store Facility STFLE instruction is available on the platform.
1061cb0ef41Sopenharmony_ci// Instruction returns a bit vector of the enabled hardware facilities.
1071cb0ef41Sopenharmony_cistatic bool supportsSTFLE() {
1081cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_S390
1091cb0ef41Sopenharmony_ci  static bool read_tried = false;
1101cb0ef41Sopenharmony_ci  static uint32_t auxv_hwcap = 0;
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  if (!read_tried) {
1131cb0ef41Sopenharmony_ci    // Open the AUXV (auxiliary vector) pseudo-file
1141cb0ef41Sopenharmony_ci    int fd = open("/proc/self/auxv", O_RDONLY);
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci    read_tried = true;
1171cb0ef41Sopenharmony_ci    if (fd != -1) {
1181cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_S390X
1191cb0ef41Sopenharmony_ci      static Elf64_auxv_t buffer[16];
1201cb0ef41Sopenharmony_ci      Elf64_auxv_t* auxv_element;
1211cb0ef41Sopenharmony_ci#else
1221cb0ef41Sopenharmony_ci      static Elf32_auxv_t buffer[16];
1231cb0ef41Sopenharmony_ci      Elf32_auxv_t* auxv_element;
1241cb0ef41Sopenharmony_ci#endif
1251cb0ef41Sopenharmony_ci      int bytes_read = 0;
1261cb0ef41Sopenharmony_ci      while (bytes_read >= 0) {
1271cb0ef41Sopenharmony_ci        // Read a chunk of the AUXV
1281cb0ef41Sopenharmony_ci        bytes_read = read(fd, buffer, sizeof(buffer));
1291cb0ef41Sopenharmony_ci        // Locate and read the platform field of AUXV if it is in the chunk
1301cb0ef41Sopenharmony_ci        for (auxv_element = buffer;
1311cb0ef41Sopenharmony_ci             auxv_element + sizeof(auxv_element) <= buffer + bytes_read &&
1321cb0ef41Sopenharmony_ci             auxv_element->a_type != AT_NULL;
1331cb0ef41Sopenharmony_ci             auxv_element++) {
1341cb0ef41Sopenharmony_ci          // We are looking for HWCAP entry in AUXV to search for STFLE support
1351cb0ef41Sopenharmony_ci          if (auxv_element->a_type == AT_HWCAP) {
1361cb0ef41Sopenharmony_ci            /* Note: Both auxv_hwcap and buffer are static */
1371cb0ef41Sopenharmony_ci            auxv_hwcap = auxv_element->a_un.a_val;
1381cb0ef41Sopenharmony_ci            goto done_reading;
1391cb0ef41Sopenharmony_ci          }
1401cb0ef41Sopenharmony_ci        }
1411cb0ef41Sopenharmony_ci      }
1421cb0ef41Sopenharmony_ci    done_reading:
1431cb0ef41Sopenharmony_ci      close(fd);
1441cb0ef41Sopenharmony_ci    }
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  // Did not find result
1481cb0ef41Sopenharmony_ci  if (0 == auxv_hwcap) {
1491cb0ef41Sopenharmony_ci    return false;
1501cb0ef41Sopenharmony_ci  }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  // HWCAP_S390_STFLE is defined to be 4 in include/asm/elf.h.  Currently
1531cb0ef41Sopenharmony_ci  // hardcoded in case that include file does not exist.
1541cb0ef41Sopenharmony_ci  const uint32_t _HWCAP_S390_STFLE = 4;
1551cb0ef41Sopenharmony_ci  return (auxv_hwcap & _HWCAP_S390_STFLE);
1561cb0ef41Sopenharmony_ci#else
1571cb0ef41Sopenharmony_ci  // STFLE is not available on non-s390 hosts
1581cb0ef41Sopenharmony_ci  return false;
1591cb0ef41Sopenharmony_ci#endif
1601cb0ef41Sopenharmony_ci}
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_cibool CpuFeatures::SupportsWasmSimd128() {
1631cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
1641cb0ef41Sopenharmony_ci  return CpuFeatures::IsSupported(VECTOR_ENHANCE_FACILITY_1);
1651cb0ef41Sopenharmony_ci#else
1661cb0ef41Sopenharmony_ci  return false;
1671cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_civoid CpuFeatures::ProbeImpl(bool cross_compile) {
1711cb0ef41Sopenharmony_ci  supported_ |= CpuFeaturesImpliedByCompiler();
1721cb0ef41Sopenharmony_ci  icache_line_size_ = 256;
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  // Only use statically determined features for cross compile (snapshot).
1751cb0ef41Sopenharmony_ci  if (cross_compile) return;
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci#ifdef DEBUG
1781cb0ef41Sopenharmony_ci  initialized_ = true;
1791cb0ef41Sopenharmony_ci#endif
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  static bool performSTFLE = supportsSTFLE();
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci// Need to define host, as we are generating inlined S390 assembly to test
1841cb0ef41Sopenharmony_ci// for facilities.
1851cb0ef41Sopenharmony_ci#if V8_HOST_ARCH_S390
1861cb0ef41Sopenharmony_ci  if (performSTFLE) {
1871cb0ef41Sopenharmony_ci    // STFLE D(B) requires:
1881cb0ef41Sopenharmony_ci    //    GPR0 to specify # of double words to update minus 1.
1891cb0ef41Sopenharmony_ci    //      i.e. GPR0 = 0 for 1 doubleword
1901cb0ef41Sopenharmony_ci    //    D(B) to specify to memory location to store the facilities bits
1911cb0ef41Sopenharmony_ci    // The facilities we are checking for are:
1921cb0ef41Sopenharmony_ci    //   Bit 45 - Distinct Operands for instructions like ARK, SRK, etc.
1931cb0ef41Sopenharmony_ci    // As such, we require only 1 double word
1941cb0ef41Sopenharmony_ci    int64_t facilities[3] = {0L};
1951cb0ef41Sopenharmony_ci    int16_t reg0;
1961cb0ef41Sopenharmony_ci    // LHI sets up GPR0
1971cb0ef41Sopenharmony_ci    // STFLE is specified as .insn, as opcode is not recognized.
1981cb0ef41Sopenharmony_ci    // We register the instructions kill r0 (LHI) and the CC (STFLE).
1991cb0ef41Sopenharmony_ci    asm volatile(
2001cb0ef41Sopenharmony_ci        "lhi   %%r0,2\n"
2011cb0ef41Sopenharmony_ci        ".insn s,0xb2b00000,%0\n"
2021cb0ef41Sopenharmony_ci        : "=Q"(facilities), "=r"(reg0)
2031cb0ef41Sopenharmony_ci        :
2041cb0ef41Sopenharmony_ci        : "cc", "r0");
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    uint64_t one = static_cast<uint64_t>(1);
2071cb0ef41Sopenharmony_ci    // Test for Distinct Operands Facility - Bit 45
2081cb0ef41Sopenharmony_ci    if (facilities[0] & (one << (63 - 45))) {
2091cb0ef41Sopenharmony_ci      supported_ |= (1u << DISTINCT_OPS);
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci    // Test for General Instruction Extension Facility - Bit 34
2121cb0ef41Sopenharmony_ci    if (facilities[0] & (one << (63 - 34))) {
2131cb0ef41Sopenharmony_ci      supported_ |= (1u << GENERAL_INSTR_EXT);
2141cb0ef41Sopenharmony_ci    }
2151cb0ef41Sopenharmony_ci    // Test for Floating Point Extension Facility - Bit 37
2161cb0ef41Sopenharmony_ci    if (facilities[0] & (one << (63 - 37))) {
2171cb0ef41Sopenharmony_ci      supported_ |= (1u << FLOATING_POINT_EXT);
2181cb0ef41Sopenharmony_ci    }
2191cb0ef41Sopenharmony_ci    // Test for Vector Facility - Bit 129
2201cb0ef41Sopenharmony_ci    if (facilities[2] & (one << (63 - (129 - 128))) &&
2211cb0ef41Sopenharmony_ci        supportsCPUFeature("vx")) {
2221cb0ef41Sopenharmony_ci      supported_ |= (1u << VECTOR_FACILITY);
2231cb0ef41Sopenharmony_ci    }
2241cb0ef41Sopenharmony_ci    // Test for Vector Enhancement Facility 1 - Bit 135
2251cb0ef41Sopenharmony_ci    if (facilities[2] & (one << (63 - (135 - 128))) &&
2261cb0ef41Sopenharmony_ci        supportsCPUFeature("vx")) {
2271cb0ef41Sopenharmony_ci      supported_ |= (1u << VECTOR_ENHANCE_FACILITY_1);
2281cb0ef41Sopenharmony_ci    }
2291cb0ef41Sopenharmony_ci    // Test for Vector Enhancement Facility 2 - Bit 148
2301cb0ef41Sopenharmony_ci    if (facilities[2] & (one << (63 - (148 - 128))) &&
2311cb0ef41Sopenharmony_ci        supportsCPUFeature("vx")) {
2321cb0ef41Sopenharmony_ci      supported_ |= (1u << VECTOR_ENHANCE_FACILITY_2);
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci    // Test for Miscellaneous Instruction Extension Facility - Bit 58
2351cb0ef41Sopenharmony_ci    if (facilities[0] & (1lu << (63 - 58))) {
2361cb0ef41Sopenharmony_ci      supported_ |= (1u << MISC_INSTR_EXT2);
2371cb0ef41Sopenharmony_ci    }
2381cb0ef41Sopenharmony_ci  }
2391cb0ef41Sopenharmony_ci#else
2401cb0ef41Sopenharmony_ci  // All distinct ops instructions can be simulated
2411cb0ef41Sopenharmony_ci  supported_ |= (1u << DISTINCT_OPS);
2421cb0ef41Sopenharmony_ci  // RISBG can be simulated
2431cb0ef41Sopenharmony_ci  supported_ |= (1u << GENERAL_INSTR_EXT);
2441cb0ef41Sopenharmony_ci  supported_ |= (1u << FLOATING_POINT_EXT);
2451cb0ef41Sopenharmony_ci  supported_ |= (1u << MISC_INSTR_EXT2);
2461cb0ef41Sopenharmony_ci  USE(performSTFLE);  // To avoid assert
2471cb0ef41Sopenharmony_ci  USE(supportsCPUFeature);
2481cb0ef41Sopenharmony_ci  supported_ |= (1u << VECTOR_FACILITY);
2491cb0ef41Sopenharmony_ci  supported_ |= (1u << VECTOR_ENHANCE_FACILITY_1);
2501cb0ef41Sopenharmony_ci  supported_ |= (1u << VECTOR_ENHANCE_FACILITY_2);
2511cb0ef41Sopenharmony_ci#endif
2521cb0ef41Sopenharmony_ci  supported_ |= (1u << FPU);
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci  // Set a static value on whether Simd is supported.
2551cb0ef41Sopenharmony_ci  // This variable is only used for certain archs to query SupportWasmSimd128()
2561cb0ef41Sopenharmony_ci  // at runtime in builtins using an extern ref. Other callers should use
2571cb0ef41Sopenharmony_ci  // CpuFeatures::SupportWasmSimd128().
2581cb0ef41Sopenharmony_ci  CpuFeatures::supports_wasm_simd_128_ = CpuFeatures::SupportsWasmSimd128();
2591cb0ef41Sopenharmony_ci}
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_civoid CpuFeatures::PrintTarget() {
2621cb0ef41Sopenharmony_ci  const char* s390_arch = nullptr;
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_S390X
2651cb0ef41Sopenharmony_ci  s390_arch = "s390x";
2661cb0ef41Sopenharmony_ci#else
2671cb0ef41Sopenharmony_ci  s390_arch = "s390";
2681cb0ef41Sopenharmony_ci#endif
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  PrintF("target %s\n", s390_arch);
2711cb0ef41Sopenharmony_ci}
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_civoid CpuFeatures::PrintFeatures() {
2741cb0ef41Sopenharmony_ci  PrintF("FPU=%d\n", CpuFeatures::IsSupported(FPU));
2751cb0ef41Sopenharmony_ci  PrintF("FPU_EXT=%d\n", CpuFeatures::IsSupported(FLOATING_POINT_EXT));
2761cb0ef41Sopenharmony_ci  PrintF("GENERAL_INSTR=%d\n", CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
2771cb0ef41Sopenharmony_ci  PrintF("DISTINCT_OPS=%d\n", CpuFeatures::IsSupported(DISTINCT_OPS));
2781cb0ef41Sopenharmony_ci  PrintF("VECTOR_FACILITY=%d\n", CpuFeatures::IsSupported(VECTOR_FACILITY));
2791cb0ef41Sopenharmony_ci  PrintF("VECTOR_ENHANCE_FACILITY_1=%d\n",
2801cb0ef41Sopenharmony_ci         CpuFeatures::IsSupported(VECTOR_ENHANCE_FACILITY_1));
2811cb0ef41Sopenharmony_ci  PrintF("VECTOR_ENHANCE_FACILITY_2=%d\n",
2821cb0ef41Sopenharmony_ci         CpuFeatures::IsSupported(VECTOR_ENHANCE_FACILITY_2));
2831cb0ef41Sopenharmony_ci  PrintF("MISC_INSTR_EXT2=%d\n", CpuFeatures::IsSupported(MISC_INSTR_EXT2));
2841cb0ef41Sopenharmony_ci}
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ciRegister ToRegister(int num) {
2871cb0ef41Sopenharmony_ci  DCHECK(num >= 0 && num < kNumRegisters);
2881cb0ef41Sopenharmony_ci  const Register kRegisters[] = {r0, r1, r2,  r3, r4, r5,  r6,  r7,
2891cb0ef41Sopenharmony_ci                                 r8, r9, r10, fp, ip, r13, r14, sp};
2901cb0ef41Sopenharmony_ci  return kRegisters[num];
2911cb0ef41Sopenharmony_ci}
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
2941cb0ef41Sopenharmony_ci// Implementation of RelocInfo
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ciconst int RelocInfo::kApplyMask =
2971cb0ef41Sopenharmony_ci    RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2981cb0ef41Sopenharmony_ci    RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_cibool RelocInfo::IsCodedSpecially() {
3011cb0ef41Sopenharmony_ci  // The deserializer needs to know whether a pointer is specially
3021cb0ef41Sopenharmony_ci  // coded.  Being specially coded on S390 means that it is an iihf/iilf
3031cb0ef41Sopenharmony_ci  // instruction sequence, and that is always the case inside code
3041cb0ef41Sopenharmony_ci  // objects.
3051cb0ef41Sopenharmony_ci  return true;
3061cb0ef41Sopenharmony_ci}
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_cibool RelocInfo::IsInConstantPool() { return false; }
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ciuint32_t RelocInfo::wasm_call_tag() const {
3111cb0ef41Sopenharmony_ci  DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
3121cb0ef41Sopenharmony_ci  return static_cast<uint32_t>(
3131cb0ef41Sopenharmony_ci      Assembler::target_address_at(pc_, constant_pool_));
3141cb0ef41Sopenharmony_ci}
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
3171cb0ef41Sopenharmony_ci// Implementation of Operand and MemOperand
3181cb0ef41Sopenharmony_ci// See assembler-s390-inl.h for inlined constructors
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ciOperand::Operand(Handle<HeapObject> handle) {
3211cb0ef41Sopenharmony_ci  AllowHandleDereference using_location;
3221cb0ef41Sopenharmony_ci  rm_ = no_reg;
3231cb0ef41Sopenharmony_ci  value_.immediate = static_cast<intptr_t>(handle.address());
3241cb0ef41Sopenharmony_ci  rmode_ = RelocInfo::FULL_EMBEDDED_OBJECT;
3251cb0ef41Sopenharmony_ci}
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ciOperand Operand::EmbeddedNumber(double value) {
3281cb0ef41Sopenharmony_ci  int32_t smi;
3291cb0ef41Sopenharmony_ci  if (DoubleToSmiInteger(value, &smi)) return Operand(Smi::FromInt(smi));
3301cb0ef41Sopenharmony_ci  Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
3311cb0ef41Sopenharmony_ci  result.is_heap_object_request_ = true;
3321cb0ef41Sopenharmony_ci  result.value_.heap_object_request = HeapObjectRequest(value);
3331cb0ef41Sopenharmony_ci  return result;
3341cb0ef41Sopenharmony_ci}
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ciOperand Operand::EmbeddedStringConstant(const StringConstantBase* str) {
3371cb0ef41Sopenharmony_ci  Operand result(0, RelocInfo::FULL_EMBEDDED_OBJECT);
3381cb0ef41Sopenharmony_ci  result.is_heap_object_request_ = true;
3391cb0ef41Sopenharmony_ci  result.value_.heap_object_request = HeapObjectRequest(str);
3401cb0ef41Sopenharmony_ci  return result;
3411cb0ef41Sopenharmony_ci}
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ciMemOperand::MemOperand(Register rn, int32_t offset)
3441cb0ef41Sopenharmony_ci    : baseRegister(rn), indexRegister(r0), offset_(offset) {}
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ciMemOperand::MemOperand(Register rx, Register rb, int32_t offset)
3471cb0ef41Sopenharmony_ci    : baseRegister(rb), indexRegister(rx), offset_(offset) {}
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_civoid Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
3501cb0ef41Sopenharmony_ci  DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
3511cb0ef41Sopenharmony_ci  for (auto& request : heap_object_requests_) {
3521cb0ef41Sopenharmony_ci    Handle<HeapObject> object;
3531cb0ef41Sopenharmony_ci    Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
3541cb0ef41Sopenharmony_ci    switch (request.kind()) {
3551cb0ef41Sopenharmony_ci      case HeapObjectRequest::kHeapNumber: {
3561cb0ef41Sopenharmony_ci        object = isolate->factory()->NewHeapNumber<AllocationType::kOld>(
3571cb0ef41Sopenharmony_ci            request.heap_number());
3581cb0ef41Sopenharmony_ci        set_target_address_at(pc, kNullAddress, object.address(),
3591cb0ef41Sopenharmony_ci                              SKIP_ICACHE_FLUSH);
3601cb0ef41Sopenharmony_ci        break;
3611cb0ef41Sopenharmony_ci      }
3621cb0ef41Sopenharmony_ci      case HeapObjectRequest::kStringConstant: {
3631cb0ef41Sopenharmony_ci        const StringConstantBase* str = request.string();
3641cb0ef41Sopenharmony_ci        CHECK_NOT_NULL(str);
3651cb0ef41Sopenharmony_ci        set_target_address_at(pc, kNullAddress,
3661cb0ef41Sopenharmony_ci                              str->AllocateStringConstant(isolate).address());
3671cb0ef41Sopenharmony_ci        break;
3681cb0ef41Sopenharmony_ci      }
3691cb0ef41Sopenharmony_ci    }
3701cb0ef41Sopenharmony_ci  }
3711cb0ef41Sopenharmony_ci}
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
3741cb0ef41Sopenharmony_ci// Specific instructions, constants, and masks.
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ciAssembler::Assembler(const AssemblerOptions& options,
3771cb0ef41Sopenharmony_ci                     std::unique_ptr<AssemblerBuffer> buffer)
3781cb0ef41Sopenharmony_ci    : AssemblerBase(options, std::move(buffer)), scratch_register_list_({ip}) {
3791cb0ef41Sopenharmony_ci  reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
3801cb0ef41Sopenharmony_ci  last_bound_pos_ = 0;
3811cb0ef41Sopenharmony_ci  relocations_.reserve(128);
3821cb0ef41Sopenharmony_ci}
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_civoid Assembler::GetCode(Isolate* isolate, CodeDesc* desc,
3851cb0ef41Sopenharmony_ci                        SafepointTableBuilder* safepoint_table_builder,
3861cb0ef41Sopenharmony_ci                        int handler_table_offset) {
3871cb0ef41Sopenharmony_ci  // As a crutch to avoid having to add manual Align calls wherever we use a
3881cb0ef41Sopenharmony_ci  // raw workflow to create Code objects (mostly in tests), add another Align
3891cb0ef41Sopenharmony_ci  // call here. It does no harm - the end of the Code object is aligned to the
3901cb0ef41Sopenharmony_ci  // (larger) kCodeAlignment anyways.
3911cb0ef41Sopenharmony_ci  // TODO(jgruber): Consider moving responsibility for proper alignment to
3921cb0ef41Sopenharmony_ci  // metadata table builders (safepoint, handler, constant pool, code
3931cb0ef41Sopenharmony_ci  // comments).
3941cb0ef41Sopenharmony_ci  DataAlign(Code::kMetadataAlignment);
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci  EmitRelocations();
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  int code_comments_size = WriteCodeComments();
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci  AllocateAndInstallRequestedHeapObjects(isolate);
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci  // Set up code descriptor.
4031cb0ef41Sopenharmony_ci  // TODO(jgruber): Reconsider how these offsets and sizes are maintained up to
4041cb0ef41Sopenharmony_ci  // this point to make CodeDesc initialization less fiddly.
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci  static constexpr int kConstantPoolSize = 0;
4071cb0ef41Sopenharmony_ci  const int instruction_size = pc_offset();
4081cb0ef41Sopenharmony_ci  const int code_comments_offset = instruction_size - code_comments_size;
4091cb0ef41Sopenharmony_ci  const int constant_pool_offset = code_comments_offset - kConstantPoolSize;
4101cb0ef41Sopenharmony_ci  const int handler_table_offset2 = (handler_table_offset == kNoHandlerTable)
4111cb0ef41Sopenharmony_ci                                        ? constant_pool_offset
4121cb0ef41Sopenharmony_ci                                        : handler_table_offset;
4131cb0ef41Sopenharmony_ci  const int safepoint_table_offset =
4141cb0ef41Sopenharmony_ci      (safepoint_table_builder == kNoSafepointTable)
4151cb0ef41Sopenharmony_ci          ? handler_table_offset2
4161cb0ef41Sopenharmony_ci          : safepoint_table_builder->safepoint_table_offset();
4171cb0ef41Sopenharmony_ci  const int reloc_info_offset =
4181cb0ef41Sopenharmony_ci      static_cast<int>(reloc_info_writer.pos() - buffer_->start());
4191cb0ef41Sopenharmony_ci  CodeDesc::Initialize(desc, this, safepoint_table_offset,
4201cb0ef41Sopenharmony_ci                       handler_table_offset2, constant_pool_offset,
4211cb0ef41Sopenharmony_ci                       code_comments_offset, reloc_info_offset);
4221cb0ef41Sopenharmony_ci}
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_civoid Assembler::Align(int m) {
4251cb0ef41Sopenharmony_ci  DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
4261cb0ef41Sopenharmony_ci  while ((pc_offset() & (m - 1)) != 0) {
4271cb0ef41Sopenharmony_ci    nop(0);
4281cb0ef41Sopenharmony_ci  }
4291cb0ef41Sopenharmony_ci}
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_civoid Assembler::CodeTargetAlign() { Align(8); }
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ciCondition Assembler::GetCondition(Instr instr) {
4341cb0ef41Sopenharmony_ci  switch (instr & kCondMask) {
4351cb0ef41Sopenharmony_ci    case BT:
4361cb0ef41Sopenharmony_ci      return eq;
4371cb0ef41Sopenharmony_ci    case BF:
4381cb0ef41Sopenharmony_ci      return ne;
4391cb0ef41Sopenharmony_ci    default:
4401cb0ef41Sopenharmony_ci      UNIMPLEMENTED();
4411cb0ef41Sopenharmony_ci  }
4421cb0ef41Sopenharmony_ci}
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_S390X
4451cb0ef41Sopenharmony_ci// This code assumes a FIXED_SEQUENCE for 64bit loads (iihf/iilf)
4461cb0ef41Sopenharmony_cibool Assembler::Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2) {
4471cb0ef41Sopenharmony_ci  // Check the instructions are the iihf/iilf load into ip
4481cb0ef41Sopenharmony_ci  return (((instr1 >> 32) == 0xC0C8) && ((instr2 >> 32) == 0xC0C9));
4491cb0ef41Sopenharmony_ci}
4501cb0ef41Sopenharmony_ci#else
4511cb0ef41Sopenharmony_ci// This code assumes a FIXED_SEQUENCE for 32bit loads (iilf)
4521cb0ef41Sopenharmony_cibool Assembler::Is32BitLoadIntoIP(SixByteInstr instr) {
4531cb0ef41Sopenharmony_ci  // Check the instruction is an iilf load into ip/r12.
4541cb0ef41Sopenharmony_ci  return ((instr >> 32) == 0xC0C9);
4551cb0ef41Sopenharmony_ci}
4561cb0ef41Sopenharmony_ci#endif
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci// Labels refer to positions in the (to be) generated code.
4591cb0ef41Sopenharmony_ci// There are bound, linked, and unused labels.
4601cb0ef41Sopenharmony_ci//
4611cb0ef41Sopenharmony_ci// Bound labels refer to known positions in the already
4621cb0ef41Sopenharmony_ci// generated code. pos() is the position the label refers to.
4631cb0ef41Sopenharmony_ci//
4641cb0ef41Sopenharmony_ci// Linked labels refer to unknown positions in the code
4651cb0ef41Sopenharmony_ci// to be generated; pos() is the position of the last
4661cb0ef41Sopenharmony_ci// instruction using the label.
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci// The link chain is terminated by a negative code position (must be aligned)
4691cb0ef41Sopenharmony_ciconst int kEndOfChain = -4;
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci// Returns the target address of the relative instructions, typically
4721cb0ef41Sopenharmony_ci// of the form: pos + imm (where immediate is in # of halfwords for
4731cb0ef41Sopenharmony_ci// BR* and LARL).
4741cb0ef41Sopenharmony_ciint Assembler::target_at(int pos) {
4751cb0ef41Sopenharmony_ci  SixByteInstr instr = instr_at(pos);
4761cb0ef41Sopenharmony_ci  // check which type of branch this is 16 or 26 bit offset
4771cb0ef41Sopenharmony_ci  Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
4801cb0ef41Sopenharmony_ci    int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
4811cb0ef41Sopenharmony_ci    imm16 <<= 1;  // immediate is in # of halfwords
4821cb0ef41Sopenharmony_ci    if (imm16 == 0) return kEndOfChain;
4831cb0ef41Sopenharmony_ci    return pos + imm16;
4841cb0ef41Sopenharmony_ci  } else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
4851cb0ef41Sopenharmony_ci             BRASL == opcode || LGRL == opcode) {
4861cb0ef41Sopenharmony_ci    int32_t imm32 =
4871cb0ef41Sopenharmony_ci        static_cast<int32_t>(instr & (static_cast<uint64_t>(0xFFFFFFFF)));
4881cb0ef41Sopenharmony_ci    if (LLILF != opcode)
4891cb0ef41Sopenharmony_ci      imm32 <<= 1;  // BR* + LARL treat immediate in # of halfwords
4901cb0ef41Sopenharmony_ci    if (imm32 == 0) return kEndOfChain;
4911cb0ef41Sopenharmony_ci    return pos + imm32;
4921cb0ef41Sopenharmony_ci  } else if (BRXHG == opcode) {
4931cb0ef41Sopenharmony_ci    // offset is in bits 16-31 of 48 bit instruction
4941cb0ef41Sopenharmony_ci    instr = instr >> 16;
4951cb0ef41Sopenharmony_ci    int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
4961cb0ef41Sopenharmony_ci    imm16 <<= 1;  // immediate is in # of halfwords
4971cb0ef41Sopenharmony_ci    if (imm16 == 0) return kEndOfChain;
4981cb0ef41Sopenharmony_ci    return pos + imm16;
4991cb0ef41Sopenharmony_ci  }
5001cb0ef41Sopenharmony_ci
5011cb0ef41Sopenharmony_ci  // Unknown condition
5021cb0ef41Sopenharmony_ci  DCHECK(false);
5031cb0ef41Sopenharmony_ci  return -1;
5041cb0ef41Sopenharmony_ci}
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci// Update the target address of the current relative instruction.
5071cb0ef41Sopenharmony_civoid Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
5081cb0ef41Sopenharmony_ci  SixByteInstr instr = instr_at(pos);
5091cb0ef41Sopenharmony_ci  Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci  if (is_branch != nullptr) {
5121cb0ef41Sopenharmony_ci    *is_branch =
5131cb0ef41Sopenharmony_ci        (opcode == BRC || opcode == BRCT || opcode == BRCTG || opcode == BRCL ||
5141cb0ef41Sopenharmony_ci         opcode == BRASL || opcode == BRXH || opcode == BRXHG);
5151cb0ef41Sopenharmony_ci  }
5161cb0ef41Sopenharmony_ci
5171cb0ef41Sopenharmony_ci  if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
5181cb0ef41Sopenharmony_ci    int16_t imm16 = target_pos - pos;
5191cb0ef41Sopenharmony_ci    instr &= (~0xFFFF);
5201cb0ef41Sopenharmony_ci    DCHECK(is_int16(imm16));
5211cb0ef41Sopenharmony_ci    instr_at_put<FourByteInstr>(pos, instr | (imm16 >> 1));
5221cb0ef41Sopenharmony_ci    return;
5231cb0ef41Sopenharmony_ci  } else if (BRCL == opcode || LARL == opcode || BRASL == opcode ||
5241cb0ef41Sopenharmony_ci             LGRL == opcode) {
5251cb0ef41Sopenharmony_ci    // Immediate is in # of halfwords
5261cb0ef41Sopenharmony_ci    int32_t imm32 = target_pos - pos;
5271cb0ef41Sopenharmony_ci    instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
5281cb0ef41Sopenharmony_ci    instr_at_put<SixByteInstr>(pos, instr | (imm32 >> 1));
5291cb0ef41Sopenharmony_ci    return;
5301cb0ef41Sopenharmony_ci  } else if (LLILF == opcode) {
5311cb0ef41Sopenharmony_ci    DCHECK(target_pos == kEndOfChain || target_pos >= 0);
5321cb0ef41Sopenharmony_ci    // Emitted label constant, not part of a branch.
5331cb0ef41Sopenharmony_ci    // Make label relative to Code pointer of generated Code object.
5341cb0ef41Sopenharmony_ci    int32_t imm32 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
5351cb0ef41Sopenharmony_ci    instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
5361cb0ef41Sopenharmony_ci    instr_at_put<SixByteInstr>(pos, instr | imm32);
5371cb0ef41Sopenharmony_ci    return;
5381cb0ef41Sopenharmony_ci  } else if (BRXHG == opcode) {
5391cb0ef41Sopenharmony_ci    // Immediate is in bits 16-31 of 48 bit instruction
5401cb0ef41Sopenharmony_ci    int32_t imm16 = target_pos - pos;
5411cb0ef41Sopenharmony_ci    instr &= (0xFFFF0000FFFF);  // clear bits 16-31
5421cb0ef41Sopenharmony_ci    imm16 &= 0xFFFF;            // clear high halfword
5431cb0ef41Sopenharmony_ci    imm16 <<= 16;
5441cb0ef41Sopenharmony_ci    // Immediate is in # of halfwords
5451cb0ef41Sopenharmony_ci    instr_at_put<SixByteInstr>(pos, instr | (imm16 >> 1));
5461cb0ef41Sopenharmony_ci    return;
5471cb0ef41Sopenharmony_ci  }
5481cb0ef41Sopenharmony_ci  DCHECK(false);
5491cb0ef41Sopenharmony_ci}
5501cb0ef41Sopenharmony_ci
5511cb0ef41Sopenharmony_ci// Returns the maximum number of bits given instruction can address.
5521cb0ef41Sopenharmony_ciint Assembler::max_reach_from(int pos) {
5531cb0ef41Sopenharmony_ci  Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
5541cb0ef41Sopenharmony_ci  // Check which type of instr.  In theory, we can return
5551cb0ef41Sopenharmony_ci  // the values below + 1, given offset is # of halfwords
5561cb0ef41Sopenharmony_ci  if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode ||
5571cb0ef41Sopenharmony_ci      BRXHG == opcode) {
5581cb0ef41Sopenharmony_ci    return 16;
5591cb0ef41Sopenharmony_ci  } else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
5601cb0ef41Sopenharmony_ci             BRASL == opcode || LGRL == opcode) {
5611cb0ef41Sopenharmony_ci    return 31;  // Using 31 as workaround instead of 32 as
5621cb0ef41Sopenharmony_ci                // is_intn(x,32) doesn't work on 32-bit platforms.
5631cb0ef41Sopenharmony_ci                // llilf: Emitted label constant, not part of
5641cb0ef41Sopenharmony_ci                //        a branch (regexp PushBacktrack).
5651cb0ef41Sopenharmony_ci  }
5661cb0ef41Sopenharmony_ci  DCHECK(false);
5671cb0ef41Sopenharmony_ci  return 16;
5681cb0ef41Sopenharmony_ci}
5691cb0ef41Sopenharmony_ci
5701cb0ef41Sopenharmony_civoid Assembler::bind_to(Label* L, int pos) {
5711cb0ef41Sopenharmony_ci  DCHECK(0 <= pos && pos <= pc_offset());  // must have a valid binding position
5721cb0ef41Sopenharmony_ci  bool is_branch = false;
5731cb0ef41Sopenharmony_ci  while (L->is_linked()) {
5741cb0ef41Sopenharmony_ci    int fixup_pos = L->pos();
5751cb0ef41Sopenharmony_ci#ifdef DEBUG
5761cb0ef41Sopenharmony_ci    int32_t offset = pos - fixup_pos;
5771cb0ef41Sopenharmony_ci    int maxReach = max_reach_from(fixup_pos);
5781cb0ef41Sopenharmony_ci#endif
5791cb0ef41Sopenharmony_ci    next(L);  // call next before overwriting link with target at fixup_pos
5801cb0ef41Sopenharmony_ci    DCHECK(is_intn(offset, maxReach));
5811cb0ef41Sopenharmony_ci    target_at_put(fixup_pos, pos, &is_branch);
5821cb0ef41Sopenharmony_ci  }
5831cb0ef41Sopenharmony_ci  L->bind_to(pos);
5841cb0ef41Sopenharmony_ci
5851cb0ef41Sopenharmony_ci  // Keep track of the last bound label so we don't eliminate any instructions
5861cb0ef41Sopenharmony_ci  // before a bound label.
5871cb0ef41Sopenharmony_ci  if (pos > last_bound_pos_) last_bound_pos_ = pos;
5881cb0ef41Sopenharmony_ci}
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_civoid Assembler::bind(Label* L) {
5911cb0ef41Sopenharmony_ci  DCHECK(!L->is_bound());  // label can only be bound once
5921cb0ef41Sopenharmony_ci  bind_to(L, pc_offset());
5931cb0ef41Sopenharmony_ci}
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_civoid Assembler::next(Label* L) {
5961cb0ef41Sopenharmony_ci  DCHECK(L->is_linked());
5971cb0ef41Sopenharmony_ci  int link = target_at(L->pos());
5981cb0ef41Sopenharmony_ci  if (link == kEndOfChain) {
5991cb0ef41Sopenharmony_ci    L->Unuse();
6001cb0ef41Sopenharmony_ci  } else {
6011cb0ef41Sopenharmony_ci    DCHECK_GE(link, 0);
6021cb0ef41Sopenharmony_ci    L->link_to(link);
6031cb0ef41Sopenharmony_ci  }
6041cb0ef41Sopenharmony_ci}
6051cb0ef41Sopenharmony_ci
6061cb0ef41Sopenharmony_ciint Assembler::link(Label* L) {
6071cb0ef41Sopenharmony_ci  int position;
6081cb0ef41Sopenharmony_ci  if (L->is_bound()) {
6091cb0ef41Sopenharmony_ci    position = L->pos();
6101cb0ef41Sopenharmony_ci  } else {
6111cb0ef41Sopenharmony_ci    if (L->is_linked()) {
6121cb0ef41Sopenharmony_ci      position = L->pos();  // L's link
6131cb0ef41Sopenharmony_ci    } else {
6141cb0ef41Sopenharmony_ci      // was: target_pos = kEndOfChain;
6151cb0ef41Sopenharmony_ci      // However, using self to mark the first reference
6161cb0ef41Sopenharmony_ci      // should avoid most instances of branch offset overflow.  See
6171cb0ef41Sopenharmony_ci      // target_at() for where this is converted back to kEndOfChain.
6181cb0ef41Sopenharmony_ci      position = pc_offset();
6191cb0ef41Sopenharmony_ci    }
6201cb0ef41Sopenharmony_ci    L->link_to(pc_offset());
6211cb0ef41Sopenharmony_ci  }
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci  return position;
6241cb0ef41Sopenharmony_ci}
6251cb0ef41Sopenharmony_ci
6261cb0ef41Sopenharmony_civoid Assembler::load_label_offset(Register r1, Label* L) {
6271cb0ef41Sopenharmony_ci  int target_pos;
6281cb0ef41Sopenharmony_ci  int constant;
6291cb0ef41Sopenharmony_ci  if (L->is_bound()) {
6301cb0ef41Sopenharmony_ci    target_pos = L->pos();
6311cb0ef41Sopenharmony_ci    constant = target_pos + (Code::kHeaderSize - kHeapObjectTag);
6321cb0ef41Sopenharmony_ci  } else {
6331cb0ef41Sopenharmony_ci    if (L->is_linked()) {
6341cb0ef41Sopenharmony_ci      target_pos = L->pos();  // L's link
6351cb0ef41Sopenharmony_ci    } else {
6361cb0ef41Sopenharmony_ci      // was: target_pos = kEndOfChain;
6371cb0ef41Sopenharmony_ci      // However, using branch to self to mark the first reference
6381cb0ef41Sopenharmony_ci      // should avoid most instances of branch offset overflow.  See
6391cb0ef41Sopenharmony_ci      // target_at() for where this is converted back to kEndOfChain.
6401cb0ef41Sopenharmony_ci      target_pos = pc_offset();
6411cb0ef41Sopenharmony_ci    }
6421cb0ef41Sopenharmony_ci    L->link_to(pc_offset());
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci    constant = target_pos - pc_offset();
6451cb0ef41Sopenharmony_ci  }
6461cb0ef41Sopenharmony_ci  llilf(r1, Operand(constant));
6471cb0ef41Sopenharmony_ci}
6481cb0ef41Sopenharmony_ci
6491cb0ef41Sopenharmony_ci// Pseudo op - branch on condition
6501cb0ef41Sopenharmony_civoid Assembler::branchOnCond(Condition c, int branch_offset, bool is_bound,
6511cb0ef41Sopenharmony_ci                             bool force_long_branch) {
6521cb0ef41Sopenharmony_ci  int offset_in_halfwords = branch_offset / 2;
6531cb0ef41Sopenharmony_ci  if (is_bound && is_int16(offset_in_halfwords) && !force_long_branch) {
6541cb0ef41Sopenharmony_ci    brc(c, Operand(offset_in_halfwords));  // short jump
6551cb0ef41Sopenharmony_ci  } else {
6561cb0ef41Sopenharmony_ci    brcl(c, Operand(offset_in_halfwords));  // long jump
6571cb0ef41Sopenharmony_ci  }
6581cb0ef41Sopenharmony_ci}
6591cb0ef41Sopenharmony_ci
6601cb0ef41Sopenharmony_ci// Exception-generating instructions and debugging support.
6611cb0ef41Sopenharmony_ci// Stops with a non-negative code less than kNumOfWatchedStops support
6621cb0ef41Sopenharmony_ci// enabling/disabling and a counter feature. See simulator-s390.h .
6631cb0ef41Sopenharmony_civoid Assembler::stop(Condition cond, int32_t code, CRegister cr) {
6641cb0ef41Sopenharmony_ci  if (cond != al) {
6651cb0ef41Sopenharmony_ci    Label skip;
6661cb0ef41Sopenharmony_ci    b(NegateCondition(cond), &skip, Label::kNear);
6671cb0ef41Sopenharmony_ci    bkpt(0);
6681cb0ef41Sopenharmony_ci    bind(&skip);
6691cb0ef41Sopenharmony_ci  } else {
6701cb0ef41Sopenharmony_ci    bkpt(0);
6711cb0ef41Sopenharmony_ci  }
6721cb0ef41Sopenharmony_ci}
6731cb0ef41Sopenharmony_ci
6741cb0ef41Sopenharmony_civoid Assembler::bkpt(uint32_t imm16) {
6751cb0ef41Sopenharmony_ci  // GDB software breakpoint instruction
6761cb0ef41Sopenharmony_ci  emit2bytes(0x0001);
6771cb0ef41Sopenharmony_ci}
6781cb0ef41Sopenharmony_ci
6791cb0ef41Sopenharmony_ci// Pseudo instructions.
6801cb0ef41Sopenharmony_civoid Assembler::nop(int type) {
6811cb0ef41Sopenharmony_ci  switch (type) {
6821cb0ef41Sopenharmony_ci    case 0:
6831cb0ef41Sopenharmony_ci      lr(r0, r0);
6841cb0ef41Sopenharmony_ci      break;
6851cb0ef41Sopenharmony_ci    case DEBUG_BREAK_NOP:
6861cb0ef41Sopenharmony_ci      // TODO(john.yan): Use a better NOP break
6871cb0ef41Sopenharmony_ci      oill(r3, Operand::Zero());
6881cb0ef41Sopenharmony_ci      break;
6891cb0ef41Sopenharmony_ci    default:
6901cb0ef41Sopenharmony_ci      UNIMPLEMENTED();
6911cb0ef41Sopenharmony_ci  }
6921cb0ef41Sopenharmony_ci}
6931cb0ef41Sopenharmony_ci
6941cb0ef41Sopenharmony_ci// -------------------------
6951cb0ef41Sopenharmony_ci// Load Address Instructions
6961cb0ef41Sopenharmony_ci// -------------------------
6971cb0ef41Sopenharmony_ci// Load Address Relative Long
6981cb0ef41Sopenharmony_civoid Assembler::larl(Register r1, Label* l) {
6991cb0ef41Sopenharmony_ci  larl(r1, Operand(branch_offset(l)));
7001cb0ef41Sopenharmony_ci}
7011cb0ef41Sopenharmony_ci
7021cb0ef41Sopenharmony_civoid Assembler::lgrl(Register r1, Label* l) {
7031cb0ef41Sopenharmony_ci  lgrl(r1, Operand(branch_offset(l)));
7041cb0ef41Sopenharmony_ci}
7051cb0ef41Sopenharmony_ci
7061cb0ef41Sopenharmony_civoid Assembler::EnsureSpaceFor(int space_needed) {
7071cb0ef41Sopenharmony_ci  if (buffer_space() <= (kGap + space_needed)) {
7081cb0ef41Sopenharmony_ci    GrowBuffer(space_needed);
7091cb0ef41Sopenharmony_ci  }
7101cb0ef41Sopenharmony_ci}
7111cb0ef41Sopenharmony_ci
7121cb0ef41Sopenharmony_civoid Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
7131cb0ef41Sopenharmony_ci  DCHECK(RelocInfo::IsCodeTarget(rmode));
7141cb0ef41Sopenharmony_ci  EnsureSpace ensure_space(this);
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_ci  RecordRelocInfo(rmode);
7171cb0ef41Sopenharmony_ci  int32_t target_index = AddCodeTarget(target);
7181cb0ef41Sopenharmony_ci  brasl(r14, Operand(target_index));
7191cb0ef41Sopenharmony_ci}
7201cb0ef41Sopenharmony_ci
7211cb0ef41Sopenharmony_civoid Assembler::jump(Handle<Code> target, RelocInfo::Mode rmode,
7221cb0ef41Sopenharmony_ci                     Condition cond) {
7231cb0ef41Sopenharmony_ci  DCHECK(RelocInfo::IsRelativeCodeTarget(rmode));
7241cb0ef41Sopenharmony_ci  EnsureSpace ensure_space(this);
7251cb0ef41Sopenharmony_ci
7261cb0ef41Sopenharmony_ci  RecordRelocInfo(rmode);
7271cb0ef41Sopenharmony_ci  int32_t target_index = AddCodeTarget(target);
7281cb0ef41Sopenharmony_ci  brcl(cond, Operand(target_index));
7291cb0ef41Sopenharmony_ci}
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci// end of S390instructions
7321cb0ef41Sopenharmony_ci
7331cb0ef41Sopenharmony_cibool Assembler::IsNop(SixByteInstr instr, int type) {
7341cb0ef41Sopenharmony_ci  DCHECK((0 == type) || (DEBUG_BREAK_NOP == type));
7351cb0ef41Sopenharmony_ci  if (DEBUG_BREAK_NOP == type) {
7361cb0ef41Sopenharmony_ci    return ((instr & 0xFFFFFFFF) == 0xA53B0000);  // oill r3, 0
7371cb0ef41Sopenharmony_ci  }
7381cb0ef41Sopenharmony_ci  return ((instr & 0xFFFF) == 0x1800);  // lr r0,r0
7391cb0ef41Sopenharmony_ci}
7401cb0ef41Sopenharmony_ci
7411cb0ef41Sopenharmony_ci// dummy instruction reserved for special use.
7421cb0ef41Sopenharmony_civoid Assembler::dumy(int r1, int x2, int b2, int d2) {
7431cb0ef41Sopenharmony_ci#if defined(USE_SIMULATOR)
7441cb0ef41Sopenharmony_ci  int op = 0xE353;
7451cb0ef41Sopenharmony_ci  uint64_t code = (static_cast<uint64_t>(op & 0xFF00)) * B32 |
7461cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(r1) & 0xF) * B36 |
7471cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(x2) & 0xF) * B32 |
7481cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(b2) & 0xF) * B28 |
7491cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(d2 & 0x0FFF)) * B16 |
7501cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(d2 & 0x0FF000)) >> 4 |
7511cb0ef41Sopenharmony_ci                  (static_cast<uint64_t>(op & 0x00FF));
7521cb0ef41Sopenharmony_ci  emit6bytes(code);
7531cb0ef41Sopenharmony_ci#endif
7541cb0ef41Sopenharmony_ci}
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_civoid Assembler::GrowBuffer(int needed) {
7571cb0ef41Sopenharmony_ci  DCHECK_EQ(buffer_start_, buffer_->start());
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_ci  // Compute new buffer size.
7601cb0ef41Sopenharmony_ci  int old_size = buffer_->size();
7611cb0ef41Sopenharmony_ci  int new_size = std::min(2 * old_size, old_size + 1 * MB);
7621cb0ef41Sopenharmony_ci  int space = buffer_space() + (new_size - old_size);
7631cb0ef41Sopenharmony_ci  new_size += (space < needed) ? needed - space : 0;
7641cb0ef41Sopenharmony_ci
7651cb0ef41Sopenharmony_ci  // Some internal data structures overflow for very large buffers,
7661cb0ef41Sopenharmony_ci  // they must ensure that kMaximalBufferSize is not too large.
7671cb0ef41Sopenharmony_ci  if (new_size > kMaximalBufferSize) {
7681cb0ef41Sopenharmony_ci    V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
7691cb0ef41Sopenharmony_ci  }
7701cb0ef41Sopenharmony_ci
7711cb0ef41Sopenharmony_ci  // Set up new buffer.
7721cb0ef41Sopenharmony_ci  std::unique_ptr<AssemblerBuffer> new_buffer = buffer_->Grow(new_size);
7731cb0ef41Sopenharmony_ci  DCHECK_EQ(new_size, new_buffer->size());
7741cb0ef41Sopenharmony_ci  byte* new_start = new_buffer->start();
7751cb0ef41Sopenharmony_ci
7761cb0ef41Sopenharmony_ci  // Copy the data.
7771cb0ef41Sopenharmony_ci  intptr_t pc_delta = new_start - buffer_start_;
7781cb0ef41Sopenharmony_ci  intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size);
7791cb0ef41Sopenharmony_ci  size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos();
7801cb0ef41Sopenharmony_ci  MemMove(new_start, buffer_start_, pc_offset());
7811cb0ef41Sopenharmony_ci  MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
7821cb0ef41Sopenharmony_ci          reloc_size);
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci  // Switch buffers.
7851cb0ef41Sopenharmony_ci  buffer_ = std::move(new_buffer);
7861cb0ef41Sopenharmony_ci  buffer_start_ = new_start;
7871cb0ef41Sopenharmony_ci  pc_ += pc_delta;
7881cb0ef41Sopenharmony_ci  reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
7891cb0ef41Sopenharmony_ci                               reloc_info_writer.last_pc() + pc_delta);
7901cb0ef41Sopenharmony_ci
7911cb0ef41Sopenharmony_ci  // None of our relocation types are pc relative pointing outside the code
7921cb0ef41Sopenharmony_ci  // buffer nor pc absolute pointing inside the code buffer, so there is no need
7931cb0ef41Sopenharmony_ci  // to relocate any emitted relocation entries.
7941cb0ef41Sopenharmony_ci}
7951cb0ef41Sopenharmony_ci
7961cb0ef41Sopenharmony_civoid Assembler::db(uint8_t data) {
7971cb0ef41Sopenharmony_ci  CheckBuffer();
7981cb0ef41Sopenharmony_ci  *reinterpret_cast<uint8_t*>(pc_) = data;
7991cb0ef41Sopenharmony_ci  pc_ += sizeof(uint8_t);
8001cb0ef41Sopenharmony_ci}
8011cb0ef41Sopenharmony_ci
8021cb0ef41Sopenharmony_civoid Assembler::dd(uint32_t data, RelocInfo::Mode rmode) {
8031cb0ef41Sopenharmony_ci  CheckBuffer();
8041cb0ef41Sopenharmony_ci  if (!RelocInfo::IsNoInfo(rmode)) {
8051cb0ef41Sopenharmony_ci    DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) ||
8061cb0ef41Sopenharmony_ci           RelocInfo::IsLiteralConstant(rmode));
8071cb0ef41Sopenharmony_ci    RecordRelocInfo(rmode);
8081cb0ef41Sopenharmony_ci  }
8091cb0ef41Sopenharmony_ci  *reinterpret_cast<uint32_t*>(pc_) = data;
8101cb0ef41Sopenharmony_ci  pc_ += sizeof(uint32_t);
8111cb0ef41Sopenharmony_ci}
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_civoid Assembler::dq(uint64_t value, RelocInfo::Mode rmode) {
8141cb0ef41Sopenharmony_ci  CheckBuffer();
8151cb0ef41Sopenharmony_ci  if (!RelocInfo::IsNoInfo(rmode)) {
8161cb0ef41Sopenharmony_ci    DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) ||
8171cb0ef41Sopenharmony_ci           RelocInfo::IsLiteralConstant(rmode));
8181cb0ef41Sopenharmony_ci    RecordRelocInfo(rmode);
8191cb0ef41Sopenharmony_ci  }
8201cb0ef41Sopenharmony_ci  *reinterpret_cast<uint64_t*>(pc_) = value;
8211cb0ef41Sopenharmony_ci  pc_ += sizeof(uint64_t);
8221cb0ef41Sopenharmony_ci}
8231cb0ef41Sopenharmony_ci
8241cb0ef41Sopenharmony_civoid Assembler::dp(uintptr_t data, RelocInfo::Mode rmode) {
8251cb0ef41Sopenharmony_ci  CheckBuffer();
8261cb0ef41Sopenharmony_ci  if (!RelocInfo::IsNoInfo(rmode)) {
8271cb0ef41Sopenharmony_ci    DCHECK(RelocInfo::IsDataEmbeddedObject(rmode) ||
8281cb0ef41Sopenharmony_ci           RelocInfo::IsLiteralConstant(rmode));
8291cb0ef41Sopenharmony_ci    RecordRelocInfo(rmode);
8301cb0ef41Sopenharmony_ci  }
8311cb0ef41Sopenharmony_ci  *reinterpret_cast<uintptr_t*>(pc_) = data;
8321cb0ef41Sopenharmony_ci  pc_ += sizeof(uintptr_t);
8331cb0ef41Sopenharmony_ci}
8341cb0ef41Sopenharmony_ci
8351cb0ef41Sopenharmony_civoid Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
8361cb0ef41Sopenharmony_ci  if (!ShouldRecordRelocInfo(rmode)) return;
8371cb0ef41Sopenharmony_ci  DeferredRelocInfo rinfo(pc_offset(), rmode, data);
8381cb0ef41Sopenharmony_ci  relocations_.push_back(rinfo);
8391cb0ef41Sopenharmony_ci}
8401cb0ef41Sopenharmony_ci
8411cb0ef41Sopenharmony_civoid Assembler::emit_label_addr(Label* label) {
8421cb0ef41Sopenharmony_ci  CheckBuffer();
8431cb0ef41Sopenharmony_ci  RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
8441cb0ef41Sopenharmony_ci  int position = link(label);
8451cb0ef41Sopenharmony_ci  DCHECK(label->is_bound());
8461cb0ef41Sopenharmony_ci  // Keep internal references relative until EmitRelocations.
8471cb0ef41Sopenharmony_ci  dp(position);
8481cb0ef41Sopenharmony_ci}
8491cb0ef41Sopenharmony_ci
8501cb0ef41Sopenharmony_civoid Assembler::EmitRelocations() {
8511cb0ef41Sopenharmony_ci  EnsureSpaceFor(relocations_.size() * kMaxRelocSize);
8521cb0ef41Sopenharmony_ci
8531cb0ef41Sopenharmony_ci  for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
8541cb0ef41Sopenharmony_ci       it != relocations_.end(); it++) {
8551cb0ef41Sopenharmony_ci    RelocInfo::Mode rmode = it->rmode();
8561cb0ef41Sopenharmony_ci    Address pc = reinterpret_cast<Address>(buffer_start_) + it->position();
8571cb0ef41Sopenharmony_ci    RelocInfo rinfo(pc, rmode, it->data(), Code());
8581cb0ef41Sopenharmony_ci
8591cb0ef41Sopenharmony_ci    // Fix up internal references now that they are guaranteed to be bound.
8601cb0ef41Sopenharmony_ci    if (RelocInfo::IsInternalReference(rmode)) {
8611cb0ef41Sopenharmony_ci      // Jump table entry
8621cb0ef41Sopenharmony_ci      Address pos = Memory<Address>(pc);
8631cb0ef41Sopenharmony_ci      Memory<Address>(pc) = reinterpret_cast<Address>(buffer_start_) + pos;
8641cb0ef41Sopenharmony_ci    } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
8651cb0ef41Sopenharmony_ci      // mov sequence
8661cb0ef41Sopenharmony_ci      Address pos = target_address_at(pc, 0);
8671cb0ef41Sopenharmony_ci      set_target_address_at(pc, 0,
8681cb0ef41Sopenharmony_ci                            reinterpret_cast<Address>(buffer_start_) + pos,
8691cb0ef41Sopenharmony_ci                            SKIP_ICACHE_FLUSH);
8701cb0ef41Sopenharmony_ci    }
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ci    reloc_info_writer.Write(&rinfo);
8731cb0ef41Sopenharmony_ci  }
8741cb0ef41Sopenharmony_ci}
8751cb0ef41Sopenharmony_ci
8761cb0ef41Sopenharmony_ciUseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)
8771cb0ef41Sopenharmony_ci    : assembler_(assembler),
8781cb0ef41Sopenharmony_ci      old_available_(*assembler->GetScratchRegisterList()) {}
8791cb0ef41Sopenharmony_ci
8801cb0ef41Sopenharmony_ciUseScratchRegisterScope::~UseScratchRegisterScope() {
8811cb0ef41Sopenharmony_ci  *assembler_->GetScratchRegisterList() = old_available_;
8821cb0ef41Sopenharmony_ci}
8831cb0ef41Sopenharmony_ci
8841cb0ef41Sopenharmony_ciRegister UseScratchRegisterScope::Acquire() {
8851cb0ef41Sopenharmony_ci  RegList* available = assembler_->GetScratchRegisterList();
8861cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(available);
8871cb0ef41Sopenharmony_ci  return available->PopFirst();
8881cb0ef41Sopenharmony_ci}
8891cb0ef41Sopenharmony_ci}  // namespace internal
8901cb0ef41Sopenharmony_ci}  // namespace v8
8911cb0ef41Sopenharmony_ci#endif  // V8_TARGET_ARCH_S390
892