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> ¶meters) 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