14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include <cstdint> 174514f5e3Sopenharmony_ci#include <map> 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/compiler/assembler/aarch64/assembler_aarch64.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_ci#include "ecmascript/base/bit_helper.h" 224514f5e3Sopenharmony_ci#include "ecmascript/ecma_macros.h" 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_cinamespace panda::ecmascript::aarch64 { 254514f5e3Sopenharmony_ciusing namespace panda::ecmascript::base; 264514f5e3Sopenharmony_cistatic const uint64_t HWORD_MASK = 0xFFFF; 274514f5e3Sopenharmony_ci 284514f5e3Sopenharmony_ciLogicalImmediate LogicalImmediate::Create(uint64_t imm, int width) 294514f5e3Sopenharmony_ci{ 304514f5e3Sopenharmony_ci if ((imm == 0ULL) || (imm == ~0ULL) || 314514f5e3Sopenharmony_ci ((width != RegXSize) && (((imm >> width) != 0) || (imm == (~0ULL >> (RegXSize - width)))))) { 324514f5e3Sopenharmony_ci return LogicalImmediate(InvalidLogicalImmediate); 334514f5e3Sopenharmony_ci } 344514f5e3Sopenharmony_ci 354514f5e3Sopenharmony_ci // First, determine the element size. 364514f5e3Sopenharmony_ci unsigned int size = static_cast<uint32_t>(width); 374514f5e3Sopenharmony_ci do { 384514f5e3Sopenharmony_ci size /= 2; // 2: Divide by 2 394514f5e3Sopenharmony_ci uint64_t mask = (1ULL << size) - 1; 404514f5e3Sopenharmony_ci 414514f5e3Sopenharmony_ci if ((imm & mask) != ((imm >> size) & mask)) { 424514f5e3Sopenharmony_ci size *= 2; // 2: Multiply by 2 434514f5e3Sopenharmony_ci break; 444514f5e3Sopenharmony_ci } 454514f5e3Sopenharmony_ci } while (size > 2); // 2: Greater than 2 464514f5e3Sopenharmony_ci 474514f5e3Sopenharmony_ci // Second, determine the rotation to make the element be: 0^m 1^n. 484514f5e3Sopenharmony_ci unsigned int cto = 0; 494514f5e3Sopenharmony_ci unsigned int i = 0; 504514f5e3Sopenharmony_ci uint64_t mask = ((uint64_t)-1LL) >> (RegXSize - size); 514514f5e3Sopenharmony_ci imm &= mask; 524514f5e3Sopenharmony_ci 534514f5e3Sopenharmony_ci if (IsShiftedMask_64(imm)) { 544514f5e3Sopenharmony_ci i = CountTrailingZeros64(imm); 554514f5e3Sopenharmony_ci ASSERT_PRINT(i < RegXSize, "undefined behavior"); 564514f5e3Sopenharmony_ci cto = CountTrailingOnes64(imm >> i); 574514f5e3Sopenharmony_ci } else { 584514f5e3Sopenharmony_ci imm |= ~mask; 594514f5e3Sopenharmony_ci if (!IsShiftedMask_64(~imm)) { 604514f5e3Sopenharmony_ci return LogicalImmediate(InvalidLogicalImmediate); 614514f5e3Sopenharmony_ci } 624514f5e3Sopenharmony_ci 634514f5e3Sopenharmony_ci uint32_t clo = CountLeadingOnes64(imm); 644514f5e3Sopenharmony_ci i = static_cast<uint32_t>(RegXSize) - clo; 654514f5e3Sopenharmony_ci cto = clo + CountTrailingOnes64(imm) - (static_cast<uint32_t>(RegXSize) - size); 664514f5e3Sopenharmony_ci } 674514f5e3Sopenharmony_ci 684514f5e3Sopenharmony_ci // Encode in Immr the number of RORs it would take to get *from* 0^m 1^n 694514f5e3Sopenharmony_ci // to our target value, where I is the number of RORs to go the opposite 704514f5e3Sopenharmony_ci // direction. 714514f5e3Sopenharmony_ci ASSERT_PRINT(size > i, "i should be smaller than element size"); 724514f5e3Sopenharmony_ci unsigned immr = (size - i) & (size - 1); 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ci // If size has a 1 in the n'th bit, create a value that has zeroes in 754514f5e3Sopenharmony_ci // bits [0, n] and ones above that. 764514f5e3Sopenharmony_ci uint64_t nImms = ~(size - 1) << 1; 774514f5e3Sopenharmony_ci 784514f5e3Sopenharmony_ci // Or the CTO value into the low bits, which must be below the Nth bit 794514f5e3Sopenharmony_ci // bit mentioned above. 804514f5e3Sopenharmony_ci ASSERT(cto > 0); 814514f5e3Sopenharmony_ci nImms |= (cto - 1); 824514f5e3Sopenharmony_ci 834514f5e3Sopenharmony_ci // Extract the seventh bit and toggle it to create the N field. 844514f5e3Sopenharmony_ci // 6 means the topmost bit in nImms 854514f5e3Sopenharmony_ci unsigned int n = ((nImms >> 6) & 1) ^ 1; 864514f5e3Sopenharmony_ci return LogicalImmediate((n << BITWISE_OP_N_LOWBITS) | (immr << BITWISE_OP_Immr_LOWBITS) | 874514f5e3Sopenharmony_ci ((nImms << BITWISE_OP_Imms_LOWBITS) & BITWISE_OP_Imms_MASK)); 884514f5e3Sopenharmony_ci} 894514f5e3Sopenharmony_ci 904514f5e3Sopenharmony_civoid AssemblerAarch64::Ldp(const Register &rt, const Register &rt2, const MemoryOperand &operand) 914514f5e3Sopenharmony_ci{ 924514f5e3Sopenharmony_ci uint32_t op = 0; 934514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 944514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 954514f5e3Sopenharmony_ci case OFFSET: 964514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_Offset; 974514f5e3Sopenharmony_ci break; 984514f5e3Sopenharmony_ci case PREINDEX: 994514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_Pre; 1004514f5e3Sopenharmony_ci break; 1014514f5e3Sopenharmony_ci case POSTINDEX: 1024514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_Post; 1034514f5e3Sopenharmony_ci break; 1044514f5e3Sopenharmony_ci default: 1054514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1064514f5e3Sopenharmony_ci UNREACHABLE(); 1074514f5e3Sopenharmony_ci } 1084514f5e3Sopenharmony_ci bool sf = !rt.IsW(); 1094514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 1104514f5e3Sopenharmony_ci if (sf) { 1114514f5e3Sopenharmony_ci imm >>= 3; // 3: 64 RegSise, imm/8 to remove trailing zeros 1124514f5e3Sopenharmony_ci } else { 1134514f5e3Sopenharmony_ci imm >>= 2; // 2: 32 RegSise, imm/4 to remove trailing zeros 1144514f5e3Sopenharmony_ci } 1154514f5e3Sopenharmony_ci uint32_t instructionCode = Sf(sf) | op | LoadAndStorePairImm(imm) | Rt2(rt2.GetId()) | 1164514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 1174514f5e3Sopenharmony_ci EmitU32(instructionCode); 1184514f5e3Sopenharmony_ci return; 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1214514f5e3Sopenharmony_ci UNREACHABLE(); 1224514f5e3Sopenharmony_ci} 1234514f5e3Sopenharmony_ci 1244514f5e3Sopenharmony_civoid AssemblerAarch64::Stp(const Register &rt, const Register &rt2, const MemoryOperand &operand) 1254514f5e3Sopenharmony_ci{ 1264514f5e3Sopenharmony_ci uint32_t op = 0; 1274514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 1284514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 1294514f5e3Sopenharmony_ci case OFFSET: 1304514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_Offset; 1314514f5e3Sopenharmony_ci break; 1324514f5e3Sopenharmony_ci case PREINDEX: 1334514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_Pre; 1344514f5e3Sopenharmony_ci break; 1354514f5e3Sopenharmony_ci case POSTINDEX: 1364514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_Post; 1374514f5e3Sopenharmony_ci break; 1384514f5e3Sopenharmony_ci default: 1394514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1404514f5e3Sopenharmony_ci UNREACHABLE(); 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci bool sf = !rt.IsW(); 1434514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 1444514f5e3Sopenharmony_ci if (sf) { 1454514f5e3Sopenharmony_ci imm >>= 3; // 3: 64 RegSise, imm/8 to remove trailing zeros 1464514f5e3Sopenharmony_ci } else { 1474514f5e3Sopenharmony_ci imm >>= 2; // 2: 32 RegSise, imm/4 to remove trailing zeros 1484514f5e3Sopenharmony_ci } 1494514f5e3Sopenharmony_ci uint32_t instructionCode = Sf(sf) | op | LoadAndStorePairImm(imm) | Rt2(rt2.GetId()) | 1504514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 1514514f5e3Sopenharmony_ci EmitU32(instructionCode); 1524514f5e3Sopenharmony_ci return; 1534514f5e3Sopenharmony_ci } 1544514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1554514f5e3Sopenharmony_ci UNREACHABLE(); 1564514f5e3Sopenharmony_ci} 1574514f5e3Sopenharmony_ci 1584514f5e3Sopenharmony_civoid AssemblerAarch64::Ldp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand) 1594514f5e3Sopenharmony_ci{ 1604514f5e3Sopenharmony_ci uint32_t op = 0; 1614514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 1624514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 1634514f5e3Sopenharmony_ci case OFFSET: 1644514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_V_Offset; 1654514f5e3Sopenharmony_ci break; 1664514f5e3Sopenharmony_ci case PREINDEX: 1674514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_V_Pre; 1684514f5e3Sopenharmony_ci break; 1694514f5e3Sopenharmony_ci case POSTINDEX: 1704514f5e3Sopenharmony_ci op = LoadStorePairOpCode::LDP_V_Post; 1714514f5e3Sopenharmony_ci break; 1724514f5e3Sopenharmony_ci default: 1734514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1744514f5e3Sopenharmony_ci UNREACHABLE(); 1754514f5e3Sopenharmony_ci } 1764514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 1774514f5e3Sopenharmony_ci switch (vt.GetScale()) { 1784514f5e3Sopenharmony_ci case S: 1794514f5e3Sopenharmony_ci // 2 : 2 means remove trailing zeros 1804514f5e3Sopenharmony_ci imm >>= 2; 1814514f5e3Sopenharmony_ci break; 1824514f5e3Sopenharmony_ci case D: 1834514f5e3Sopenharmony_ci // 3 : 3 means remove trailing zeros 1844514f5e3Sopenharmony_ci imm >>= 3; 1854514f5e3Sopenharmony_ci break; 1864514f5e3Sopenharmony_ci case Q: 1874514f5e3Sopenharmony_ci // 4 : 4 means remove trailing zeros 1884514f5e3Sopenharmony_ci imm >>= 4; 1894514f5e3Sopenharmony_ci break; 1904514f5e3Sopenharmony_ci default: 1914514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1924514f5e3Sopenharmony_ci UNREACHABLE(); 1934514f5e3Sopenharmony_ci } 1944514f5e3Sopenharmony_ci uint32_t opc = GetOpcFromScale(vt.GetScale(), true); 1954514f5e3Sopenharmony_ci uint32_t instructionCode = opc | op | LoadAndStorePairImm(imm) | Rt2(vt2.GetId()) | 1964514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(vt.GetId()); 1974514f5e3Sopenharmony_ci EmitU32(instructionCode); 1984514f5e3Sopenharmony_ci return; 1994514f5e3Sopenharmony_ci } 2004514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2014514f5e3Sopenharmony_ci UNREACHABLE(); 2024514f5e3Sopenharmony_ci} 2034514f5e3Sopenharmony_ci 2044514f5e3Sopenharmony_civoid AssemblerAarch64::Stp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand) 2054514f5e3Sopenharmony_ci{ 2064514f5e3Sopenharmony_ci uint32_t op = 0; 2074514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 2084514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 2094514f5e3Sopenharmony_ci case OFFSET: 2104514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_V_Offset; 2114514f5e3Sopenharmony_ci break; 2124514f5e3Sopenharmony_ci case PREINDEX: 2134514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_V_Pre; 2144514f5e3Sopenharmony_ci break; 2154514f5e3Sopenharmony_ci case POSTINDEX: 2164514f5e3Sopenharmony_ci op = LoadStorePairOpCode::STP_V_Post; 2174514f5e3Sopenharmony_ci break; 2184514f5e3Sopenharmony_ci default: 2194514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2204514f5e3Sopenharmony_ci UNREACHABLE(); 2214514f5e3Sopenharmony_ci } 2224514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 2234514f5e3Sopenharmony_ci switch (vt.GetScale()) { 2244514f5e3Sopenharmony_ci case S: 2254514f5e3Sopenharmony_ci // 2 : 2 means remove trailing zeros 2264514f5e3Sopenharmony_ci imm >>= 2; 2274514f5e3Sopenharmony_ci break; 2284514f5e3Sopenharmony_ci case D: 2294514f5e3Sopenharmony_ci // 3 : 3 means remove trailing zeros 2304514f5e3Sopenharmony_ci imm >>= 3; 2314514f5e3Sopenharmony_ci break; 2324514f5e3Sopenharmony_ci case Q: 2334514f5e3Sopenharmony_ci // 4 : 4 means remove trailing zeros 2344514f5e3Sopenharmony_ci imm >>= 4; 2354514f5e3Sopenharmony_ci break; 2364514f5e3Sopenharmony_ci default: 2374514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2384514f5e3Sopenharmony_ci UNREACHABLE(); 2394514f5e3Sopenharmony_ci } 2404514f5e3Sopenharmony_ci uint32_t opc = GetOpcFromScale(vt.GetScale(), true); 2414514f5e3Sopenharmony_ci uint32_t instructionCode = opc | op | LoadAndStorePairImm(imm) | Rt2(vt2.GetId()) | 2424514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(vt.GetId()); 2434514f5e3Sopenharmony_ci EmitU32(instructionCode); 2444514f5e3Sopenharmony_ci return; 2454514f5e3Sopenharmony_ci } 2464514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2474514f5e3Sopenharmony_ci UNREACHABLE(); 2484514f5e3Sopenharmony_ci} 2494514f5e3Sopenharmony_ci 2504514f5e3Sopenharmony_ciuint32_t AssemblerAarch64::GetOpcFromScale(Scale scale, bool ispair) 2514514f5e3Sopenharmony_ci{ 2524514f5e3Sopenharmony_ci uint32_t opc = 0; 2534514f5e3Sopenharmony_ci switch (scale) { 2544514f5e3Sopenharmony_ci case Scale::B: 2554514f5e3Sopenharmony_ci case Scale::H: 2564514f5e3Sopenharmony_ci ASSERT(!ispair); 2574514f5e3Sopenharmony_ci opc = 1; 2584514f5e3Sopenharmony_ci break; 2594514f5e3Sopenharmony_ci case Scale::S: 2604514f5e3Sopenharmony_ci opc = ispair ? 0 : 1; 2614514f5e3Sopenharmony_ci break; 2624514f5e3Sopenharmony_ci case Scale::D: 2634514f5e3Sopenharmony_ci opc = 1; 2644514f5e3Sopenharmony_ci break; 2654514f5e3Sopenharmony_ci case Scale::Q: 2664514f5e3Sopenharmony_ci // 3 : means opc bit is 11 2674514f5e3Sopenharmony_ci opc = ispair ? 1 : 3; 2684514f5e3Sopenharmony_ci break; 2694514f5e3Sopenharmony_ci default: 2704514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2714514f5e3Sopenharmony_ci UNREACHABLE(); 2724514f5e3Sopenharmony_ci } 2734514f5e3Sopenharmony_ci 2744514f5e3Sopenharmony_ci return (opc << LDP_STP_Opc_LOWBITS) & LDP_STP_Opc_MASK; 2754514f5e3Sopenharmony_ci} 2764514f5e3Sopenharmony_ci 2774514f5e3Sopenharmony_civoid AssemblerAarch64::Ldr(const Register &rt, const MemoryOperand &operand, Scale scale) 2784514f5e3Sopenharmony_ci{ 2794514f5e3Sopenharmony_ci bool regX = !rt.IsW(); 2804514f5e3Sopenharmony_ci uint32_t op = GetOpcodeOfLdr(operand, scale); 2814514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 2824514f5e3Sopenharmony_ci uint64_t imm = GetImmOfLdr(operand, scale, regX); 2834514f5e3Sopenharmony_ci bool isSigned = operand.GetAddrMode() != AddrMode::OFFSET; 2844514f5e3Sopenharmony_ci // 30: 30bit indicate the size of LDR Reg, and Ldrb and Ldrh do not need it 2854514f5e3Sopenharmony_ci uint32_t instructionCode = ((regX && (scale == Scale::Q)) << 30) | op | LoadAndStoreImm(imm, isSigned) | 2864514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 2874514f5e3Sopenharmony_ci EmitU32(instructionCode); 2884514f5e3Sopenharmony_ci } else { 2894514f5e3Sopenharmony_ci ASSERT(operand.GetExtendOption() != Extend::NO_EXTEND); 2904514f5e3Sopenharmony_ci uint32_t shift = GetShiftOfLdr(operand, scale, regX); 2914514f5e3Sopenharmony_ci Register rm = operand.GetRegisterOffset(); 2924514f5e3Sopenharmony_ci Register rn = operand.GetRegBase(); 2934514f5e3Sopenharmony_ci uint32_t extendField = 2944514f5e3Sopenharmony_ci (operand.GetExtendOption() << LDR_STR_Extend_LOWBITS) & LDR_STR_Extend_MASK; 2954514f5e3Sopenharmony_ci uint32_t shiftField = (shift << LDR_STR_S_LOWBITS) & LDR_STR_S_MASK; 2964514f5e3Sopenharmony_ci // 30: 30bit indicate the size of LDR Reg, and Ldrb and Ldrh do not need it 2974514f5e3Sopenharmony_ci uint32_t instructionCode = ((regX && (scale == Scale::Q)) << 30) | op | Rm(rm.GetId()) | 2984514f5e3Sopenharmony_ci extendField | shiftField | Rn(rn.GetId()) | Rt(rt.GetId()); 2994514f5e3Sopenharmony_ci EmitU32(instructionCode); 3004514f5e3Sopenharmony_ci } 3014514f5e3Sopenharmony_ci} 3024514f5e3Sopenharmony_ci 3034514f5e3Sopenharmony_civoid AssemblerAarch64::Ldr(const Register &rt, const MemoryOperand &operand) 3044514f5e3Sopenharmony_ci{ 3054514f5e3Sopenharmony_ci Ldr(rt, operand, Scale::Q); 3064514f5e3Sopenharmony_ci} 3074514f5e3Sopenharmony_ci 3084514f5e3Sopenharmony_civoid AssemblerAarch64::Ldrh(const Register &rt, const MemoryOperand &operand) 3094514f5e3Sopenharmony_ci{ 3104514f5e3Sopenharmony_ci ASSERT(rt.IsW()); 3114514f5e3Sopenharmony_ci Ldr(rt, operand, Scale::H); 3124514f5e3Sopenharmony_ci} 3134514f5e3Sopenharmony_ci 3144514f5e3Sopenharmony_civoid AssemblerAarch64::Ldrb(const Register &rt, const MemoryOperand &operand) 3154514f5e3Sopenharmony_ci{ 3164514f5e3Sopenharmony_ci ASSERT(rt.IsW()); 3174514f5e3Sopenharmony_ci Ldr(rt, operand, Scale::B); 3184514f5e3Sopenharmony_ci} 3194514f5e3Sopenharmony_ci 3204514f5e3Sopenharmony_civoid AssemblerAarch64::Str(const Register &rt, const MemoryOperand &operand) 3214514f5e3Sopenharmony_ci{ 3224514f5e3Sopenharmony_ci uint32_t op = 0; 3234514f5e3Sopenharmony_ci bool regX = !rt.IsW(); 3244514f5e3Sopenharmony_ci bool isSigned = true; 3254514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 3264514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 3274514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 3284514f5e3Sopenharmony_ci case OFFSET: 3294514f5e3Sopenharmony_ci op = LoadStoreOpCode::STR_Offset; 3304514f5e3Sopenharmony_ci if (regX) { 3314514f5e3Sopenharmony_ci imm >>= 3; // 3: 64 RegSise, imm/8 to remove trailing zeros 3324514f5e3Sopenharmony_ci } else { 3334514f5e3Sopenharmony_ci imm >>= 2; // 2: 32 RegSise, imm/4 to remove trailing zeros 3344514f5e3Sopenharmony_ci } 3354514f5e3Sopenharmony_ci isSigned = false; 3364514f5e3Sopenharmony_ci break; 3374514f5e3Sopenharmony_ci case PREINDEX: 3384514f5e3Sopenharmony_ci op = LoadStoreOpCode::STR_Pre; 3394514f5e3Sopenharmony_ci break; 3404514f5e3Sopenharmony_ci case POSTINDEX: 3414514f5e3Sopenharmony_ci op = LoadStoreOpCode::STR_Post; 3424514f5e3Sopenharmony_ci break; 3434514f5e3Sopenharmony_ci default: 3444514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 3454514f5e3Sopenharmony_ci UNREACHABLE(); 3464514f5e3Sopenharmony_ci } 3474514f5e3Sopenharmony_ci // 30: 30bit indicate the size of LDR Reg 3484514f5e3Sopenharmony_ci uint32_t instructionCode = (regX << 30) | op | LoadAndStoreImm(imm, isSigned) | 3494514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 3504514f5e3Sopenharmony_ci EmitU32(instructionCode); 3514514f5e3Sopenharmony_ci return; 3524514f5e3Sopenharmony_ci } 3534514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 3544514f5e3Sopenharmony_ci UNREACHABLE(); 3554514f5e3Sopenharmony_ci} 3564514f5e3Sopenharmony_ci 3574514f5e3Sopenharmony_civoid AssemblerAarch64::Ldur(const Register &rt, const MemoryOperand &operand) 3584514f5e3Sopenharmony_ci{ 3594514f5e3Sopenharmony_ci bool regX = !rt.IsW(); 3604514f5e3Sopenharmony_ci uint32_t op = LDUR_Offset; 3614514f5e3Sopenharmony_ci ASSERT(operand.IsImmediateOffset()); 3624514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 3634514f5e3Sopenharmony_ci // 30: 30bit indicate the size of LDUR Reg 3644514f5e3Sopenharmony_ci uint32_t instructionCode = (regX << 30) | op | LoadAndStoreImm(imm, true) | 3654514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 3664514f5e3Sopenharmony_ci EmitU32(instructionCode); 3674514f5e3Sopenharmony_ci} 3684514f5e3Sopenharmony_ci 3694514f5e3Sopenharmony_civoid AssemblerAarch64::Stur(const Register &rt, const MemoryOperand &operand) 3704514f5e3Sopenharmony_ci{ 3714514f5e3Sopenharmony_ci bool regX = !rt.IsW(); 3724514f5e3Sopenharmony_ci uint32_t op = STUR_Offset; 3734514f5e3Sopenharmony_ci ASSERT(operand.IsImmediateOffset()); 3744514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 3754514f5e3Sopenharmony_ci // 30: 30bit indicate the size of LDUR Reg 3764514f5e3Sopenharmony_ci uint32_t instructionCode = (regX << 30) | op | LoadAndStoreImm(imm, true) | 3774514f5e3Sopenharmony_ci Rn(operand.GetRegBase().GetId()) | Rt(rt.GetId()); 3784514f5e3Sopenharmony_ci EmitU32(instructionCode); 3794514f5e3Sopenharmony_ci} 3804514f5e3Sopenharmony_ci 3814514f5e3Sopenharmony_civoid AssemblerAarch64::Mov(const Register &rd, const Immediate &imm) 3824514f5e3Sopenharmony_ci{ 3834514f5e3Sopenharmony_ci ASSERT_PRINT(!rd.IsSp(), "sp can't load immediate, please use add instruction"); 3844514f5e3Sopenharmony_ci const unsigned int HWORDSIZE = 16; 3854514f5e3Sopenharmony_ci uint64_t immValue = static_cast<uint64_t>(imm.Value()); 3864514f5e3Sopenharmony_ci unsigned int allOneHalfWords = 0; 3874514f5e3Sopenharmony_ci unsigned int allZeroHalfWords = 0; 3884514f5e3Sopenharmony_ci unsigned int regSize = rd.IsW() ? RegWSize : RegXSize; 3894514f5e3Sopenharmony_ci unsigned int halfWords = regSize / HWORDSIZE; 3904514f5e3Sopenharmony_ci 3914514f5e3Sopenharmony_ci for (unsigned int shift = 0; shift < regSize; shift += HWORDSIZE) { 3924514f5e3Sopenharmony_ci const unsigned int halfWord = (immValue >> shift) & HWORD_MASK; 3934514f5e3Sopenharmony_ci if (halfWord == HWORD_MASK) { 3944514f5e3Sopenharmony_ci allOneHalfWords++; 3954514f5e3Sopenharmony_ci } else if (halfWord == 0) { 3964514f5e3Sopenharmony_ci allZeroHalfWords++; 3974514f5e3Sopenharmony_ci } 3984514f5e3Sopenharmony_ci } 3994514f5e3Sopenharmony_ci // use movz/movn over ORR. 4004514f5e3Sopenharmony_ci if (((halfWords - allOneHalfWords) <= 1) && ((halfWords - allZeroHalfWords) <= 1)) { 4014514f5e3Sopenharmony_ci EmitMovInstruct(rd, immValue, allOneHalfWords, allZeroHalfWords); 4024514f5e3Sopenharmony_ci return; 4034514f5e3Sopenharmony_ci } 4044514f5e3Sopenharmony_ci // Try a single ORR. 4054514f5e3Sopenharmony_ci uint64_t realImm = immValue << (RegXSize - regSize) >> (RegXSize - regSize); 4064514f5e3Sopenharmony_ci LogicalImmediate orrImm = LogicalImmediate::Create(realImm, regSize); 4074514f5e3Sopenharmony_ci if (orrImm.IsValid()) { 4084514f5e3Sopenharmony_ci Orr(rd, Register(Zero), orrImm); 4094514f5e3Sopenharmony_ci return; 4104514f5e3Sopenharmony_ci } 4114514f5e3Sopenharmony_ci // 2: One to up three instruction sequence. 4124514f5e3Sopenharmony_ci if (allOneHalfWords >= (halfWords - 2) || allZeroHalfWords >= (halfWords - 2)) { 4134514f5e3Sopenharmony_ci EmitMovInstruct(rd, immValue, allOneHalfWords, allZeroHalfWords); 4144514f5e3Sopenharmony_ci return; 4154514f5e3Sopenharmony_ci } 4164514f5e3Sopenharmony_ci ASSERT_PRINT(regSize == RegXSize, "all 32-bit Immediate will be transformed with a MOVZ/MOVK pair"); 4174514f5e3Sopenharmony_ci 4184514f5e3Sopenharmony_ci for (unsigned int shift = 0; shift < regSize; shift += HWORDSIZE) { 4194514f5e3Sopenharmony_ci uint64_t shiftedMask = (HWORD_MASK << shift); 4204514f5e3Sopenharmony_ci uint64_t zeroChunk = realImm & ~shiftedMask; 4214514f5e3Sopenharmony_ci uint64_t oneChunk = realImm | shiftedMask; 4224514f5e3Sopenharmony_ci uint64_t rotatedImm = (realImm << 32) | (realImm >> 32); 4234514f5e3Sopenharmony_ci uint64_t replicateChunk = zeroChunk | (rotatedImm & shiftedMask); 4244514f5e3Sopenharmony_ci LogicalImmediate zeroImm = LogicalImmediate::Create(zeroChunk, regSize); 4254514f5e3Sopenharmony_ci LogicalImmediate oneImm = LogicalImmediate::Create(oneChunk, regSize); 4264514f5e3Sopenharmony_ci LogicalImmediate replicateImm = LogicalImmediate::Create(replicateChunk, regSize); 4274514f5e3Sopenharmony_ci if (!zeroImm.IsValid() && !oneImm.IsValid() && !replicateImm.IsValid()) { 4284514f5e3Sopenharmony_ci continue; 4294514f5e3Sopenharmony_ci } 4304514f5e3Sopenharmony_ci 4314514f5e3Sopenharmony_ci if (zeroImm.IsValid()) { 4324514f5e3Sopenharmony_ci Orr(rd, Register(Zero), zeroImm); 4334514f5e3Sopenharmony_ci } else if (oneImm.IsValid()) { 4344514f5e3Sopenharmony_ci Orr(rd, Register(Zero), oneImm); 4354514f5e3Sopenharmony_ci } else { 4364514f5e3Sopenharmony_ci Orr(rd, Register(Zero), replicateImm); 4374514f5e3Sopenharmony_ci } 4384514f5e3Sopenharmony_ci const uint64_t movkImm = (realImm & shiftedMask) >> shift; 4394514f5e3Sopenharmony_ci Movk(rd, movkImm, shift); 4404514f5e3Sopenharmony_ci return; 4414514f5e3Sopenharmony_ci } 4424514f5e3Sopenharmony_ci 4434514f5e3Sopenharmony_ci if (allOneHalfWords || allZeroHalfWords) { 4444514f5e3Sopenharmony_ci EmitMovInstruct(rd, immValue, allOneHalfWords, allZeroHalfWords); 4454514f5e3Sopenharmony_ci return; 4464514f5e3Sopenharmony_ci } 4474514f5e3Sopenharmony_ci 4484514f5e3Sopenharmony_ci if (regSize == RegXSize && TryReplicateHWords(rd, realImm)) { 4494514f5e3Sopenharmony_ci return; 4504514f5e3Sopenharmony_ci } 4514514f5e3Sopenharmony_ci 4524514f5e3Sopenharmony_ci if (regSize == RegXSize && TrySequenceOfOnes(rd, realImm)) { 4534514f5e3Sopenharmony_ci return; 4544514f5e3Sopenharmony_ci } 4554514f5e3Sopenharmony_ci EmitMovInstruct(rd, immValue, allOneHalfWords, allZeroHalfWords); 4564514f5e3Sopenharmony_ci return; 4574514f5e3Sopenharmony_ci} 4584514f5e3Sopenharmony_ci 4594514f5e3Sopenharmony_civoid AssemblerAarch64::Mov(const Register &rd, const Register &rm) 4604514f5e3Sopenharmony_ci{ 4614514f5e3Sopenharmony_ci if (rd.IsSp() || rm.IsSp()) { 4624514f5e3Sopenharmony_ci Add(rd, rm, Operand(Immediate(0))); 4634514f5e3Sopenharmony_ci } else { 4644514f5e3Sopenharmony_ci Orr(rd, Register(Zero), Operand(rm)); 4654514f5e3Sopenharmony_ci } 4664514f5e3Sopenharmony_ci} 4674514f5e3Sopenharmony_ci 4684514f5e3Sopenharmony_ci/// Check whether this chunk matches the pattern '1...0...'. This pattern 4694514f5e3Sopenharmony_ci/// starts a contiguous sequence of ones if we look at the bits from the LSB 4704514f5e3Sopenharmony_ci/// towards the MSB. 4714514f5e3Sopenharmony_cistatic bool IsStartHWord(uint64_t hWord) 4724514f5e3Sopenharmony_ci{ 4734514f5e3Sopenharmony_ci if (hWord == 0 || hWord == std::numeric_limits<uint64_t>::max()) { 4744514f5e3Sopenharmony_ci return false; 4754514f5e3Sopenharmony_ci } 4764514f5e3Sopenharmony_ci return IsMask_64(~hWord); 4774514f5e3Sopenharmony_ci} 4784514f5e3Sopenharmony_ci 4794514f5e3Sopenharmony_ci/// Check whether this chunk matches the pattern '0...1...' This pattern 4804514f5e3Sopenharmony_ci/// ends a contiguous sequence of ones if we look at the bits from the LSB 4814514f5e3Sopenharmony_ci/// towards the MSB. 4824514f5e3Sopenharmony_cistatic bool IsEndHWord(uint64_t hWord) 4834514f5e3Sopenharmony_ci{ 4844514f5e3Sopenharmony_ci if (hWord == 0 || hWord == std::numeric_limits<uint64_t>::max()) { 4854514f5e3Sopenharmony_ci return false; 4864514f5e3Sopenharmony_ci } 4874514f5e3Sopenharmony_ci return IsMask_64(hWord); 4884514f5e3Sopenharmony_ci} 4894514f5e3Sopenharmony_ci 4904514f5e3Sopenharmony_ci/// Clear or set all bits in the chunk at the given index. 4914514f5e3Sopenharmony_cistatic uint64_t UpdateImm(uint64_t imm, unsigned idx, bool clear) 4924514f5e3Sopenharmony_ci{ 4934514f5e3Sopenharmony_ci if (clear) { 4944514f5e3Sopenharmony_ci // Clear chunk in the immediate. 4954514f5e3Sopenharmony_ci imm &= ~(HWORD_MASK << idx); 4964514f5e3Sopenharmony_ci } else { 4974514f5e3Sopenharmony_ci // Set all bits in the immediate for the particular chunk. 4984514f5e3Sopenharmony_ci imm |= HWORD_MASK << idx; 4994514f5e3Sopenharmony_ci } 5004514f5e3Sopenharmony_ci return imm; 5014514f5e3Sopenharmony_ci} 5024514f5e3Sopenharmony_ci 5034514f5e3Sopenharmony_cibool AssemblerAarch64::TrySequenceOfOnes(const Register &rd, uint64_t imm) 5044514f5e3Sopenharmony_ci{ 5054514f5e3Sopenharmony_ci const int HWORDSIZE = 16; 5064514f5e3Sopenharmony_ci int startIdx = -1; 5074514f5e3Sopenharmony_ci int endIdx = -1; 5084514f5e3Sopenharmony_ci // Try to find the chunks which start/end a contiguous sequence of ones. 5094514f5e3Sopenharmony_ci for (int shift = 0; shift < RegXSize; shift += HWORDSIZE) { 5104514f5e3Sopenharmony_ci int64_t himm = (imm >> shift) & HWORD_MASK; 5114514f5e3Sopenharmony_ci // Sign extend the 16-bit chunk to 64-bit. 5124514f5e3Sopenharmony_ci // 48 : 48 means RegXSize - HWORDSIZE 5134514f5e3Sopenharmony_ci himm = (himm << 48) >> 48; 5144514f5e3Sopenharmony_ci 5154514f5e3Sopenharmony_ci if (IsStartHWord(himm)) { 5164514f5e3Sopenharmony_ci startIdx = shift; 5174514f5e3Sopenharmony_ci } else if (IsEndHWord(static_cast<uint64_t>(himm))) { 5184514f5e3Sopenharmony_ci endIdx = shift; 5194514f5e3Sopenharmony_ci } 5204514f5e3Sopenharmony_ci } 5214514f5e3Sopenharmony_ci // Early exit in case we can't find a start/end chunk. 5224514f5e3Sopenharmony_ci if (startIdx == -1 || endIdx == -1) { 5234514f5e3Sopenharmony_ci return false; 5244514f5e3Sopenharmony_ci } 5254514f5e3Sopenharmony_ci // Outside of the contiguous sequence of ones everything needs to be zero. 5264514f5e3Sopenharmony_ci uint64_t outside = 0; 5274514f5e3Sopenharmony_ci // Chunks between the start and end chunk need to have all their bits set. 5284514f5e3Sopenharmony_ci uint64_t inside = HWORD_MASK; 5294514f5e3Sopenharmony_ci 5304514f5e3Sopenharmony_ci // If our contiguous sequence of ones wraps around from the MSB into the LSB, 5314514f5e3Sopenharmony_ci // just swap indices and pretend we are materializing a contiguous sequence 5324514f5e3Sopenharmony_ci // of zeros surrounded by a contiguous sequence of ones. 5334514f5e3Sopenharmony_ci if (startIdx > endIdx) { 5344514f5e3Sopenharmony_ci std::swap(startIdx, endIdx); 5354514f5e3Sopenharmony_ci std::swap(outside, inside); 5364514f5e3Sopenharmony_ci } 5374514f5e3Sopenharmony_ci 5384514f5e3Sopenharmony_ci uint64_t orrImm = imm; 5394514f5e3Sopenharmony_ci int firstMovkShift = -1; 5404514f5e3Sopenharmony_ci int secondMovkShift = -1; 5414514f5e3Sopenharmony_ci for (int shift = 0; shift < RegXSize; shift += HWORDSIZE) { 5424514f5e3Sopenharmony_ci uint64_t himm = (imm >> shift) & HWORD_MASK; 5434514f5e3Sopenharmony_ci // Check whether we are looking at a chunk which is not part of the 5444514f5e3Sopenharmony_ci // contiguous sequence of ones. 5454514f5e3Sopenharmony_ci if ((shift < startIdx || endIdx < shift) && himm != outside) { 5464514f5e3Sopenharmony_ci orrImm = UpdateImm(orrImm, shift, outside == 0); 5474514f5e3Sopenharmony_ci if (firstMovkShift == -1) { 5484514f5e3Sopenharmony_ci firstMovkShift = shift; 5494514f5e3Sopenharmony_ci } else { 5504514f5e3Sopenharmony_ci secondMovkShift = shift; 5514514f5e3Sopenharmony_ci } 5524514f5e3Sopenharmony_ci } else if (shift > startIdx && shift < endIdx && himm != inside) { 5534514f5e3Sopenharmony_ci orrImm = UpdateImm(orrImm, shift, outside == 0); 5544514f5e3Sopenharmony_ci if (firstMovkShift == -1) { 5554514f5e3Sopenharmony_ci firstMovkShift = shift; 5564514f5e3Sopenharmony_ci } else { 5574514f5e3Sopenharmony_ci secondMovkShift = shift; 5584514f5e3Sopenharmony_ci } 5594514f5e3Sopenharmony_ci } 5604514f5e3Sopenharmony_ci } 5614514f5e3Sopenharmony_ci ASSERT_PRINT(firstMovkShift != -1, "constant materializable with single orr!"); 5624514f5e3Sopenharmony_ci Orr(rd, rd, LogicalImmediate::Create(orrImm, RegXSize)); 5634514f5e3Sopenharmony_ci Movk(rd, (imm >> firstMovkShift) & HWORD_MASK, firstMovkShift); 5644514f5e3Sopenharmony_ci if (secondMovkShift != -1) { 5654514f5e3Sopenharmony_ci Movk(rd, (imm >> secondMovkShift) & HWORD_MASK, secondMovkShift); 5664514f5e3Sopenharmony_ci } 5674514f5e3Sopenharmony_ci return true; 5684514f5e3Sopenharmony_ci} 5694514f5e3Sopenharmony_ci 5704514f5e3Sopenharmony_cibool AssemblerAarch64::TryReplicateHWords(const Register &rd, uint64_t imm) 5714514f5e3Sopenharmony_ci{ 5724514f5e3Sopenharmony_ci const int HWORDSIZE = 16; 5734514f5e3Sopenharmony_ci std::map<uint64_t, int> repeatMaps; 5744514f5e3Sopenharmony_ci for (int idx = 0; idx < RegXSize; idx += HWORDSIZE) { 5754514f5e3Sopenharmony_ci uint64_t halfWord = (imm >> idx) & HWORD_MASK; 5764514f5e3Sopenharmony_ci if (repeatMaps.find(halfWord) != repeatMaps.end()) { 5774514f5e3Sopenharmony_ci repeatMaps[halfWord] += 1; 5784514f5e3Sopenharmony_ci } else { 5794514f5e3Sopenharmony_ci repeatMaps[halfWord] = 1; 5804514f5e3Sopenharmony_ci } 5814514f5e3Sopenharmony_ci } 5824514f5e3Sopenharmony_ci for (auto iter : repeatMaps) { 5834514f5e3Sopenharmony_ci const uint64_t hImm = iter.first; 5844514f5e3Sopenharmony_ci const int count = iter.second; 5854514f5e3Sopenharmony_ci uint64_t repeatImm = hImm | (hImm << 16) | (hImm << 32) | (hImm << 48); 5864514f5e3Sopenharmony_ci LogicalImmediate orrImm = LogicalImmediate::Create(repeatImm, 64); 5874514f5e3Sopenharmony_ci // if orrImm not valid, repeat count can't be 2 or 3, it can't be simplified with orr. 5884514f5e3Sopenharmony_ci if ((count != 2 && count != 3) || orrImm.IsValid()) { 5894514f5e3Sopenharmony_ci continue; 5904514f5e3Sopenharmony_ci } 5914514f5e3Sopenharmony_ci Orr(rd, rd, orrImm); 5924514f5e3Sopenharmony_ci int shift = 0; 5934514f5e3Sopenharmony_ci uint64_t imm16 = 0; 5944514f5e3Sopenharmony_ci // Find the first chunk not materialized with the ORR instruction. 5954514f5e3Sopenharmony_ci for (; shift < RegXSize; shift += HWORDSIZE) { 5964514f5e3Sopenharmony_ci imm16 = (imm >> shift) & HWORD_MASK; 5974514f5e3Sopenharmony_ci if (imm16 != hImm) { 5984514f5e3Sopenharmony_ci break; 5994514f5e3Sopenharmony_ci } 6004514f5e3Sopenharmony_ci } 6014514f5e3Sopenharmony_ci // Create the first MOVK instruction. 6024514f5e3Sopenharmony_ci Movk(rd, imm16, shift); 6034514f5e3Sopenharmony_ci // 3 : 3 means repeat 3 times, Imm encode has been done. 6044514f5e3Sopenharmony_ci if (count == 3) { 6054514f5e3Sopenharmony_ci return true; 6064514f5e3Sopenharmony_ci } 6074514f5e3Sopenharmony_ci // Find the remaining chunk which needs to be materialized. 6084514f5e3Sopenharmony_ci for (shift += HWORDSIZE; shift < RegXSize; shift += HWORDSIZE) { 6094514f5e3Sopenharmony_ci imm16 = (imm >> shift) & HWORD_MASK; 6104514f5e3Sopenharmony_ci if (imm16 != hImm) { 6114514f5e3Sopenharmony_ci break; 6124514f5e3Sopenharmony_ci } 6134514f5e3Sopenharmony_ci } 6144514f5e3Sopenharmony_ci Movk(rd, imm16, shift); 6154514f5e3Sopenharmony_ci return true; 6164514f5e3Sopenharmony_ci } 6174514f5e3Sopenharmony_ci return false; 6184514f5e3Sopenharmony_ci} 6194514f5e3Sopenharmony_ci 6204514f5e3Sopenharmony_civoid AssemblerAarch64::EmitMovInstruct(const Register &rd, uint64_t imm, 6214514f5e3Sopenharmony_ci unsigned int allOneHWords, unsigned int allZeroHWords) 6224514f5e3Sopenharmony_ci{ 6234514f5e3Sopenharmony_ci bool isNeg = false; 6244514f5e3Sopenharmony_ci if (allOneHWords > allZeroHWords) { 6254514f5e3Sopenharmony_ci isNeg = true; 6264514f5e3Sopenharmony_ci imm = ~imm; 6274514f5e3Sopenharmony_ci } 6284514f5e3Sopenharmony_ci int firstshift = 0; // LSL amount for high bits with MOVZ/MOVN 6294514f5e3Sopenharmony_ci int lastshift = 0; // LSL amount for last MOVK 6304514f5e3Sopenharmony_ci if (imm != 0) { 6314514f5e3Sopenharmony_ci int lz = static_cast<int>(CountLeadingZeros64(imm)); 6324514f5e3Sopenharmony_ci int tz = static_cast<int>(CountTrailingZeros64(imm)); 6334514f5e3Sopenharmony_ci firstshift = (tz / 16) * 16; // 16 : 16 means the operand of MOVK/N/Z is 16 bits Immediate 6344514f5e3Sopenharmony_ci // 63 : 63 means the topmost bits of RegXSize 6354514f5e3Sopenharmony_ci lastshift = ((63 - lz) / 16) * 16; // 16 : 16 means the operand of MOVK/N/Z is 16 bits Immediate 6364514f5e3Sopenharmony_ci } 6374514f5e3Sopenharmony_ci uint64_t imm16 = (imm >> firstshift) & HWORD_MASK; 6384514f5e3Sopenharmony_ci if (isNeg) { 6394514f5e3Sopenharmony_ci Movn(rd, imm16, firstshift); 6404514f5e3Sopenharmony_ci imm = ~imm; 6414514f5e3Sopenharmony_ci } else { 6424514f5e3Sopenharmony_ci Movz(rd, imm16, firstshift); 6434514f5e3Sopenharmony_ci } 6444514f5e3Sopenharmony_ci if (firstshift == lastshift) { 6454514f5e3Sopenharmony_ci return; 6464514f5e3Sopenharmony_ci } 6474514f5e3Sopenharmony_ci while (firstshift < lastshift) { 6484514f5e3Sopenharmony_ci firstshift += 16; // 16 : 16 means the operand of MOVK is 16 bits Immediate 6494514f5e3Sopenharmony_ci imm16 = (imm >> firstshift) & HWORD_MASK; 6504514f5e3Sopenharmony_ci if (imm16 == (isNeg ? HWORD_MASK : 0)) { 6514514f5e3Sopenharmony_ci // skip movk because initial value is already set correctly. 6524514f5e3Sopenharmony_ci continue; 6534514f5e3Sopenharmony_ci } 6544514f5e3Sopenharmony_ci Movk(rd, imm16, firstshift); 6554514f5e3Sopenharmony_ci } 6564514f5e3Sopenharmony_ci} 6574514f5e3Sopenharmony_ci 6584514f5e3Sopenharmony_civoid AssemblerAarch64::Movz(const Register &rd, uint64_t imm, int shift) 6594514f5e3Sopenharmony_ci{ 6604514f5e3Sopenharmony_ci MovWide(MoveOpCode::MOVZ, rd, imm, shift); 6614514f5e3Sopenharmony_ci} 6624514f5e3Sopenharmony_ci 6634514f5e3Sopenharmony_civoid AssemblerAarch64::Movk(const Register &rd, uint64_t imm, int shift) 6644514f5e3Sopenharmony_ci{ 6654514f5e3Sopenharmony_ci MovWide(MoveOpCode::MOVK, rd, imm, shift); 6664514f5e3Sopenharmony_ci} 6674514f5e3Sopenharmony_ci 6684514f5e3Sopenharmony_civoid AssemblerAarch64::Movn(const Register &rd, uint64_t imm, int shift) 6694514f5e3Sopenharmony_ci{ 6704514f5e3Sopenharmony_ci MovWide(MoveOpCode::MOVN, rd, imm, shift); 6714514f5e3Sopenharmony_ci} 6724514f5e3Sopenharmony_ci 6734514f5e3Sopenharmony_civoid AssemblerAarch64::MovWide(uint32_t op, const Register &rd, uint64_t imm, int shift) 6744514f5e3Sopenharmony_ci{ 6754514f5e3Sopenharmony_ci uint32_t imm_field = (imm << MOV_WIDE_Imm16_LOWBITS) & MOV_WIDE_Imm16_MASK; 6764514f5e3Sopenharmony_ci uint32_t hw_field = ((shift / 16) << MOV_WIDE_Hw_LOWBITS) & MOV_WIDE_Hw_MASK; 6774514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | op | imm_field | hw_field | Rd(rd.GetId()); 6784514f5e3Sopenharmony_ci EmitU32(code); 6794514f5e3Sopenharmony_ci} 6804514f5e3Sopenharmony_ci 6814514f5e3Sopenharmony_ci 6824514f5e3Sopenharmony_civoid AssemblerAarch64::Orr(const Register &rd, const Register &rn, const LogicalImmediate &imm) 6834514f5e3Sopenharmony_ci{ 6844514f5e3Sopenharmony_ci BitWiseOpImm(ORR_Imm, rd, rn, imm.Value()); 6854514f5e3Sopenharmony_ci} 6864514f5e3Sopenharmony_ci 6874514f5e3Sopenharmony_civoid AssemblerAarch64::And(const Register &rd, const Register &rn, const LogicalImmediate &imm) 6884514f5e3Sopenharmony_ci{ 6894514f5e3Sopenharmony_ci BitWiseOpImm(AND_Imm, rd, rn, imm.Value()); 6904514f5e3Sopenharmony_ci} 6914514f5e3Sopenharmony_ci 6924514f5e3Sopenharmony_civoid AssemblerAarch64::Ands(const Register &rd, const Register &rn, const LogicalImmediate &imm) 6934514f5e3Sopenharmony_ci{ 6944514f5e3Sopenharmony_ci BitWiseOpImm(ANDS_Imm, rd, rn, imm.Value()); 6954514f5e3Sopenharmony_ci} 6964514f5e3Sopenharmony_ci 6974514f5e3Sopenharmony_civoid AssemblerAarch64::Orr(const Register &rd, const Register &rn, const Operand &operand) 6984514f5e3Sopenharmony_ci{ 6994514f5e3Sopenharmony_ci ASSERT(operand.IsShifted()); 7004514f5e3Sopenharmony_ci BitWiseOpShift(ORR_Shift, rd, rn, operand); 7014514f5e3Sopenharmony_ci} 7024514f5e3Sopenharmony_ci 7034514f5e3Sopenharmony_civoid AssemblerAarch64::And(const Register &rd, const Register &rn, const Operand &operand) 7044514f5e3Sopenharmony_ci{ 7054514f5e3Sopenharmony_ci ASSERT(operand.IsShifted()); 7064514f5e3Sopenharmony_ci BitWiseOpShift(AND_Shift, rd, rn, operand); 7074514f5e3Sopenharmony_ci} 7084514f5e3Sopenharmony_ci 7094514f5e3Sopenharmony_civoid AssemblerAarch64::Ands(const Register &rd, const Register &rn, const Operand &operand) 7104514f5e3Sopenharmony_ci{ 7114514f5e3Sopenharmony_ci ASSERT(operand.IsShifted()); 7124514f5e3Sopenharmony_ci BitWiseOpShift(ANDS_Shift, rd, rn, operand); 7134514f5e3Sopenharmony_ci} 7144514f5e3Sopenharmony_ci 7154514f5e3Sopenharmony_civoid AssemblerAarch64::BitWiseOpImm(BitwiseOpCode op, const Register &rd, const Register &rn, uint64_t imm) 7164514f5e3Sopenharmony_ci{ 7174514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | op | imm | Rn(rn.GetId()) | Rd(rd.GetId()); 7184514f5e3Sopenharmony_ci EmitU32(code); 7194514f5e3Sopenharmony_ci} 7204514f5e3Sopenharmony_ci 7214514f5e3Sopenharmony_civoid AssemblerAarch64::BitWiseOpShift(BitwiseOpCode op, const Register &rd, const Register &rn, const Operand &operand) 7224514f5e3Sopenharmony_ci{ 7234514f5e3Sopenharmony_ci uint32_t shift_field = (operand.GetShiftOption() << BITWISE_OP_Shift_LOWBITS) & BITWISE_OP_Shift_MASK; 7244514f5e3Sopenharmony_ci uint32_t shift_amount = (operand.GetShiftAmount() << BITWISE_OP_ShiftAmount_LOWBITS) & BITWISE_OP_ShiftAmount_MASK; 7254514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | op | shift_field | Rm(operand.Reg().GetId()) | 7264514f5e3Sopenharmony_ci shift_amount | Rn(rn.GetId()) | Rd(rd.GetId()); 7274514f5e3Sopenharmony_ci EmitU32(code); 7284514f5e3Sopenharmony_ci} 7294514f5e3Sopenharmony_ci 7304514f5e3Sopenharmony_civoid AssemblerAarch64::Lsl(const Register &rd, const Register &rn, const Register &rm) 7314514f5e3Sopenharmony_ci{ 7324514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | LSL_Reg | Rm(rm.GetId()) | Rn(rn.GetId()) | Rd(rd.GetId()); 7334514f5e3Sopenharmony_ci EmitU32(code); 7344514f5e3Sopenharmony_ci} 7354514f5e3Sopenharmony_ci 7364514f5e3Sopenharmony_civoid AssemblerAarch64::Lsr(const Register &rd, const Register &rn, const Register &rm) 7374514f5e3Sopenharmony_ci{ 7384514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | LSR_Reg | Rm(rm.GetId()) | Rn(rn.GetId()) | Rd(rd.GetId()); 7394514f5e3Sopenharmony_ci EmitU32(code); 7404514f5e3Sopenharmony_ci} 7414514f5e3Sopenharmony_ci 7424514f5e3Sopenharmony_civoid AssemblerAarch64::Ubfm(const Register &rd, const Register &rn, unsigned immr, unsigned imms) 7434514f5e3Sopenharmony_ci{ 7444514f5e3Sopenharmony_ci bool sf = !rd.IsW(); 7454514f5e3Sopenharmony_ci uint32_t n = (sf << BITWISE_OP_N_LOWBITS) & BITWISE_OP_N_MASK; 7464514f5e3Sopenharmony_ci uint32_t immr_field = (immr << BITWISE_OP_Immr_LOWBITS) & BITWISE_OP_Immr_MASK; 7474514f5e3Sopenharmony_ci uint32_t imms_field = (imms << BITWISE_OP_Imms_LOWBITS) & BITWISE_OP_Imms_MASK; 7484514f5e3Sopenharmony_ci uint32_t code = Sf(sf) | UBFM | n | immr_field | imms_field | Rn(rn.GetId()) | Rd(rd.GetId()); 7494514f5e3Sopenharmony_ci EmitU32(code); 7504514f5e3Sopenharmony_ci} 7514514f5e3Sopenharmony_ci 7524514f5e3Sopenharmony_civoid AssemblerAarch64::Bfm(const Register &rd, const Register &rn, unsigned immr, unsigned imms) 7534514f5e3Sopenharmony_ci{ 7544514f5e3Sopenharmony_ci bool sf = !rd.IsW(); 7554514f5e3Sopenharmony_ci uint32_t n = (sf << BITWISE_OP_N_LOWBITS) & BITWISE_OP_N_MASK; 7564514f5e3Sopenharmony_ci uint32_t immr_field = (immr << BITWISE_OP_Immr_LOWBITS) & BITWISE_OP_Immr_MASK; 7574514f5e3Sopenharmony_ci uint32_t imms_field = (imms << BITWISE_OP_Imms_LOWBITS) & BITWISE_OP_Imms_MASK; 7584514f5e3Sopenharmony_ci uint32_t code = Sf(sf) | BFM | n | immr_field | imms_field | Rn(rn.GetId()) | Rd(rd.GetId()); 7594514f5e3Sopenharmony_ci EmitU32(code); 7604514f5e3Sopenharmony_ci} 7614514f5e3Sopenharmony_ci 7624514f5e3Sopenharmony_civoid AssemblerAarch64::Lsr(const Register &rd, const Register &rn, unsigned shift) 7634514f5e3Sopenharmony_ci{ 7644514f5e3Sopenharmony_ci unsigned imms = 0; 7654514f5e3Sopenharmony_ci if (rd.IsW()) { 7664514f5e3Sopenharmony_ci imms = 31; // 31 : 31 32-bit variant Applies when sf == 0 && N == 0 && imms == 011111 7674514f5e3Sopenharmony_ci // LSR <Wd>, <Wn>, #<shift> is equivalent to UBFM <Wd>, <Wn>, #<shift>, #31 7684514f5e3Sopenharmony_ci // and is always the preferred disassembly 7694514f5e3Sopenharmony_ci } else { 7704514f5e3Sopenharmony_ci imms = 63; // 63 : 63 64-bit variant Applies when sf == 1 && N == 1 && imms == 111111 7714514f5e3Sopenharmony_ci // LSR <Xd>, <Xn>, #<shift> is equivalent to UBFM <Xd>, <Xn>, #<shift>, #63 7724514f5e3Sopenharmony_ci // and is always the preferred disassembly 7734514f5e3Sopenharmony_ci } 7744514f5e3Sopenharmony_ci Ubfm(rd, rn, shift, imms); 7754514f5e3Sopenharmony_ci} 7764514f5e3Sopenharmony_ci 7774514f5e3Sopenharmony_civoid AssemblerAarch64::Add(const Register &rd, const Register &rn, const Operand &operand) 7784514f5e3Sopenharmony_ci{ 7794514f5e3Sopenharmony_ci if (operand.IsImmediate()) { 7804514f5e3Sopenharmony_ci int64_t imm = static_cast<int64_t>(operand.ImmediateValue()); 7814514f5e3Sopenharmony_ci if (imm < 0) { 7824514f5e3Sopenharmony_ci AddSubImm(SUB_Imm, rd, rn, false, -1 * imm); 7834514f5e3Sopenharmony_ci } else { 7844514f5e3Sopenharmony_ci AddSubImm(ADD_Imm, rd, rn, false, imm); 7854514f5e3Sopenharmony_ci } 7864514f5e3Sopenharmony_ci } else { 7874514f5e3Sopenharmony_ci if (operand.IsShifted()) { 7884514f5e3Sopenharmony_ci AddSubReg(ADD_Shift, rd, rn, false, operand); 7894514f5e3Sopenharmony_ci } else { 7904514f5e3Sopenharmony_ci AddSubReg(ADD_Extend, rd, rn, false, operand); 7914514f5e3Sopenharmony_ci } 7924514f5e3Sopenharmony_ci } 7934514f5e3Sopenharmony_ci} 7944514f5e3Sopenharmony_ci 7954514f5e3Sopenharmony_civoid AssemblerAarch64::Adds(const Register &rd, const Register &rn, const Operand &operand) 7964514f5e3Sopenharmony_ci{ 7974514f5e3Sopenharmony_ci if (operand.IsImmediate()) { 7984514f5e3Sopenharmony_ci AddSubImm(ADD_Imm, rd, rn, true, operand.ImmediateValue()); 7994514f5e3Sopenharmony_ci } else { 8004514f5e3Sopenharmony_ci if (operand.IsShifted()) { 8014514f5e3Sopenharmony_ci AddSubReg(ADD_Shift, rd, rn, true, operand); 8024514f5e3Sopenharmony_ci } else { 8034514f5e3Sopenharmony_ci AddSubReg(ADD_Extend, rd, rn, true, operand); 8044514f5e3Sopenharmony_ci } 8054514f5e3Sopenharmony_ci } 8064514f5e3Sopenharmony_ci} 8074514f5e3Sopenharmony_ci 8084514f5e3Sopenharmony_civoid AssemblerAarch64::Sub(const Register &rd, const Register &rn, const Operand &operand) 8094514f5e3Sopenharmony_ci{ 8104514f5e3Sopenharmony_ci if (operand.IsImmediate()) { 8114514f5e3Sopenharmony_ci int64_t imm = static_cast<int64_t>(operand.ImmediateValue()); 8124514f5e3Sopenharmony_ci if (imm < 0) { 8134514f5e3Sopenharmony_ci AddSubImm(ADD_Imm, rd, rn, false, -1 * imm); 8144514f5e3Sopenharmony_ci } else { 8154514f5e3Sopenharmony_ci AddSubImm(SUB_Imm, rd, rn, false, imm); 8164514f5e3Sopenharmony_ci } 8174514f5e3Sopenharmony_ci } else { 8184514f5e3Sopenharmony_ci if (operand.IsShifted()) { 8194514f5e3Sopenharmony_ci AddSubReg(SUB_Shift, rd, rn, false, operand); 8204514f5e3Sopenharmony_ci } else { 8214514f5e3Sopenharmony_ci AddSubReg(SUB_Extend, rd, rn, false, operand); 8224514f5e3Sopenharmony_ci } 8234514f5e3Sopenharmony_ci } 8244514f5e3Sopenharmony_ci} 8254514f5e3Sopenharmony_ci 8264514f5e3Sopenharmony_civoid AssemblerAarch64::Subs(const Register &rd, const Register &rn, const Operand &operand) 8274514f5e3Sopenharmony_ci{ 8284514f5e3Sopenharmony_ci if (operand.IsImmediate()) { 8294514f5e3Sopenharmony_ci AddSubImm(SUB_Imm, rd, rn, true, operand.ImmediateValue()); 8304514f5e3Sopenharmony_ci } else { 8314514f5e3Sopenharmony_ci if (operand.IsShifted()) { 8324514f5e3Sopenharmony_ci AddSubReg(SUB_Shift, rd, rn, true, operand); 8334514f5e3Sopenharmony_ci } else { 8344514f5e3Sopenharmony_ci AddSubReg(SUB_Extend, rd, rn, true, operand); 8354514f5e3Sopenharmony_ci } 8364514f5e3Sopenharmony_ci } 8374514f5e3Sopenharmony_ci} 8384514f5e3Sopenharmony_ci 8394514f5e3Sopenharmony_cibool AssemblerAarch64::IsAddSubImm(uint64_t imm) 8404514f5e3Sopenharmony_ci{ 8414514f5e3Sopenharmony_ci const uint64_t IMM12_MASK = (1 << ADD_SUB_Imm12_WIDTH) - 1; 8424514f5e3Sopenharmony_ci if (imm <= IMM12_MASK) { 8434514f5e3Sopenharmony_ci return true; 8444514f5e3Sopenharmony_ci } 8454514f5e3Sopenharmony_ci 8464514f5e3Sopenharmony_ci if (((imm & IMM12_MASK) == 0) && ((imm & ~IMM12_MASK) <= IMM12_MASK)) { 8474514f5e3Sopenharmony_ci return true; 8484514f5e3Sopenharmony_ci } 8494514f5e3Sopenharmony_ci return false; 8504514f5e3Sopenharmony_ci} 8514514f5e3Sopenharmony_ci 8524514f5e3Sopenharmony_civoid AssemblerAarch64::AddSubImm(AddSubOpCode op, const Register &rd, const Register &rn, bool setFlags, uint64_t imm) 8534514f5e3Sopenharmony_ci{ 8544514f5e3Sopenharmony_ci ASSERT(IsAddSubImm(imm)); 8554514f5e3Sopenharmony_ci uint32_t shift = 0; 8564514f5e3Sopenharmony_ci const uint64_t IMM12_MASK = (1 << ADD_SUB_Imm12_WIDTH) - 1; 8574514f5e3Sopenharmony_ci uint64_t imm12 = imm & (~IMM12_MASK); 8584514f5e3Sopenharmony_ci if (imm12 != 0) { 8594514f5e3Sopenharmony_ci shift = 1; 8604514f5e3Sopenharmony_ci } else { 8614514f5e3Sopenharmony_ci imm12 = imm; 8624514f5e3Sopenharmony_ci } 8634514f5e3Sopenharmony_ci uint32_t flags_field = ((setFlags ? 1 : 0) << ADD_SUB_S_LOWBITS) & ADD_SUB_S_MASK; 8644514f5e3Sopenharmony_ci uint32_t imm_field = (imm12 << ADD_SUB_Imm12_LOWBITS) & ADD_SUB_Imm12_MASK; 8654514f5e3Sopenharmony_ci uint32_t shift_field = (shift << ADD_SUB_Sh_LOWBITS) & ADD_SUB_Sh_MASK; 8664514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | op | flags_field | shift_field | imm_field | Rd(rd.GetId()) | Rn(rn.GetId()); 8674514f5e3Sopenharmony_ci EmitU32(code); 8684514f5e3Sopenharmony_ci} 8694514f5e3Sopenharmony_ci 8704514f5e3Sopenharmony_civoid AssemblerAarch64::AddSubReg(AddSubOpCode op, const Register &rd, const Register &rn, 8714514f5e3Sopenharmony_ci bool setFlags, const Operand &operand) 8724514f5e3Sopenharmony_ci{ 8734514f5e3Sopenharmony_ci uint32_t flags_field = ((setFlags ? 1 : 0) << ADD_SUB_S_LOWBITS) & ADD_SUB_S_MASK; 8744514f5e3Sopenharmony_ci uint32_t code = 0; 8754514f5e3Sopenharmony_ci if (operand.IsShifted()) { 8764514f5e3Sopenharmony_ci uint32_t shift_field = ((operand.GetShiftOption()) << ADD_SUB_Shift_LOWBITS) & ADD_SUB_Shift_MASK; 8774514f5e3Sopenharmony_ci uint32_t shift_amount = ((operand.GetShiftAmount()) << ADD_SUB_ShiftAmount_LOWBITS) & ADD_SUB_ShiftAmount_MASK; 8784514f5e3Sopenharmony_ci ASSERT((op == ADD_Shift) | (op == SUB_Shift)); 8794514f5e3Sopenharmony_ci code = Sf(!rd.IsW()) | op | flags_field | shift_field | Rm(operand.Reg().GetId()) | 8804514f5e3Sopenharmony_ci shift_amount | Rn(rn.GetId()) | Rd(rd.GetId()); 8814514f5e3Sopenharmony_ci } else { 8824514f5e3Sopenharmony_ci ASSERT((op == ADD_Extend) | (op == SUB_Extend)); 8834514f5e3Sopenharmony_ci uint32_t extend_field = 8844514f5e3Sopenharmony_ci (operand.GetExtendOption() << ADD_SUB_ExtendOption_LOWBITS) & ADD_SUB_ExtendOption_MASK; 8854514f5e3Sopenharmony_ci uint32_t extend_shift = (operand.GetShiftAmount() << ADD_SUB_ExtendShift_LOWBITS) & ADD_SUB_ExtendShift_MASK; 8864514f5e3Sopenharmony_ci code = Sf(!rd.IsW()) | op | flags_field | Rm(operand.Reg().GetId()) | extend_field | 8874514f5e3Sopenharmony_ci extend_shift | Rn(rn.GetId()) | Rd(rd.GetId()); 8884514f5e3Sopenharmony_ci } 8894514f5e3Sopenharmony_ci EmitU32(code); 8904514f5e3Sopenharmony_ci} 8914514f5e3Sopenharmony_ci 8924514f5e3Sopenharmony_civoid AssemblerAarch64::Cmp(const Register &rd, const Operand &operand) 8934514f5e3Sopenharmony_ci{ 8944514f5e3Sopenharmony_ci Subs(Register(Zero, rd.GetType()), rd, operand); 8954514f5e3Sopenharmony_ci} 8964514f5e3Sopenharmony_ci 8974514f5e3Sopenharmony_civoid AssemblerAarch64::CMov(const Register &rd, const Register &rn, const Operand &operand, Condition cond) 8984514f5e3Sopenharmony_ci{ 8994514f5e3Sopenharmony_ci ASSERT(!operand.IsImmediate()); 9004514f5e3Sopenharmony_ci uint32_t cond_field = (cond << CSEL_Cond_LOWBITS) & CSEL_Cond_MASK; 9014514f5e3Sopenharmony_ci uint32_t code = Sf(!rd.IsW()) | CSEL | Rm(operand.Reg().GetId()) | cond_field | Rn(rn.GetId()) | Rd(rd.GetId()); 9024514f5e3Sopenharmony_ci EmitU32(code); 9034514f5e3Sopenharmony_ci} 9044514f5e3Sopenharmony_ci 9054514f5e3Sopenharmony_civoid AssemblerAarch64::B(Label *label) 9064514f5e3Sopenharmony_ci{ 9074514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9084514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9094514f5e3Sopenharmony_ci offsetImm >>= 2; 9104514f5e3Sopenharmony_ci B(offsetImm); 9114514f5e3Sopenharmony_ci} 9124514f5e3Sopenharmony_ci 9134514f5e3Sopenharmony_civoid AssemblerAarch64::B(int32_t imm) 9144514f5e3Sopenharmony_ci{ 9154514f5e3Sopenharmony_ci uint32_t code = BranchOpCode::Branch | ((imm << BRANCH_Imm26_LOWBITS) & BRANCH_Imm26_MASK); 9164514f5e3Sopenharmony_ci EmitU32(code); 9174514f5e3Sopenharmony_ci} 9184514f5e3Sopenharmony_ci 9194514f5e3Sopenharmony_civoid AssemblerAarch64::Br(const Register &rn) 9204514f5e3Sopenharmony_ci{ 9214514f5e3Sopenharmony_ci uint32_t code = BranchOpCode::BR | Rn(rn.GetId()); 9224514f5e3Sopenharmony_ci EmitU32(code); 9234514f5e3Sopenharmony_ci} 9244514f5e3Sopenharmony_ci 9254514f5e3Sopenharmony_civoid AssemblerAarch64::Bl(Label *label) 9264514f5e3Sopenharmony_ci{ 9274514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9284514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9294514f5e3Sopenharmony_ci offsetImm >>= 2; 9304514f5e3Sopenharmony_ci Bl(offsetImm); 9314514f5e3Sopenharmony_ci} 9324514f5e3Sopenharmony_ci 9334514f5e3Sopenharmony_civoid AssemblerAarch64::Bl(int32_t imm) 9344514f5e3Sopenharmony_ci{ 9354514f5e3Sopenharmony_ci uint32_t code = CallOpCode::BL | ((imm << BRANCH_Imm26_LOWBITS) & BRANCH_Imm26_MASK); 9364514f5e3Sopenharmony_ci EmitU32(code); 9374514f5e3Sopenharmony_ci} 9384514f5e3Sopenharmony_ci 9394514f5e3Sopenharmony_civoid AssemblerAarch64::Blr(const Register &rn) 9404514f5e3Sopenharmony_ci{ 9414514f5e3Sopenharmony_ci ASSERT(!rn.IsW()); 9424514f5e3Sopenharmony_ci uint32_t code = CallOpCode::BLR | Rn(rn.GetId()); 9434514f5e3Sopenharmony_ci EmitU32(code); 9444514f5e3Sopenharmony_ci} 9454514f5e3Sopenharmony_ci 9464514f5e3Sopenharmony_civoid AssemblerAarch64::B(Condition cond, Label *label) 9474514f5e3Sopenharmony_ci{ 9484514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9494514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9504514f5e3Sopenharmony_ci offsetImm >>= 2; 9514514f5e3Sopenharmony_ci B(cond, offsetImm); 9524514f5e3Sopenharmony_ci} 9534514f5e3Sopenharmony_ci 9544514f5e3Sopenharmony_civoid AssemblerAarch64::B(Condition cond, int32_t imm) 9554514f5e3Sopenharmony_ci{ 9564514f5e3Sopenharmony_ci uint32_t code = BranchOpCode::BranchCond | BranchImm19(imm) | cond; 9574514f5e3Sopenharmony_ci EmitU32(code); 9584514f5e3Sopenharmony_ci} 9594514f5e3Sopenharmony_ci 9604514f5e3Sopenharmony_civoid AssemblerAarch64::Cbz(const Register &rt, Label *label) 9614514f5e3Sopenharmony_ci{ 9624514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9634514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9644514f5e3Sopenharmony_ci offsetImm >>= 2; 9654514f5e3Sopenharmony_ci Cbz(rt, offsetImm); 9664514f5e3Sopenharmony_ci} 9674514f5e3Sopenharmony_ci 9684514f5e3Sopenharmony_civoid AssemblerAarch64::Cbnz(const Register &rt, Label *label) 9694514f5e3Sopenharmony_ci{ 9704514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9714514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9724514f5e3Sopenharmony_ci offsetImm >>= 2; 9734514f5e3Sopenharmony_ci Cbnz(rt, offsetImm); 9744514f5e3Sopenharmony_ci} 9754514f5e3Sopenharmony_ci 9764514f5e3Sopenharmony_civoid AssemblerAarch64::Cbz(const Register &rt, int32_t imm) 9774514f5e3Sopenharmony_ci{ 9784514f5e3Sopenharmony_ci uint32_t code = Sf(!rt.IsW()) | BranchOpCode::CBZ | BranchImm19(imm) | rt.GetId(); 9794514f5e3Sopenharmony_ci EmitU32(code); 9804514f5e3Sopenharmony_ci} 9814514f5e3Sopenharmony_ci 9824514f5e3Sopenharmony_civoid AssemblerAarch64::Cbnz(const Register &rt, int32_t imm) 9834514f5e3Sopenharmony_ci{ 9844514f5e3Sopenharmony_ci uint32_t code = Sf(!rt.IsW()) | BranchOpCode::CBNZ | BranchImm19(imm) | rt.GetId(); 9854514f5e3Sopenharmony_ci EmitU32(code); 9864514f5e3Sopenharmony_ci} 9874514f5e3Sopenharmony_ci 9884514f5e3Sopenharmony_civoid AssemblerAarch64::Tbz(const Register &rt, int32_t bitPos, Label *label) 9894514f5e3Sopenharmony_ci{ 9904514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 9914514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 9924514f5e3Sopenharmony_ci offsetImm >>= 2; 9934514f5e3Sopenharmony_ci Tbz(rt, bitPos, offsetImm); 9944514f5e3Sopenharmony_ci} 9954514f5e3Sopenharmony_ci 9964514f5e3Sopenharmony_civoid AssemblerAarch64::Tbz(const Register &rt, int32_t bitPos, int32_t imm) 9974514f5e3Sopenharmony_ci{ 9984514f5e3Sopenharmony_ci uint32_t b5 = (bitPos << (BRANCH_B5_LOWBITS - 5)) & BRANCH_B5_MASK; 9994514f5e3Sopenharmony_ci uint32_t b40 = (bitPos << BRANCH_B40_LOWBITS) & BRANCH_B40_MASK; 10004514f5e3Sopenharmony_ci uint32_t imm14 = (imm << BRANCH_Imm14_LOWBITS) & BRANCH_Imm14_MASK; 10014514f5e3Sopenharmony_ci uint32_t code = b5 | BranchOpCode::TBZ | b40 | imm14 | rt.GetId(); 10024514f5e3Sopenharmony_ci EmitU32(code); 10034514f5e3Sopenharmony_ci} 10044514f5e3Sopenharmony_ci 10054514f5e3Sopenharmony_civoid AssemblerAarch64::Tbnz(const Register &rt, int32_t bitPos, Label *label) 10064514f5e3Sopenharmony_ci{ 10074514f5e3Sopenharmony_ci int32_t offsetImm = LinkAndGetInstOffsetToLabel(label); 10084514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 10094514f5e3Sopenharmony_ci offsetImm >>= 2; 10104514f5e3Sopenharmony_ci Tbnz(rt, bitPos, offsetImm); 10114514f5e3Sopenharmony_ci} 10124514f5e3Sopenharmony_ci 10134514f5e3Sopenharmony_civoid AssemblerAarch64::Tbnz(const Register &rt, int32_t bitPos, int32_t imm) 10144514f5e3Sopenharmony_ci{ 10154514f5e3Sopenharmony_ci uint32_t b5 = (bitPos << (BRANCH_B5_LOWBITS - 5)) & BRANCH_B5_MASK; 10164514f5e3Sopenharmony_ci uint32_t b40 = (bitPos << BRANCH_B40_LOWBITS) & BRANCH_B40_MASK; 10174514f5e3Sopenharmony_ci uint32_t imm14 = (imm <<BRANCH_Imm14_LOWBITS) & BRANCH_Imm14_MASK; 10184514f5e3Sopenharmony_ci uint32_t code = b5 | BranchOpCode::TBNZ | b40 | imm14 | rt.GetId(); 10194514f5e3Sopenharmony_ci EmitU32(code); 10204514f5e3Sopenharmony_ci} 10214514f5e3Sopenharmony_ci 10224514f5e3Sopenharmony_civoid AssemblerAarch64::Tst(const Register& rn, const Operand& operand) 10234514f5e3Sopenharmony_ci{ 10244514f5e3Sopenharmony_ci Ands(Register(Zero, rn.GetType()), rn, operand); 10254514f5e3Sopenharmony_ci} 10264514f5e3Sopenharmony_ci 10274514f5e3Sopenharmony_civoid AssemblerAarch64::Tst(const Register &rn, const LogicalImmediate &imm) 10284514f5e3Sopenharmony_ci{ 10294514f5e3Sopenharmony_ci Ands(Register(Zero, rn.GetType()), rn, imm); 10304514f5e3Sopenharmony_ci} 10314514f5e3Sopenharmony_ci 10324514f5e3Sopenharmony_ciint32_t AssemblerAarch64::LinkAndGetInstOffsetToLabel(Label *label) 10334514f5e3Sopenharmony_ci{ 10344514f5e3Sopenharmony_ci int32_t offset = 0; 10354514f5e3Sopenharmony_ci if (label->IsBound()) { 10364514f5e3Sopenharmony_ci offset = static_cast<int32_t>(label->GetPos() - GetCurrentPosition()); 10374514f5e3Sopenharmony_ci } else { 10384514f5e3Sopenharmony_ci if (label->IsLinked()) { 10394514f5e3Sopenharmony_ci offset = static_cast<int32_t>(label->GetLinkedPos() - GetCurrentPosition()); 10404514f5e3Sopenharmony_ci } else { 10414514f5e3Sopenharmony_ci offset = 0; 10424514f5e3Sopenharmony_ci } 10434514f5e3Sopenharmony_ci label->LinkTo(GetCurrentPosition()); 10444514f5e3Sopenharmony_ci } 10454514f5e3Sopenharmony_ci return offset; 10464514f5e3Sopenharmony_ci} 10474514f5e3Sopenharmony_ci 10484514f5e3Sopenharmony_civoid AssemblerAarch64::Bind(Label *target) 10494514f5e3Sopenharmony_ci{ 10504514f5e3Sopenharmony_ci size_t pos = GetCurrentPosition(); 10514514f5e3Sopenharmony_ci ASSERT(!target->IsBound()); 10524514f5e3Sopenharmony_ci if (target->IsLinked()) { 10534514f5e3Sopenharmony_ci uint32_t linkPos = target->GetLinkedPos(); 10544514f5e3Sopenharmony_ci while (linkPos != 0) { 10554514f5e3Sopenharmony_ci int32_t offset = GetLinkOffsetFromBranchInst(linkPos); 10564514f5e3Sopenharmony_ci int32_t disp = static_cast<int32_t>(pos - linkPos); 10574514f5e3Sopenharmony_ci SetRealOffsetToBranchInst(linkPos, disp); 10584514f5e3Sopenharmony_ci if (offset == 0) { 10594514f5e3Sopenharmony_ci break; 10604514f5e3Sopenharmony_ci } 10614514f5e3Sopenharmony_ci linkPos = linkPos + offset; 10624514f5e3Sopenharmony_ci } 10634514f5e3Sopenharmony_ci } 10644514f5e3Sopenharmony_ci target->BindTo(pos); 10654514f5e3Sopenharmony_ci} 10664514f5e3Sopenharmony_ci 10674514f5e3Sopenharmony_ciint32_t AssemblerAarch64::GetLinkOffsetFromBranchInst(int32_t pos) 10684514f5e3Sopenharmony_ci{ 10694514f5e3Sopenharmony_ci uint32_t branchCode = GetU32(pos); 10704514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 10714514f5e3Sopenharmony_ci int32_t immOffSet = ImmBranch(branchCode) << 2; 10724514f5e3Sopenharmony_ci return immOffSet; 10734514f5e3Sopenharmony_ci} 10744514f5e3Sopenharmony_ci 10754514f5e3Sopenharmony_ciint32_t AssemblerAarch64::ImmBranch(uint32_t branchCode) 10764514f5e3Sopenharmony_ci{ 10774514f5e3Sopenharmony_ci int32_t immOffset = 0; 10784514f5e3Sopenharmony_ci if ((branchCode & BranchFMask) == BranchOpCode::Branch) { 10794514f5e3Sopenharmony_ci immOffset = (branchCode & BRANCH_Imm26_MASK) >> BRANCH_Imm26_LOWBITS; 10804514f5e3Sopenharmony_ci if (immOffset & (1 << (BRANCH_Imm26_WIDTH - 1))) { 10814514f5e3Sopenharmony_ci // 31 : 31 means topmost bits of instruction "uint32_t" 10824514f5e3Sopenharmony_ci immOffset |= ((1 << (31 - BRANCH_Imm26_WIDTH)) - 1) << BRANCH_Imm26_WIDTH; 10834514f5e3Sopenharmony_ci } 10844514f5e3Sopenharmony_ci } else if ((branchCode & BranchCondFMask) == BranchOpCode::BranchCond) { 10854514f5e3Sopenharmony_ci immOffset = (branchCode & BRANCH_Imm19_MASK) >> BRANCH_Imm19_LOWBITS; 10864514f5e3Sopenharmony_ci if (immOffset & (1 << (BRANCH_Imm19_WIDTH - 1))) { 10874514f5e3Sopenharmony_ci // 31 : 31 means topmost bits of instruction "uint32_t" 10884514f5e3Sopenharmony_ci immOffset |= ((1 << (31 - BRANCH_Imm19_WIDTH)) - 1) << BRANCH_Imm19_WIDTH; 10894514f5e3Sopenharmony_ci } 10904514f5e3Sopenharmony_ci } else if ((branchCode & BranchCompareFMask) == BranchOpCode::CBZ) { 10914514f5e3Sopenharmony_ci immOffset = (branchCode & BRANCH_Imm19_MASK) >> BRANCH_Imm19_LOWBITS; 10924514f5e3Sopenharmony_ci if (immOffset & (1 << (BRANCH_Imm19_WIDTH - 1))) { 10934514f5e3Sopenharmony_ci // 31 : 31 means topmost bits of instruction "uint32_t" 10944514f5e3Sopenharmony_ci immOffset |= ((1 << (31 - BRANCH_Imm19_WIDTH)) - 1) << BRANCH_Imm19_WIDTH; 10954514f5e3Sopenharmony_ci } 10964514f5e3Sopenharmony_ci } else if ((branchCode & BranchTestFMask) == BranchOpCode::TBZ) { 10974514f5e3Sopenharmony_ci immOffset = (branchCode & BRANCH_Imm14_MASK) >> BRANCH_Imm14_LOWBITS; 10984514f5e3Sopenharmony_ci if (immOffset & (1 << (BRANCH_Imm14_WIDTH - 1))) { 10994514f5e3Sopenharmony_ci // 31 : 31 means topmost bits of instruction "uint32_t" 11004514f5e3Sopenharmony_ci immOffset |= ((1 << (31 - BRANCH_Imm14_WIDTH)) - 1) << BRANCH_Imm14_WIDTH; 11014514f5e3Sopenharmony_ci } 11024514f5e3Sopenharmony_ci } else { 11034514f5e3Sopenharmony_ci UNREACHABLE(); 11044514f5e3Sopenharmony_ci } 11054514f5e3Sopenharmony_ci return immOffset; 11064514f5e3Sopenharmony_ci} 11074514f5e3Sopenharmony_ci 11084514f5e3Sopenharmony_civoid AssemblerAarch64::SetRealOffsetToBranchInst(uint32_t linkPos, int32_t disp) 11094514f5e3Sopenharmony_ci{ 11104514f5e3Sopenharmony_ci uint32_t branchCode = GetU32(linkPos); 11114514f5e3Sopenharmony_ci // 2 : 2 means 4 bytes aligned. 11124514f5e3Sopenharmony_ci uint32_t immOffset = disp >> 2; 11134514f5e3Sopenharmony_ci 11144514f5e3Sopenharmony_ci if ((branchCode & BranchFMask) == BranchOpCode::Branch) { 11154514f5e3Sopenharmony_ci branchCode &= ~BRANCH_Imm26_MASK; 11164514f5e3Sopenharmony_ci branchCode |= (immOffset << BRANCH_Imm26_LOWBITS) & BRANCH_Imm26_MASK; 11174514f5e3Sopenharmony_ci } else if ((branchCode & BranchCondFMask) == BranchOpCode::BranchCond) { 11184514f5e3Sopenharmony_ci branchCode &= ~BRANCH_Imm19_MASK; 11194514f5e3Sopenharmony_ci branchCode |= (immOffset << BRANCH_Imm19_LOWBITS) & BRANCH_Imm19_MASK; 11204514f5e3Sopenharmony_ci } else if ((branchCode & BranchCompareFMask) == BranchOpCode::CBZ) { 11214514f5e3Sopenharmony_ci branchCode &= ~BRANCH_Imm19_MASK; 11224514f5e3Sopenharmony_ci branchCode |= (immOffset << BRANCH_Imm19_LOWBITS) & BRANCH_Imm19_MASK; 11234514f5e3Sopenharmony_ci } else if ((branchCode & BranchTestFMask) == BranchOpCode::TBZ) { 11244514f5e3Sopenharmony_ci branchCode &= ~BRANCH_Imm14_MASK; 11254514f5e3Sopenharmony_ci branchCode |= (immOffset << BRANCH_Imm14_LOWBITS) & BRANCH_Imm14_MASK; 11264514f5e3Sopenharmony_ci } 11274514f5e3Sopenharmony_ci PutI32(linkPos, branchCode); 11284514f5e3Sopenharmony_ci} 11294514f5e3Sopenharmony_ci 11304514f5e3Sopenharmony_civoid AssemblerAarch64::Ret() 11314514f5e3Sopenharmony_ci{ 11324514f5e3Sopenharmony_ci Ret(Register(X30)); 11334514f5e3Sopenharmony_ci} 11344514f5e3Sopenharmony_ci 11354514f5e3Sopenharmony_civoid AssemblerAarch64::Ret(const Register &rn) 11364514f5e3Sopenharmony_ci{ 11374514f5e3Sopenharmony_ci uint32_t code = RetOpCode::Ret | Rn(rn.GetId()); 11384514f5e3Sopenharmony_ci EmitU32(code); 11394514f5e3Sopenharmony_ci} 11404514f5e3Sopenharmony_ci 11414514f5e3Sopenharmony_civoid AssemblerAarch64::Brk(const Immediate &imm) 11424514f5e3Sopenharmony_ci{ 11434514f5e3Sopenharmony_ci uint32_t brk_number_field = 11444514f5e3Sopenharmony_ci (static_cast<uint32_t>(imm.Value()) << BRK_Imm16_LOWBITS) & BRK_Imm16_MASK; 11454514f5e3Sopenharmony_ci uint32_t code = BRKImm | brk_number_field; 11464514f5e3Sopenharmony_ci EmitU32(code); 11474514f5e3Sopenharmony_ci} 11484514f5e3Sopenharmony_ci 11494514f5e3Sopenharmony_ciuint64_t AssemblerAarch64::GetImmOfLdr(const MemoryOperand &operand, Scale scale, bool isRegX) 11504514f5e3Sopenharmony_ci{ 11514514f5e3Sopenharmony_ci ASSERT(operand.IsImmediateOffset()); 11524514f5e3Sopenharmony_ci uint64_t imm = static_cast<uint64_t>(operand.GetImmediate().Value()); 11534514f5e3Sopenharmony_ci if (operand.GetAddrMode() == OFFSET) { 11544514f5e3Sopenharmony_ci if (scale == Scale::H) { 11554514f5e3Sopenharmony_ci imm >>= 1; 11564514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 11574514f5e3Sopenharmony_ci if (isRegX) { 11584514f5e3Sopenharmony_ci imm >>= 3; // 3: 64 RegSise, imm/8 to remove trailing zeros 11594514f5e3Sopenharmony_ci } else { 11604514f5e3Sopenharmony_ci imm >>= 2; // 2: 32 RegSise, imm/4 to remove trailing zeros 11614514f5e3Sopenharmony_ci } 11624514f5e3Sopenharmony_ci } 11634514f5e3Sopenharmony_ci } 11644514f5e3Sopenharmony_ci return imm; 11654514f5e3Sopenharmony_ci} 11664514f5e3Sopenharmony_ci 11674514f5e3Sopenharmony_ciuint64_t AssemblerAarch64::GetOpcodeOfLdr(const MemoryOperand &operand, Scale scale) 11684514f5e3Sopenharmony_ci{ 11694514f5e3Sopenharmony_ci uint32_t op = 0; 11704514f5e3Sopenharmony_ci if (operand.IsImmediateOffset()) { 11714514f5e3Sopenharmony_ci switch (operand.GetAddrMode()) { 11724514f5e3Sopenharmony_ci case OFFSET: { 11734514f5e3Sopenharmony_ci if (scale == Scale::B) { 11744514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRB_Offset; 11754514f5e3Sopenharmony_ci } else if (scale == Scale::H) { 11764514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRH_Offset; 11774514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 11784514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDR_Offset; 11794514f5e3Sopenharmony_ci } else { 11804514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 11814514f5e3Sopenharmony_ci UNREACHABLE(); 11824514f5e3Sopenharmony_ci } 11834514f5e3Sopenharmony_ci break; 11844514f5e3Sopenharmony_ci } 11854514f5e3Sopenharmony_ci case PREINDEX: { 11864514f5e3Sopenharmony_ci if (scale == Scale::B) { 11874514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRB_Pre; 11884514f5e3Sopenharmony_ci } else if (scale == Scale::H) { 11894514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRH_Pre; 11904514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 11914514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDR_Pre; 11924514f5e3Sopenharmony_ci } else { 11934514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 11944514f5e3Sopenharmony_ci UNREACHABLE(); 11954514f5e3Sopenharmony_ci } 11964514f5e3Sopenharmony_ci break; 11974514f5e3Sopenharmony_ci } 11984514f5e3Sopenharmony_ci case POSTINDEX: { 11994514f5e3Sopenharmony_ci if (scale == Scale::B) { 12004514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRB_Post; 12014514f5e3Sopenharmony_ci } else if (scale == Scale::H) { 12024514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRH_Post; 12034514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 12044514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDR_Post; 12054514f5e3Sopenharmony_ci } else { 12064514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 12074514f5e3Sopenharmony_ci UNREACHABLE(); 12084514f5e3Sopenharmony_ci } 12094514f5e3Sopenharmony_ci break; 12104514f5e3Sopenharmony_ci } 12114514f5e3Sopenharmony_ci default: 12124514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 12134514f5e3Sopenharmony_ci UNREACHABLE(); 12144514f5e3Sopenharmony_ci } 12154514f5e3Sopenharmony_ci } else { 12164514f5e3Sopenharmony_ci if (scale == Scale::B) { 12174514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRB_Register; 12184514f5e3Sopenharmony_ci } else if (scale == Scale::H) { 12194514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDRH_Register; 12204514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 12214514f5e3Sopenharmony_ci op = LoadStoreOpCode::LDR_Register; 12224514f5e3Sopenharmony_ci } else { 12234514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 12244514f5e3Sopenharmony_ci UNREACHABLE(); 12254514f5e3Sopenharmony_ci } 12264514f5e3Sopenharmony_ci } 12274514f5e3Sopenharmony_ci return op; 12284514f5e3Sopenharmony_ci} 12294514f5e3Sopenharmony_ci 12304514f5e3Sopenharmony_ciuint32_t AssemblerAarch64::GetShiftOfLdr(const MemoryOperand &operand, Scale scale, bool isRegX) 12314514f5e3Sopenharmony_ci{ 12324514f5e3Sopenharmony_ci uint32_t shift = 0; 12334514f5e3Sopenharmony_ci if (scale == Scale::B) { 12344514f5e3Sopenharmony_ci shift = operand.GetShiftOption() != Shift::NO_SHIFT; 12354514f5e3Sopenharmony_ci } else if (scale == Scale::H) { 12364514f5e3Sopenharmony_ci shift = operand.GetShiftAmount(); 12374514f5e3Sopenharmony_ci ASSERT(shift == 0 || shift == 1); 12384514f5e3Sopenharmony_ci shift = (shift == 0) ? 0 : 1; 12394514f5e3Sopenharmony_ci } else if (scale == Scale::Q) { 12404514f5e3Sopenharmony_ci shift = operand.GetShiftAmount(); 12414514f5e3Sopenharmony_ci if (isRegX) { 12424514f5e3Sopenharmony_ci // 3 : 3 means address aligned with 8bytes 12434514f5e3Sopenharmony_ci ASSERT(shift == 0 || shift == 3); 12444514f5e3Sopenharmony_ci } else { 12454514f5e3Sopenharmony_ci // 2 : 2 means address aligned with 4bytes 12464514f5e3Sopenharmony_ci ASSERT(shift == 0 || shift == 2); 12474514f5e3Sopenharmony_ci } 12484514f5e3Sopenharmony_ci shift = (shift == 0) ? 0 : 1; 12494514f5e3Sopenharmony_ci } 12504514f5e3Sopenharmony_ci return shift; 12514514f5e3Sopenharmony_ci} 12524514f5e3Sopenharmony_ci} // namespace panda::ecmascript::aarch64 1253