14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 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 "ecmascript/compiler/assembler/aarch64/macro_assembler_aarch64.h"
174514f5e3Sopenharmony_ci#include <set>
184514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
194514f5e3Sopenharmony_ci
204514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
214514f5e3Sopenharmony_ciusing namespace panda::ecmascript;
224514f5e3Sopenharmony_ciconstexpr uint32_t k4BitSize = 4;
234514f5e3Sopenharmony_ciconstexpr uint32_t k16BitSize = 16;
244514f5e3Sopenharmony_ciconstexpr uint32_t k32BitSize = 32;
254514f5e3Sopenharmony_ciconstexpr uint32_t k48BitSize = 48;
264514f5e3Sopenharmony_ciconstexpr uint32_t k64BitSize = 64;
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_ciconst std::set<uint64_t> ValidBitmaskImmSet = {
294514f5e3Sopenharmony_ci#include "valid_bitmask_imm.txt"
304514f5e3Sopenharmony_ci};
314514f5e3Sopenharmony_ciconstexpr uint32_t kMaxBitTableSize = 5;
324514f5e3Sopenharmony_ciconstexpr std::array<uint64_t, kMaxBitTableSize> kBitmaskImmMultTable = {
334514f5e3Sopenharmony_ci    0x0000000100000001UL, 0x0001000100010001UL, 0x0101010101010101UL, 0x1111111111111111UL, 0x5555555555555555UL,
344514f5e3Sopenharmony_ci};
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Move(const StackSlotOperand &dstStackSlot, Immediate value)
374514f5e3Sopenharmony_ci{
384514f5e3Sopenharmony_ci    aarch64::Register baseReg = (dstStackSlot.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
394514f5e3Sopenharmony_ci                                                               aarch64::Register(aarch64::SP);
404514f5e3Sopenharmony_ci    aarch64::MemoryOperand dstOpnd(baseReg, static_cast<int64_t>(dstStackSlot.GetOffset()));
414514f5e3Sopenharmony_ci    assembler.Mov(LOCAL_SCOPE_REGISTER, aarch64::Immediate(value.GetValue()));
424514f5e3Sopenharmony_ci    PickLoadStoreInsn(LOCAL_SCOPE_REGISTER, dstOpnd, false);
434514f5e3Sopenharmony_ci}
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Move(const StackSlotOperand &dstStackSlot,
464514f5e3Sopenharmony_ci                                 const StackSlotOperand &srcStackSlot)
474514f5e3Sopenharmony_ci{
484514f5e3Sopenharmony_ci    aarch64::Register dstBaseReg = (dstStackSlot.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
494514f5e3Sopenharmony_ci                                                                  aarch64::Register(aarch64::SP);
504514f5e3Sopenharmony_ci    aarch64::MemoryOperand dstOpnd(dstBaseReg, static_cast<int64_t>(dstStackSlot.GetOffset()));
514514f5e3Sopenharmony_ci    aarch64::Register srcBaseReg = (srcStackSlot.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
524514f5e3Sopenharmony_ci                                                                  aarch64::Register(aarch64::SP);
534514f5e3Sopenharmony_ci    aarch64::MemoryOperand srcOpnd(srcBaseReg, static_cast<int64_t>(srcStackSlot.GetOffset()));
544514f5e3Sopenharmony_ci    PickLoadStoreInsn(LOCAL_SCOPE_REGISTER, srcOpnd);
554514f5e3Sopenharmony_ci    PickLoadStoreInsn(LOCAL_SCOPE_REGISTER, dstOpnd, false);
564514f5e3Sopenharmony_ci}
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Cmp(const StackSlotOperand &stackSlot, Immediate value)
594514f5e3Sopenharmony_ci{
604514f5e3Sopenharmony_ci    aarch64::Register baseReg = (stackSlot.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
614514f5e3Sopenharmony_ci                                                            aarch64::Register(aarch64::SP);
624514f5e3Sopenharmony_ci    aarch64::MemoryOperand opnd(baseReg, static_cast<int64_t>(stackSlot.GetOffset()));
634514f5e3Sopenharmony_ci    aarch64::Operand immOpnd = aarch64::Immediate(value.GetValue());
644514f5e3Sopenharmony_ci    PickLoadStoreInsn(LOCAL_SCOPE_REGISTER, opnd);
654514f5e3Sopenharmony_ci    assembler.Cmp(LOCAL_SCOPE_REGISTER, immOpnd);
664514f5e3Sopenharmony_ci}
674514f5e3Sopenharmony_ci
684514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Bind(JumpLabel &label)
694514f5e3Sopenharmony_ci{
704514f5e3Sopenharmony_ci    assembler.Bind(&label);
714514f5e3Sopenharmony_ci}
724514f5e3Sopenharmony_ci
734514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Jz(JumpLabel &label)
744514f5e3Sopenharmony_ci{
754514f5e3Sopenharmony_ci    assembler.B(aarch64::EQ, &label);
764514f5e3Sopenharmony_ci}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Jnz(JumpLabel &label)
794514f5e3Sopenharmony_ci{
804514f5e3Sopenharmony_ci    assembler.B(aarch64::NE, &label);
814514f5e3Sopenharmony_ci}
824514f5e3Sopenharmony_ci
834514f5e3Sopenharmony_civoid MacroAssemblerAArch64::Jump(JumpLabel &label)
844514f5e3Sopenharmony_ci{
854514f5e3Sopenharmony_ci    assembler.B(&label);
864514f5e3Sopenharmony_ci}
874514f5e3Sopenharmony_ci
884514f5e3Sopenharmony_civoid MacroAssemblerAArch64::CallBuiltin(Address funcAddress,
894514f5e3Sopenharmony_ci                                        const std::vector<MacroParameter> &parameters)
904514f5e3Sopenharmony_ci{
914514f5e3Sopenharmony_ci    for (size_t i = 0; i < parameters.size(); ++i) {
924514f5e3Sopenharmony_ci        auto param = parameters[i];
934514f5e3Sopenharmony_ci        if (i == PARAM_REGISTER_COUNT) {
944514f5e3Sopenharmony_ci            std::cout << "not support aarch64 baseline stack parameter " << std::endl;
954514f5e3Sopenharmony_ci            std::abort();
964514f5e3Sopenharmony_ci            break;
974514f5e3Sopenharmony_ci        }
984514f5e3Sopenharmony_ci        MovParameterIntoParamReg(param, registerParamVec[i]);
994514f5e3Sopenharmony_ci    }
1004514f5e3Sopenharmony_ci    assembler.Mov(LOCAL_SCOPE_REGISTER, aarch64::Immediate(funcAddress));
1014514f5e3Sopenharmony_ci    assembler.Blr(LOCAL_SCOPE_REGISTER);
1024514f5e3Sopenharmony_ci}
1034514f5e3Sopenharmony_ci
1044514f5e3Sopenharmony_civoid MacroAssemblerAArch64::SaveReturnRegister(const StackSlotOperand &dstStackSlot)
1054514f5e3Sopenharmony_ci{
1064514f5e3Sopenharmony_ci    aarch64::Register baseReg = (dstStackSlot.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
1074514f5e3Sopenharmony_ci                                                               aarch64::Register(aarch64::SP);
1084514f5e3Sopenharmony_ci    aarch64::MemoryOperand dstOpnd(baseReg, static_cast<int64_t>(dstStackSlot.GetOffset()));
1094514f5e3Sopenharmony_ci    PickLoadStoreInsn(RETURN_REGISTER, dstOpnd, false);
1104514f5e3Sopenharmony_ci}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_civoid MacroAssemblerAArch64::MovParameterIntoParamReg(MacroParameter param, aarch64::Register paramReg)
1134514f5e3Sopenharmony_ci{
1144514f5e3Sopenharmony_ci    if (std::holds_alternative<BaselineSpecialParameter>(param)) {
1154514f5e3Sopenharmony_ci        auto specialParam = std::get<BaselineSpecialParameter>(param);
1164514f5e3Sopenharmony_ci        switch (specialParam) {
1174514f5e3Sopenharmony_ci            case BaselineSpecialParameter::GLUE: {
1184514f5e3Sopenharmony_ci                assembler.Mov(paramReg, GLUE_REGISTER);
1194514f5e3Sopenharmony_ci                break;
1204514f5e3Sopenharmony_ci            }
1214514f5e3Sopenharmony_ci            case BaselineSpecialParameter::PROFILE_TYPE_INFO: {
1224514f5e3Sopenharmony_ci                assembler.Ldur(LOCAL_SCOPE_REGISTER,
1234514f5e3Sopenharmony_ci                               aarch64::MemoryOperand(aarch64::Register(aarch64::X29),
1244514f5e3Sopenharmony_ci                                                      static_cast<int64_t>(FUNCTION_OFFSET_FROM_SP)));
1254514f5e3Sopenharmony_ci                assembler.Ldr(LOCAL_SCOPE_REGISTER,
1264514f5e3Sopenharmony_ci                              aarch64::MemoryOperand(LOCAL_SCOPE_REGISTER, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
1274514f5e3Sopenharmony_ci                assembler.Ldr(paramReg,
1284514f5e3Sopenharmony_ci                              aarch64::MemoryOperand(LOCAL_SCOPE_REGISTER, ProfileTypeInfoCell::VALUE_OFFSET));
1294514f5e3Sopenharmony_ci                break;
1304514f5e3Sopenharmony_ci            }
1314514f5e3Sopenharmony_ci            case BaselineSpecialParameter::SP: {
1324514f5e3Sopenharmony_ci                assembler.Mov(paramReg, aarch64::Register(aarch64::X29));
1334514f5e3Sopenharmony_ci                break;
1344514f5e3Sopenharmony_ci            }
1354514f5e3Sopenharmony_ci            case BaselineSpecialParameter::HOTNESS_COUNTER: {
1364514f5e3Sopenharmony_ci                assembler.Ldur(LOCAL_SCOPE_REGISTER, aarch64::MemoryOperand(aarch64::Register(aarch64::X29),
1374514f5e3Sopenharmony_ci                    static_cast<int64_t>(FUNCTION_OFFSET_FROM_SP)));
1384514f5e3Sopenharmony_ci                assembler.Ldr(LOCAL_SCOPE_REGISTER,
1394514f5e3Sopenharmony_ci                              aarch64::MemoryOperand(LOCAL_SCOPE_REGISTER, JSFunctionBase::METHOD_OFFSET));
1404514f5e3Sopenharmony_ci                assembler.Ldr(paramReg,
1414514f5e3Sopenharmony_ci                              aarch64::MemoryOperand(LOCAL_SCOPE_REGISTER, Method::LITERAL_INFO_OFFSET));
1424514f5e3Sopenharmony_ci                break;
1434514f5e3Sopenharmony_ci            }
1444514f5e3Sopenharmony_ci            default: {
1454514f5e3Sopenharmony_ci                std::cout << "not supported other BaselineSpecialParameter currently" << std::endl;
1464514f5e3Sopenharmony_ci                std::abort();
1474514f5e3Sopenharmony_ci            }
1484514f5e3Sopenharmony_ci        }
1494514f5e3Sopenharmony_ci        return;
1504514f5e3Sopenharmony_ci    }
1514514f5e3Sopenharmony_ci    if (std::holds_alternative<int8_t>(param)) {
1524514f5e3Sopenharmony_ci        int16_t num = std::get<int8_t>(param);
1534514f5e3Sopenharmony_ci        assembler.Mov(paramReg, aarch64::Immediate(static_cast<int64_t>(num)));
1544514f5e3Sopenharmony_ci        return;
1554514f5e3Sopenharmony_ci    }
1564514f5e3Sopenharmony_ci    if (std::holds_alternative<int16_t>(param)) {
1574514f5e3Sopenharmony_ci        int16_t num = std::get<int16_t>(param);
1584514f5e3Sopenharmony_ci        assembler.Mov(paramReg, aarch64::Immediate(static_cast<int64_t>(num)));
1594514f5e3Sopenharmony_ci        return;
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci    if (std::holds_alternative<int32_t>(param)) {
1624514f5e3Sopenharmony_ci        int32_t num = std::get<int32_t>(param);
1634514f5e3Sopenharmony_ci        assembler.Mov(paramReg, aarch64::Immediate(static_cast<int64_t>(num)));
1644514f5e3Sopenharmony_ci        return;
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci    if (std::holds_alternative<int64_t>(param)) {
1674514f5e3Sopenharmony_ci        int64_t num = std::get<int64_t>(param);
1684514f5e3Sopenharmony_ci        CopyImm(paramReg, num, k64BitSize);
1694514f5e3Sopenharmony_ci        return;
1704514f5e3Sopenharmony_ci    }
1714514f5e3Sopenharmony_ci    if (std::holds_alternative<StackSlotOperand>(param)) {
1724514f5e3Sopenharmony_ci        StackSlotOperand stackSlotOpnd = std::get<StackSlotOperand>(param);
1734514f5e3Sopenharmony_ci        aarch64::Register dstBaseReg = (stackSlotOpnd.IsFrameBase()) ? aarch64::Register(aarch64::FP) :
1744514f5e3Sopenharmony_ci                                                                       aarch64::Register(aarch64::SP);
1754514f5e3Sopenharmony_ci        aarch64::MemoryOperand paramOpnd(dstBaseReg, static_cast<int64_t>(stackSlotOpnd.GetOffset()));
1764514f5e3Sopenharmony_ci        PickLoadStoreInsn(paramReg, paramOpnd);
1774514f5e3Sopenharmony_ci        return;
1784514f5e3Sopenharmony_ci    }
1794514f5e3Sopenharmony_ci    std::cout << "not supported other type of aarch64 baseline parameters currently" << std::endl;
1804514f5e3Sopenharmony_ci    std::abort();
1814514f5e3Sopenharmony_ci}
1824514f5e3Sopenharmony_ci
1834514f5e3Sopenharmony_civoid MacroAssemblerAArch64::PickLoadStoreInsn(aarch64::Register reg, aarch64::MemoryOperand memOpnd, bool isLoad)
1844514f5e3Sopenharmony_ci{
1854514f5e3Sopenharmony_ci    int64_t maxNineBitsSignedValue = 255;
1864514f5e3Sopenharmony_ci    int64_t minNineBitsSignedValue = -256;
1874514f5e3Sopenharmony_ci    int64_t value = memOpnd.GetImmediate().Value();
1884514f5e3Sopenharmony_ci    if (value < minNineBitsSignedValue) {
1894514f5e3Sopenharmony_ci        std::cout << "not support aarch64 offset in memory operand is less than -256!" << std::endl;
1904514f5e3Sopenharmony_ci        std::abort();
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci    if (value > maxNineBitsSignedValue && isLoad) {
1934514f5e3Sopenharmony_ci        if (value % 8 != 0) { // 8: offset in memory operand must be a multiple of 8 for ldr insn
1944514f5e3Sopenharmony_ci            std::cout << "not support offset in memory operand is not a multiple of 8 for ldr insn!" << std::endl;
1954514f5e3Sopenharmony_ci            std::abort();
1964514f5e3Sopenharmony_ci        }
1974514f5e3Sopenharmony_ci        assembler.Ldr(reg, memOpnd);
1984514f5e3Sopenharmony_ci    }
1994514f5e3Sopenharmony_ci    if (value > maxNineBitsSignedValue && !isLoad) {
2004514f5e3Sopenharmony_ci        if (value % 8 != 0) { // 8: offset in memory operand must be a multiple of 8 for str insn
2014514f5e3Sopenharmony_ci            std::cout << "not support offset in memory operand is not a multiple of 8 for str insn!" << std::endl;
2024514f5e3Sopenharmony_ci            std::abort();
2034514f5e3Sopenharmony_ci        }
2044514f5e3Sopenharmony_ci        assembler.Str(reg, memOpnd);
2054514f5e3Sopenharmony_ci    }
2064514f5e3Sopenharmony_ci    if (value <= maxNineBitsSignedValue && isLoad) {
2074514f5e3Sopenharmony_ci        assembler.Ldur(reg, memOpnd);
2084514f5e3Sopenharmony_ci    }
2094514f5e3Sopenharmony_ci    if (value <= maxNineBitsSignedValue && !isLoad) {
2104514f5e3Sopenharmony_ci        assembler.Stur(reg, memOpnd);
2114514f5e3Sopenharmony_ci    }
2124514f5e3Sopenharmony_ci}
2134514f5e3Sopenharmony_ci
2144514f5e3Sopenharmony_cibool MacroAssemblerAArch64::IsMoveWidableImmediate(uint64_t val, uint32_t bitLen)
2154514f5e3Sopenharmony_ci{
2164514f5e3Sopenharmony_ci    if (bitLen == k64BitSize) {
2174514f5e3Sopenharmony_ci        /* 0xHHHH000000000000 or 0x0000HHHH00000000, return true */
2184514f5e3Sopenharmony_ci        if (((val & ((static_cast<uint64_t>(0xffff)) << k48BitSize)) == val) ||
2194514f5e3Sopenharmony_ci            ((val & ((static_cast<uint64_t>(0xffff)) << k32BitSize)) == val)) {
2204514f5e3Sopenharmony_ci            return true;
2214514f5e3Sopenharmony_ci        }
2224514f5e3Sopenharmony_ci    } else {
2234514f5e3Sopenharmony_ci        /* get lower 32 bits */
2244514f5e3Sopenharmony_ci        val &= static_cast<uint64_t>(0xffffffff);
2254514f5e3Sopenharmony_ci    }
2264514f5e3Sopenharmony_ci    /* 0x00000000HHHH0000 or 0x000000000000HHHH, return true */
2274514f5e3Sopenharmony_ci    return ((val & ((static_cast<uint64_t>(0xffff)) << k16BitSize)) == val ||
2284514f5e3Sopenharmony_ci            (val & ((static_cast<uint64_t>(0xffff)) << 0)) == val);
2294514f5e3Sopenharmony_ci}
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_cibool MacroAssemblerAArch64::IsBitmaskImmediate(uint64_t val, uint32_t bitLen)
2324514f5e3Sopenharmony_ci{
2334514f5e3Sopenharmony_ci    if (static_cast<int64_t>(val) == -1 || val == 0) {
2344514f5e3Sopenharmony_ci        std::cout << "IsBitmaskImmediate() don't accept 0 or -1!" << std::endl;
2354514f5e3Sopenharmony_ci        std::abort();
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci    if ((bitLen == k32BitSize) && (static_cast<int32_t>(val) == -1)) {
2384514f5e3Sopenharmony_ci        return false;
2394514f5e3Sopenharmony_ci    }
2404514f5e3Sopenharmony_ci    uint64_t val2 = val;
2414514f5e3Sopenharmony_ci    if (bitLen == k32BitSize) {
2424514f5e3Sopenharmony_ci        val2 = (val2 << k32BitSize) | (val2 & ((1ULL << k32BitSize) - 1));
2434514f5e3Sopenharmony_ci    }
2444514f5e3Sopenharmony_ci    bool expectedOutcome = (ValidBitmaskImmSet.find(val2) != ValidBitmaskImmSet.end());
2454514f5e3Sopenharmony_ci
2464514f5e3Sopenharmony_ci    if ((val & 0x1) != 0) {
2474514f5e3Sopenharmony_ci        /*
2484514f5e3Sopenharmony_ci         * we want to work with
2494514f5e3Sopenharmony_ci         * 0000000000000000000000000000000000000000000001100000000000000000
2504514f5e3Sopenharmony_ci         * instead of
2514514f5e3Sopenharmony_ci         * 1111111111111111111111111111111111111111111110011111111111111111
2524514f5e3Sopenharmony_ci         */
2534514f5e3Sopenharmony_ci        val = ~val;
2544514f5e3Sopenharmony_ci    }
2554514f5e3Sopenharmony_ci
2564514f5e3Sopenharmony_ci    if (bitLen == k32BitSize) {
2574514f5e3Sopenharmony_ci        val = (val << k32BitSize) | (val & ((1ULL << k32BitSize) - 1));
2584514f5e3Sopenharmony_ci    }
2594514f5e3Sopenharmony_ci
2604514f5e3Sopenharmony_ci    /* get the least significant bit set and add it to 'val' */
2614514f5e3Sopenharmony_ci    uint64_t tmpVal = val + (val & static_cast<uint64_t>(UINT64_MAX - val + 1));
2624514f5e3Sopenharmony_ci
2634514f5e3Sopenharmony_ci    /* now check if tmp is a power of 2 or tmpVal==0. */
2644514f5e3Sopenharmony_ci    if (tmpVal < 1 || tmpVal > UINT64_MAX) {
2654514f5e3Sopenharmony_ci        std::cout << "tmpVal value overflow!" << std::endl;
2664514f5e3Sopenharmony_ci        std::abort();
2674514f5e3Sopenharmony_ci    }
2684514f5e3Sopenharmony_ci    tmpVal = tmpVal & (tmpVal - 1);
2694514f5e3Sopenharmony_ci    if (tmpVal == 0) {
2704514f5e3Sopenharmony_ci        if (!expectedOutcome) {
2714514f5e3Sopenharmony_ci            return false;
2724514f5e3Sopenharmony_ci        }
2734514f5e3Sopenharmony_ci        /* power of two or zero ; return true */
2744514f5e3Sopenharmony_ci        return true;
2754514f5e3Sopenharmony_ci    }
2764514f5e3Sopenharmony_ci
2774514f5e3Sopenharmony_ci    int32_t p0 = __builtin_ctzll(val);
2784514f5e3Sopenharmony_ci    int32_t p1 = __builtin_ctzll(tmpVal);
2794514f5e3Sopenharmony_ci    int64_t diff = p1 - p0;
2804514f5e3Sopenharmony_ci
2814514f5e3Sopenharmony_ci    /* check if diff is a power of two; return false if not. */
2824514f5e3Sopenharmony_ci    if (static_cast<uint64_t>(diff) < 1 || static_cast<uint64_t>(diff) > UINT64_MAX) {
2834514f5e3Sopenharmony_ci        std::cout << "diff value overflow!" << std::endl;
2844514f5e3Sopenharmony_ci        std::abort();
2854514f5e3Sopenharmony_ci    }
2864514f5e3Sopenharmony_ci    if ((static_cast<uint64_t>(diff) & (static_cast<uint64_t>(diff) - 1)) != 0) {
2874514f5e3Sopenharmony_ci        return false;
2884514f5e3Sopenharmony_ci    }
2894514f5e3Sopenharmony_ci
2904514f5e3Sopenharmony_ci    uint32_t logDiff = static_cast<uint32_t>(__builtin_ctzll(static_cast<uint64_t>(diff)));
2914514f5e3Sopenharmony_ci    uint64_t pattern = val & ((1ULL << static_cast<uint64_t>(diff)) - 1);
2924514f5e3Sopenharmony_ci    return val == pattern * kBitmaskImmMultTable[kMaxBitTableSize - logDiff];
2934514f5e3Sopenharmony_ci}
2944514f5e3Sopenharmony_ci
2954514f5e3Sopenharmony_cibool MacroAssemblerAArch64::IsSingleInstructionMovable(uint64_t val, uint32_t size)
2964514f5e3Sopenharmony_ci{
2974514f5e3Sopenharmony_ci    return (IsMoveWidableImmediate(val, size) ||
2984514f5e3Sopenharmony_ci           IsMoveWidableImmediate(~val, size) || IsBitmaskImmediate(val, size));
2994514f5e3Sopenharmony_ci}
3004514f5e3Sopenharmony_ci
3014514f5e3Sopenharmony_cibool MacroAssemblerAArch64::BetterUseMOVZ(uint64_t val)
3024514f5e3Sopenharmony_ci{
3034514f5e3Sopenharmony_ci    int32_t n16zerosChunks = 0;
3044514f5e3Sopenharmony_ci    int32_t n16onesChunks = 0;
3054514f5e3Sopenharmony_ci    uint64_t sa = 0;
3064514f5e3Sopenharmony_ci    /* a 64 bits number is split 4 chunks, each chunk has 16 bits. check each chunk whether is all 1 or is all 0 */
3074514f5e3Sopenharmony_ci    for (uint64_t i = 0; i < k4BitSize; ++i, sa += k16BitSize) {
3084514f5e3Sopenharmony_ci        uint64_t chunkVal = (val >> (static_cast<uint64_t>(sa))) & 0x0000FFFFUL;
3094514f5e3Sopenharmony_ci        if (chunkVal == 0) {
3104514f5e3Sopenharmony_ci            ++n16zerosChunks;
3114514f5e3Sopenharmony_ci        } else if (chunkVal == 0xFFFFUL) {
3124514f5e3Sopenharmony_ci            ++n16onesChunks;
3134514f5e3Sopenharmony_ci        }
3144514f5e3Sopenharmony_ci    }
3154514f5e3Sopenharmony_ci    return (n16zerosChunks >= n16onesChunks);
3164514f5e3Sopenharmony_ci}
3174514f5e3Sopenharmony_ci
3184514f5e3Sopenharmony_civoid MacroAssemblerAArch64::CopyImm(aarch64::Register destReg, int64_t imm, uint32_t size)
3194514f5e3Sopenharmony_ci{
3204514f5e3Sopenharmony_ci    uint64_t srcVal = static_cast<uint64_t>(imm);
3214514f5e3Sopenharmony_ci
3224514f5e3Sopenharmony_ci    if (IsSingleInstructionMovable(srcVal, size)) {
3234514f5e3Sopenharmony_ci        assembler.Mov(destReg, aarch64::Immediate(imm));
3244514f5e3Sopenharmony_ci        return;
3254514f5e3Sopenharmony_ci    }
3264514f5e3Sopenharmony_ci
3274514f5e3Sopenharmony_ci    if (size != k32BitSize && size != k64BitSize) {
3284514f5e3Sopenharmony_ci        std::cout << "only support 32 and 64 bits size!" << std::endl;
3294514f5e3Sopenharmony_ci        std::abort();
3304514f5e3Sopenharmony_ci    }
3314514f5e3Sopenharmony_ci
3324514f5e3Sopenharmony_ci    if (size == k32BitSize) {
3334514f5e3Sopenharmony_ci        /* check lower 16 bits and higher 16 bits respectively */
3344514f5e3Sopenharmony_ci        if ((srcVal & 0x0000FFFFULL) == 0 || (srcVal & 0x0000FFFFULL) == 0xFFFFULL) {
3354514f5e3Sopenharmony_ci            std::cout << "unexpected val!" << std::endl;
3364514f5e3Sopenharmony_ci            std::abort();
3374514f5e3Sopenharmony_ci        }
3384514f5e3Sopenharmony_ci        if (((srcVal >> k16BitSize) & 0x0000FFFFULL) == 0 || ((srcVal >> k16BitSize) & 0x0000FFFFULL) == 0xFFFFULL) {
3394514f5e3Sopenharmony_ci            std::cout << "unexpected val" << std::endl;
3404514f5e3Sopenharmony_ci            std::abort();
3414514f5e3Sopenharmony_ci        }
3424514f5e3Sopenharmony_ci        /* create an imm opereand which represents lower 16 bits of the immediate */
3434514f5e3Sopenharmony_ci        int64_t srcLower = static_cast<int64_t>(srcVal & 0x0000FFFFULL);
3444514f5e3Sopenharmony_ci        assembler.Mov(destReg, aarch64::Immediate(srcLower));
3454514f5e3Sopenharmony_ci        /* create an imm opereand which represents upper 16 bits of the immediate */
3464514f5e3Sopenharmony_ci        int64_t srcUpper = static_cast<int64_t>((srcVal >> k16BitSize) & 0x0000FFFFULL);
3474514f5e3Sopenharmony_ci        assembler.Movk(destReg, srcUpper, k16BitSize);
3484514f5e3Sopenharmony_ci    } else {
3494514f5e3Sopenharmony_ci        CopyImmSize64(destReg, srcVal);
3504514f5e3Sopenharmony_ci    }
3514514f5e3Sopenharmony_ci}
3524514f5e3Sopenharmony_ci
3534514f5e3Sopenharmony_civoid MacroAssemblerAArch64::CopyImmSize64(aarch64::Register destReg, uint64_t srcVal)
3544514f5e3Sopenharmony_ci{
3554514f5e3Sopenharmony_ci    /*
3564514f5e3Sopenharmony_ci     * partition it into 4 16-bit chunks
3574514f5e3Sopenharmony_ci     * if more 0's than 0xFFFF's, use movz as the initial instruction.
3584514f5e3Sopenharmony_ci     * otherwise, movn.
3594514f5e3Sopenharmony_ci     */
3604514f5e3Sopenharmony_ci    bool useMovz = BetterUseMOVZ(srcVal);
3614514f5e3Sopenharmony_ci    bool useMovk = false;
3624514f5e3Sopenharmony_ci    /* get lower 32 bits of the immediate */
3634514f5e3Sopenharmony_ci    uint64_t chunkLval = srcVal & 0xFFFFFFFFULL;
3644514f5e3Sopenharmony_ci    /* get upper 32 bits of the immediate */
3654514f5e3Sopenharmony_ci    uint64_t chunkHval = (srcVal >> k32BitSize) & 0xFFFFFFFFULL;
3664514f5e3Sopenharmony_ci    int32_t maxLoopTime = 4;
3674514f5e3Sopenharmony_ci
3684514f5e3Sopenharmony_ci    if (chunkLval == chunkHval) {
3694514f5e3Sopenharmony_ci        /* compute lower 32 bits, and then copy to higher 32 bits, so only 2 chunks need be processed */
3704514f5e3Sopenharmony_ci        maxLoopTime = 2;
3714514f5e3Sopenharmony_ci    }
3724514f5e3Sopenharmony_ci
3734514f5e3Sopenharmony_ci    uint64_t sa = 0;
3744514f5e3Sopenharmony_ci    for (int64_t i = 0; i < maxLoopTime; ++i, sa += k16BitSize) {
3754514f5e3Sopenharmony_ci        /* create an imm opereand which represents the i-th 16-bit chunk of the immediate */
3764514f5e3Sopenharmony_ci        uint64_t chunkVal = (srcVal >> (static_cast<uint64_t>(sa))) & 0x0000FFFFULL;
3774514f5e3Sopenharmony_ci        if (useMovz ? (chunkVal == 0) : (chunkVal == 0x0000FFFFULL)) {
3784514f5e3Sopenharmony_ci            continue;
3794514f5e3Sopenharmony_ci        }
3804514f5e3Sopenharmony_ci        int64_t src16 = static_cast<int64_t>(chunkVal);
3814514f5e3Sopenharmony_ci        if (!useMovk) {
3824514f5e3Sopenharmony_ci            /* use movz or movn */
3834514f5e3Sopenharmony_ci            if (!useMovz) {
3844514f5e3Sopenharmony_ci                src16 = ~(static_cast<uint64_t>(src16)) & ((1ULL << k16BitSize) - 1UL);
3854514f5e3Sopenharmony_ci                assembler.Movn(destReg, src16, sa);
3864514f5e3Sopenharmony_ci            } else {
3874514f5e3Sopenharmony_ci                assembler.Movz(destReg, src16, sa);
3884514f5e3Sopenharmony_ci            }
3894514f5e3Sopenharmony_ci            useMovk = true;
3904514f5e3Sopenharmony_ci        } else {
3914514f5e3Sopenharmony_ci            assembler.Movk(destReg, src16, sa);
3924514f5e3Sopenharmony_ci        }
3934514f5e3Sopenharmony_ci    }
3944514f5e3Sopenharmony_ci
3954514f5e3Sopenharmony_ci    if (maxLoopTime == 2) { /* as described above, only 2 chunks need be processed */
3964514f5e3Sopenharmony_ci        /* copy lower 32 bits to higher 32 bits */
3974514f5e3Sopenharmony_ci        uint32_t immr = -k32BitSize % k64BitSize; // immr = -shift % size
3984514f5e3Sopenharmony_ci        uint32_t imms = k32BitSize - 1; // imms = width - 1
3994514f5e3Sopenharmony_ci        assembler.Bfm(destReg, destReg, immr, imms);
4004514f5e3Sopenharmony_ci    }
4014514f5e3Sopenharmony_ci}
4024514f5e3Sopenharmony_ci
4034514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
404