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