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