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#ifndef ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
164514f5e3Sopenharmony_ci#define ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/compiler/assembler/assembler.h"
194514f5e3Sopenharmony_ci
204514f5e3Sopenharmony_cinamespace panda::ecmascript::x64 {
214514f5e3Sopenharmony_cienum Register : uint8_t {
224514f5e3Sopenharmony_ci    rax = 0,
234514f5e3Sopenharmony_ci    rcx,
244514f5e3Sopenharmony_ci    rdx,
254514f5e3Sopenharmony_ci    rbx,
264514f5e3Sopenharmony_ci    rsp,
274514f5e3Sopenharmony_ci    rbp,
284514f5e3Sopenharmony_ci    rsi,
294514f5e3Sopenharmony_ci    rdi,
304514f5e3Sopenharmony_ci    r8,
314514f5e3Sopenharmony_ci    r9,
324514f5e3Sopenharmony_ci    r10,
334514f5e3Sopenharmony_ci    r11,
344514f5e3Sopenharmony_ci    r12,
354514f5e3Sopenharmony_ci    r13,
364514f5e3Sopenharmony_ci    r14,
374514f5e3Sopenharmony_ci    r15,
384514f5e3Sopenharmony_ci    rInvalid,
394514f5e3Sopenharmony_ci};
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_cienum Scale : uint8_t {
424514f5e3Sopenharmony_ci    Times1 = 0,
434514f5e3Sopenharmony_ci    Times2,
444514f5e3Sopenharmony_ci    Times4,
454514f5e3Sopenharmony_ci    Times8
464514f5e3Sopenharmony_ci};
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ciclass Immediate {
494514f5e3Sopenharmony_cipublic:
504514f5e3Sopenharmony_ci    Immediate(int32_t value) : value_(value) {}
514514f5e3Sopenharmony_ci    ~Immediate() = default;
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_ci    int32_t Value() const
544514f5e3Sopenharmony_ci    {
554514f5e3Sopenharmony_ci        return value_;
564514f5e3Sopenharmony_ci    }
574514f5e3Sopenharmony_ciprivate:
584514f5e3Sopenharmony_ci    int32_t value_;
594514f5e3Sopenharmony_ci};
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ciclass Operand {
624514f5e3Sopenharmony_cipublic:
634514f5e3Sopenharmony_ci    Operand(Register base, int32_t disp);
644514f5e3Sopenharmony_ci    Operand(Register base, Register index, Scale scale, int32_t disp);
654514f5e3Sopenharmony_ci    Operand(Register index, Scale scale, int32_t disp);
664514f5e3Sopenharmony_ci    ~Operand() = default;
674514f5e3Sopenharmony_ci
684514f5e3Sopenharmony_ci    void BuildSIB(Scale scale, Register index, Register base);
694514f5e3Sopenharmony_ci    void BuildModerm(int32_t mode, Register rm);
704514f5e3Sopenharmony_ci    void BuildDisp8(int32_t disp);
714514f5e3Sopenharmony_ci    void BuildDisp32(int32_t disp);
724514f5e3Sopenharmony_ci    int32_t disp_ = 0;
734514f5e3Sopenharmony_ci    uint8_t rex_ = 0;
744514f5e3Sopenharmony_ci    uint8_t sib_ = 0;
754514f5e3Sopenharmony_ci    uint8_t moderm_ = 0;
764514f5e3Sopenharmony_ci    bool hasSIB_ = false;
774514f5e3Sopenharmony_ci    bool hasDisp8_ = false;
784514f5e3Sopenharmony_ci    bool hasDisp32_ = false;
794514f5e3Sopenharmony_ci};
804514f5e3Sopenharmony_ci
814514f5e3Sopenharmony_ci// The Intel 64 instruction format is:
824514f5e3Sopenharmony_ci// | prefixs| opcode| modR/M| SIB| Displacement| Immediate|
834514f5e3Sopenharmony_ciclass AssemblerX64 : public Assembler {
844514f5e3Sopenharmony_cipublic:
854514f5e3Sopenharmony_ci    explicit AssemblerX64(Chunk *chunk)
864514f5e3Sopenharmony_ci        : Assembler(chunk) {}
874514f5e3Sopenharmony_ci    ~AssemblerX64() = default;
884514f5e3Sopenharmony_ci
894514f5e3Sopenharmony_ci    void Pushq(Register x);
904514f5e3Sopenharmony_ci    void Pushq(Immediate x);
914514f5e3Sopenharmony_ci    void Push(Register x);
924514f5e3Sopenharmony_ci    void Popq(Register x);
934514f5e3Sopenharmony_ci    void Pop(Register x);
944514f5e3Sopenharmony_ci    void Movq(Register src, Register dst);
954514f5e3Sopenharmony_ci    void Movq(const Operand &src, Register dst);
964514f5e3Sopenharmony_ci    void Movq(Register src, const Operand &dst);
974514f5e3Sopenharmony_ci    void Movq(Immediate src, Operand dst);
984514f5e3Sopenharmony_ci    void Movq(Immediate src, Register dst);
994514f5e3Sopenharmony_ci    void Mov(const Operand &src, Register dst);
1004514f5e3Sopenharmony_ci    void Mov(Register src, Register dst);
1014514f5e3Sopenharmony_ci    void Addq(Immediate src, Register dst);
1024514f5e3Sopenharmony_ci    void Addq(Register src, Register dst);
1034514f5e3Sopenharmony_ci    void Addl(Immediate src, Register dst);
1044514f5e3Sopenharmony_ci    void Subq(Immediate src, Register dst);
1054514f5e3Sopenharmony_ci    void Subq(Register src, Register dst);
1064514f5e3Sopenharmony_ci    void Subl(Immediate src, Register dst);
1074514f5e3Sopenharmony_ci    void Cmpq(Immediate src, Register dst);
1084514f5e3Sopenharmony_ci    void Cmpq(Register src, Register dst);
1094514f5e3Sopenharmony_ci    void Cmpl(Immediate src, Register dst);
1104514f5e3Sopenharmony_ci    void Cmpb(Immediate src, Register dst);
1114514f5e3Sopenharmony_ci    void Cmp(Immediate src, Register dst);
1124514f5e3Sopenharmony_ci    void Callq(Register addr);
1134514f5e3Sopenharmony_ci    void Callq(Label *target);
1144514f5e3Sopenharmony_ci    void Ret();
1154514f5e3Sopenharmony_ci    void Jmp(Label *target, Distance distance = Distance::Far);
1164514f5e3Sopenharmony_ci    void Jmp(Register dst);
1174514f5e3Sopenharmony_ci    void Jmp(Immediate offset);
1184514f5e3Sopenharmony_ci    void Bind(Label* target);
1194514f5e3Sopenharmony_ci    void Align16();
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_ci    void Andq(Immediate src, Register dst);
1224514f5e3Sopenharmony_ci    void Andl(Immediate src, Register dst);
1234514f5e3Sopenharmony_ci    void And(Register src, Register dst);
1244514f5e3Sopenharmony_ci    void Or(Immediate src, Register dst);
1254514f5e3Sopenharmony_ci    void Orq(Register src, Register dst);
1264514f5e3Sopenharmony_ci    void Btq(Immediate src, Register dst);
1274514f5e3Sopenharmony_ci    void Btl(Immediate src, Register dst);
1284514f5e3Sopenharmony_ci    void Cmpl(Register src, Register dst);
1294514f5e3Sopenharmony_ci    void CMovbe(Register src, Register dst);
1304514f5e3Sopenharmony_ci    void Ja(Label *target, Distance distance = Distance::Far);
1314514f5e3Sopenharmony_ci    void Jb(Label *target, Distance distance = Distance::Far);
1324514f5e3Sopenharmony_ci    void Jz(Label *target, Distance distance = Distance::Far);
1334514f5e3Sopenharmony_ci    void Je(Label *target, Distance distance = Distance::Far);
1344514f5e3Sopenharmony_ci    void Jg(Label *target, Distance distance = Distance::Far);
1354514f5e3Sopenharmony_ci    void Jge(Label *target, Distance distance = Distance::Far);
1364514f5e3Sopenharmony_ci    void Jne(Label *target, Distance distance = Distance::Far);
1374514f5e3Sopenharmony_ci    void Jbe(Label *target, Distance distance = Distance::Far);
1384514f5e3Sopenharmony_ci    void Jnz(Label *target, Distance distance = Distance::Far);
1394514f5e3Sopenharmony_ci    void Jle(Label *target, Distance distance = Distance::Far);
1404514f5e3Sopenharmony_ci    void Jae(Label *target, Distance distance = Distance::Far);
1414514f5e3Sopenharmony_ci    void Jnb(Label *target, Distance distance = Distance::Far);
1424514f5e3Sopenharmony_ci    void Leaq(const Operand &src, Register dst);
1434514f5e3Sopenharmony_ci    void Leal(const Operand &src, Register dst);
1444514f5e3Sopenharmony_ci    void Movl(Register src, Register dst);
1454514f5e3Sopenharmony_ci    void Movl(const Operand &src, Register dst);
1464514f5e3Sopenharmony_ci    void Movl(Register dst, const Operand& src);
1474514f5e3Sopenharmony_ci    void Movzbq(const Operand &src, Register dst);
1484514f5e3Sopenharmony_ci    void Movzbl(const Operand &src, Register dst);
1494514f5e3Sopenharmony_ci    void Movzbl(Register src, Register dst);
1504514f5e3Sopenharmony_ci    void Movabs(uint64_t src, Register dst);
1514514f5e3Sopenharmony_ci    void Shrq(Immediate src, Register dst);
1524514f5e3Sopenharmony_ci    void Shrl(Immediate src, Register dst);
1534514f5e3Sopenharmony_ci    void Shr(Immediate src, Register dst);
1544514f5e3Sopenharmony_ci    void Shll(Immediate src, Register dst);
1554514f5e3Sopenharmony_ci    void Shlq(Immediate src, Register dst);
1564514f5e3Sopenharmony_ci    void Btsl(Register src, Register dst);
1574514f5e3Sopenharmony_ci    void Testq(Immediate src, Register dst);
1584514f5e3Sopenharmony_ci    void Testb(Immediate src, Register dst);
1594514f5e3Sopenharmony_ci    void Int3();
1604514f5e3Sopenharmony_ci    void Movzwq(const Operand &src, Register dst);
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ciprivate:
1634514f5e3Sopenharmony_ci    void EmitRexPrefix(const Register &x)
1644514f5e3Sopenharmony_ci    {
1654514f5e3Sopenharmony_ci        if (HighBit(x) != 0) {
1664514f5e3Sopenharmony_ci            EmitU8(REX_PREFIX_B);
1674514f5e3Sopenharmony_ci        }
1684514f5e3Sopenharmony_ci    }
1694514f5e3Sopenharmony_ci
1704514f5e3Sopenharmony_ci    void EmitRexPrefixW(const Register &rm)
1714514f5e3Sopenharmony_ci    {
1724514f5e3Sopenharmony_ci        EmitU8(REX_PREFIX_W | HighBit(rm));
1734514f5e3Sopenharmony_ci    }
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_ci    void EmitRexPrefixL(const Register &rm)
1764514f5e3Sopenharmony_ci    {
1774514f5e3Sopenharmony_ci        EmitU8(REX_PREFIX_FIXED_BITS | HighBit(rm));
1784514f5e3Sopenharmony_ci    }
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_ci    void EmitRexPrefix(const Operand &rm)
1814514f5e3Sopenharmony_ci    {
1824514f5e3Sopenharmony_ci        // 0: Extension to the MODRM.rm field B
1834514f5e3Sopenharmony_ci        EmitU8(REX_PREFIX_W | rm.rex_);
1844514f5e3Sopenharmony_ci    }
1854514f5e3Sopenharmony_ci
1864514f5e3Sopenharmony_ci    void EmitRexPrefix(Register reg, Register rm)
1874514f5e3Sopenharmony_ci    {
1884514f5e3Sopenharmony_ci        // 0: Extension to the MODRM.rm field B
1894514f5e3Sopenharmony_ci        // 2: Extension to the MODRM.reg field R
1904514f5e3Sopenharmony_ci        EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | HighBit(rm));
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci
1934514f5e3Sopenharmony_ci    void EmitRexPrefixl(Register reg, Register rm)
1944514f5e3Sopenharmony_ci    {
1954514f5e3Sopenharmony_ci        // 0: Extension to the MODRM.rm field B
1964514f5e3Sopenharmony_ci        if (HighBit(reg) != 0 || HighBit(rm) != 0) {
1974514f5e3Sopenharmony_ci            // 2: Extension to the MODRM.reg field R
1984514f5e3Sopenharmony_ci            EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | HighBit(rm));
1994514f5e3Sopenharmony_ci        }
2004514f5e3Sopenharmony_ci    }
2014514f5e3Sopenharmony_ci
2024514f5e3Sopenharmony_ci    void EmitRexPrefix(Register reg, Operand rm)
2034514f5e3Sopenharmony_ci    {
2044514f5e3Sopenharmony_ci        // 0: Extension to the MODRM.rm field B
2054514f5e3Sopenharmony_ci        // 2: Extension to the MODRM.reg field R
2064514f5e3Sopenharmony_ci        EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | rm.rex_);
2074514f5e3Sopenharmony_ci    }
2084514f5e3Sopenharmony_ci
2094514f5e3Sopenharmony_ci    void EmitRexPrefixl(Register reg, Operand rm)
2104514f5e3Sopenharmony_ci    {
2114514f5e3Sopenharmony_ci        // 0: Extension to the MODRM.rm field B
2124514f5e3Sopenharmony_ci        if (HighBit(reg) != 0 || rm.rex_ != 0) {
2134514f5e3Sopenharmony_ci            // 2: Extension to the MODRM.reg field R
2144514f5e3Sopenharmony_ci            EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | rm.rex_);
2154514f5e3Sopenharmony_ci        }
2164514f5e3Sopenharmony_ci    }
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2194514f5e3Sopenharmony_ci    // |  mod  |    reg    |     rm    |
2204514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2214514f5e3Sopenharmony_ci    void EmitModrm(int32_t reg, Register rm)
2224514f5e3Sopenharmony_ci    {
2234514f5e3Sopenharmony_ci        EmitU8(MODE_RM | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE) | LowBits(rm));
2244514f5e3Sopenharmony_ci    }
2254514f5e3Sopenharmony_ci
2264514f5e3Sopenharmony_ci    void EmitModrm(Register reg, Register rm)
2274514f5e3Sopenharmony_ci    {
2284514f5e3Sopenharmony_ci        EmitModrm(LowBits(reg), rm);
2294514f5e3Sopenharmony_ci    }
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_ci    void EmitOperand(Register reg, Operand rm)
2324514f5e3Sopenharmony_ci    {
2334514f5e3Sopenharmony_ci        EmitOperand(LowBits(reg), rm);
2344514f5e3Sopenharmony_ci    }
2354514f5e3Sopenharmony_ci    void EmitOperand(int32_t reg, Operand rm);
2364514f5e3Sopenharmony_ci    void EmitJmp(int32_t offset);
2374514f5e3Sopenharmony_ci    void EmitJa(int32_t offset);
2384514f5e3Sopenharmony_ci    void EmitJb(int32_t offset);
2394514f5e3Sopenharmony_ci    void EmitJz(int32_t offset);
2404514f5e3Sopenharmony_ci    void EmitJne(int32_t offset);
2414514f5e3Sopenharmony_ci    void EmitJbe(int32_t offset);
2424514f5e3Sopenharmony_ci    void EmitJnz(int32_t offset);
2434514f5e3Sopenharmony_ci    void EmitJle(int32_t offset);
2444514f5e3Sopenharmony_ci    void EmitJae(int32_t offset);
2454514f5e3Sopenharmony_ci    void EmitJg(int32_t offset);
2464514f5e3Sopenharmony_ci    void EmitJge(int32_t offset);
2474514f5e3Sopenharmony_ci    void EmitJe(int32_t offset);
2484514f5e3Sopenharmony_ci    void EmitCall(int32_t offset);
2494514f5e3Sopenharmony_ci    void EmitJnb(int32_t offset);
2504514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2514514f5e3Sopenharmony_ci    // | 0   1   0   0 | W | R | X | B |
2524514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2534514f5e3Sopenharmony_ci    static constexpr uint8_t REX_PREFIX_FIXED_BITS = 0x40;
2544514f5e3Sopenharmony_ci    static constexpr uint8_t REX_PREFIX_B = 0x41;
2554514f5e3Sopenharmony_ci    static constexpr uint8_t REX_PREFIX_W = 0x48;
2564514f5e3Sopenharmony_ci    // b11
2574514f5e3Sopenharmony_ci    static constexpr uint8_t MODE_RM = 0xC0;
2584514f5e3Sopenharmony_ci    // low bits: 3, high bit 1
2594514f5e3Sopenharmony_ci    static constexpr size_t LOW_BITS_SIZE = 3;
2604514f5e3Sopenharmony_ci    static constexpr size_t LOW_BITS_MASK = (1 << LOW_BITS_SIZE) - 1;
2614514f5e3Sopenharmony_ci
2624514f5e3Sopenharmony_ci    static constexpr int32_t SIZE_OF_INT8 = static_cast<int32_t>(sizeof(int8_t));
2634514f5e3Sopenharmony_ci    static constexpr int32_t SIZE_OF_INT32 = static_cast<int32_t>(sizeof(int32_t));
2644514f5e3Sopenharmony_ci
2654514f5e3Sopenharmony_ci    static uint8_t GetModrm(int32_t mode, Register rm)
2664514f5e3Sopenharmony_ci    {
2674514f5e3Sopenharmony_ci        // [r/m]
2684514f5e3Sopenharmony_ci        // [r/m + disp8]
2694514f5e3Sopenharmony_ci        // [r/m + disp32]
2704514f5e3Sopenharmony_ci        // 6: offset of mode
2714514f5e3Sopenharmony_ci        return (static_cast<uint32_t>(mode) << 6) | LowBits(rm);
2724514f5e3Sopenharmony_ci    }
2734514f5e3Sopenharmony_ci    static uint8_t GetModrmRex(Register rm)
2744514f5e3Sopenharmony_ci    {
2754514f5e3Sopenharmony_ci        return HighBit(rm);
2764514f5e3Sopenharmony_ci    }
2774514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2784514f5e3Sopenharmony_ci    // | scale |   index   |    base   |
2794514f5e3Sopenharmony_ci    // +---+---+---+---+---+---+---+---+
2804514f5e3Sopenharmony_ci    static uint8_t GetSIB(Scale scale, Register index, Register base)
2814514f5e3Sopenharmony_ci    {
2824514f5e3Sopenharmony_ci        // 6: offset of scale
2834514f5e3Sopenharmony_ci        return (static_cast<uint8_t>(scale) << 6) | (LowBits(index) << LOW_BITS_SIZE) |
2844514f5e3Sopenharmony_ci            LowBits(base);
2854514f5e3Sopenharmony_ci    }
2864514f5e3Sopenharmony_ci    static uint8_t GetSIBRex(Register index, Register base)
2874514f5e3Sopenharmony_ci    {
2884514f5e3Sopenharmony_ci        return (HighBit(index) << 1) | HighBit(base);
2894514f5e3Sopenharmony_ci    }
2904514f5e3Sopenharmony_ci    static uint32_t LowBits(Register x)
2914514f5e3Sopenharmony_ci    {
2924514f5e3Sopenharmony_ci        return static_cast<uint8_t>(x) & LOW_BITS_MASK;
2934514f5e3Sopenharmony_ci    }
2944514f5e3Sopenharmony_ci    static uint32_t HighBit(Register x)
2954514f5e3Sopenharmony_ci    {
2964514f5e3Sopenharmony_ci        return static_cast<uint8_t>(x) >> LOW_BITS_SIZE;
2974514f5e3Sopenharmony_ci    }
2984514f5e3Sopenharmony_ci    friend class Operand;
2994514f5e3Sopenharmony_ci};
3004514f5e3Sopenharmony_ci}  // panda::ecmascript::x64
3014514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
302