1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifndef ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
16#define ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
17
18#include "ecmascript/compiler/assembler/assembler.h"
19
20namespace panda::ecmascript::x64 {
21enum Register : uint8_t {
22    rax = 0,
23    rcx,
24    rdx,
25    rbx,
26    rsp,
27    rbp,
28    rsi,
29    rdi,
30    r8,
31    r9,
32    r10,
33    r11,
34    r12,
35    r13,
36    r14,
37    r15,
38    rInvalid,
39};
40
41enum Scale : uint8_t {
42    Times1 = 0,
43    Times2,
44    Times4,
45    Times8
46};
47
48class Immediate {
49public:
50    Immediate(int32_t value) : value_(value) {}
51    ~Immediate() = default;
52
53    int32_t Value() const
54    {
55        return value_;
56    }
57private:
58    int32_t value_;
59};
60
61class Operand {
62public:
63    Operand(Register base, int32_t disp);
64    Operand(Register base, Register index, Scale scale, int32_t disp);
65    Operand(Register index, Scale scale, int32_t disp);
66    ~Operand() = default;
67
68    void BuildSIB(Scale scale, Register index, Register base);
69    void BuildModerm(int32_t mode, Register rm);
70    void BuildDisp8(int32_t disp);
71    void BuildDisp32(int32_t disp);
72    int32_t disp_ = 0;
73    uint8_t rex_ = 0;
74    uint8_t sib_ = 0;
75    uint8_t moderm_ = 0;
76    bool hasSIB_ = false;
77    bool hasDisp8_ = false;
78    bool hasDisp32_ = false;
79};
80
81// The Intel 64 instruction format is:
82// | prefixs| opcode| modR/M| SIB| Displacement| Immediate|
83class AssemblerX64 : public Assembler {
84public:
85    explicit AssemblerX64(Chunk *chunk)
86        : Assembler(chunk) {}
87    ~AssemblerX64() = default;
88
89    void Pushq(Register x);
90    void Pushq(Immediate x);
91    void Push(Register x);
92    void Popq(Register x);
93    void Pop(Register x);
94    void Movq(Register src, Register dst);
95    void Movq(const Operand &src, Register dst);
96    void Movq(Register src, const Operand &dst);
97    void Movq(Immediate src, Operand dst);
98    void Movq(Immediate src, Register dst);
99    void Mov(const Operand &src, Register dst);
100    void Mov(Register src, Register dst);
101    void Addq(Immediate src, Register dst);
102    void Addq(Register src, Register dst);
103    void Addl(Immediate src, Register dst);
104    void Subq(Immediate src, Register dst);
105    void Subq(Register src, Register dst);
106    void Subl(Immediate src, Register dst);
107    void Cmpq(Immediate src, Register dst);
108    void Cmpq(Register src, Register dst);
109    void Cmpl(Immediate src, Register dst);
110    void Cmpb(Immediate src, Register dst);
111    void Cmp(Immediate src, Register dst);
112    void Callq(Register addr);
113    void Callq(Label *target);
114    void Ret();
115    void Jmp(Label *target, Distance distance = Distance::Far);
116    void Jmp(Register dst);
117    void Jmp(Immediate offset);
118    void Bind(Label* target);
119    void Align16();
120
121    void Andq(Immediate src, Register dst);
122    void Andl(Immediate src, Register dst);
123    void And(Register src, Register dst);
124    void Or(Immediate src, Register dst);
125    void Orq(Register src, Register dst);
126    void Btq(Immediate src, Register dst);
127    void Btl(Immediate src, Register dst);
128    void Cmpl(Register src, Register dst);
129    void CMovbe(Register src, Register dst);
130    void Ja(Label *target, Distance distance = Distance::Far);
131    void Jb(Label *target, Distance distance = Distance::Far);
132    void Jz(Label *target, Distance distance = Distance::Far);
133    void Je(Label *target, Distance distance = Distance::Far);
134    void Jg(Label *target, Distance distance = Distance::Far);
135    void Jge(Label *target, Distance distance = Distance::Far);
136    void Jne(Label *target, Distance distance = Distance::Far);
137    void Jbe(Label *target, Distance distance = Distance::Far);
138    void Jnz(Label *target, Distance distance = Distance::Far);
139    void Jle(Label *target, Distance distance = Distance::Far);
140    void Jae(Label *target, Distance distance = Distance::Far);
141    void Jnb(Label *target, Distance distance = Distance::Far);
142    void Leaq(const Operand &src, Register dst);
143    void Leal(const Operand &src, Register dst);
144    void Movl(Register src, Register dst);
145    void Movl(const Operand &src, Register dst);
146    void Movl(Register dst, const Operand& src);
147    void Movzbq(const Operand &src, Register dst);
148    void Movzbl(const Operand &src, Register dst);
149    void Movzbl(Register src, Register dst);
150    void Movabs(uint64_t src, Register dst);
151    void Shrq(Immediate src, Register dst);
152    void Shrl(Immediate src, Register dst);
153    void Shr(Immediate src, Register dst);
154    void Shll(Immediate src, Register dst);
155    void Shlq(Immediate src, Register dst);
156    void Btsl(Register src, Register dst);
157    void Testq(Immediate src, Register dst);
158    void Testb(Immediate src, Register dst);
159    void Int3();
160    void Movzwq(const Operand &src, Register dst);
161
162private:
163    void EmitRexPrefix(const Register &x)
164    {
165        if (HighBit(x) != 0) {
166            EmitU8(REX_PREFIX_B);
167        }
168    }
169
170    void EmitRexPrefixW(const Register &rm)
171    {
172        EmitU8(REX_PREFIX_W | HighBit(rm));
173    }
174
175    void EmitRexPrefixL(const Register &rm)
176    {
177        EmitU8(REX_PREFIX_FIXED_BITS | HighBit(rm));
178    }
179
180    void EmitRexPrefix(const Operand &rm)
181    {
182        // 0: Extension to the MODRM.rm field B
183        EmitU8(REX_PREFIX_W | rm.rex_);
184    }
185
186    void EmitRexPrefix(Register reg, Register rm)
187    {
188        // 0: Extension to the MODRM.rm field B
189        // 2: Extension to the MODRM.reg field R
190        EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | HighBit(rm));
191    }
192
193    void EmitRexPrefixl(Register reg, Register rm)
194    {
195        // 0: Extension to the MODRM.rm field B
196        if (HighBit(reg) != 0 || HighBit(rm) != 0) {
197            // 2: Extension to the MODRM.reg field R
198            EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | HighBit(rm));
199        }
200    }
201
202    void EmitRexPrefix(Register reg, Operand rm)
203    {
204        // 0: Extension to the MODRM.rm field B
205        // 2: Extension to the MODRM.reg field R
206        EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | rm.rex_);
207    }
208
209    void EmitRexPrefixl(Register reg, Operand rm)
210    {
211        // 0: Extension to the MODRM.rm field B
212        if (HighBit(reg) != 0 || rm.rex_ != 0) {
213            // 2: Extension to the MODRM.reg field R
214            EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | rm.rex_);
215        }
216    }
217
218    // +---+---+---+---+---+---+---+---+
219    // |  mod  |    reg    |     rm    |
220    // +---+---+---+---+---+---+---+---+
221    void EmitModrm(int32_t reg, Register rm)
222    {
223        EmitU8(MODE_RM | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE) | LowBits(rm));
224    }
225
226    void EmitModrm(Register reg, Register rm)
227    {
228        EmitModrm(LowBits(reg), rm);
229    }
230
231    void EmitOperand(Register reg, Operand rm)
232    {
233        EmitOperand(LowBits(reg), rm);
234    }
235    void EmitOperand(int32_t reg, Operand rm);
236    void EmitJmp(int32_t offset);
237    void EmitJa(int32_t offset);
238    void EmitJb(int32_t offset);
239    void EmitJz(int32_t offset);
240    void EmitJne(int32_t offset);
241    void EmitJbe(int32_t offset);
242    void EmitJnz(int32_t offset);
243    void EmitJle(int32_t offset);
244    void EmitJae(int32_t offset);
245    void EmitJg(int32_t offset);
246    void EmitJge(int32_t offset);
247    void EmitJe(int32_t offset);
248    void EmitCall(int32_t offset);
249    void EmitJnb(int32_t offset);
250    // +---+---+---+---+---+---+---+---+
251    // | 0   1   0   0 | W | R | X | B |
252    // +---+---+---+---+---+---+---+---+
253    static constexpr uint8_t REX_PREFIX_FIXED_BITS = 0x40;
254    static constexpr uint8_t REX_PREFIX_B = 0x41;
255    static constexpr uint8_t REX_PREFIX_W = 0x48;
256    // b11
257    static constexpr uint8_t MODE_RM = 0xC0;
258    // low bits: 3, high bit 1
259    static constexpr size_t LOW_BITS_SIZE = 3;
260    static constexpr size_t LOW_BITS_MASK = (1 << LOW_BITS_SIZE) - 1;
261
262    static constexpr int32_t SIZE_OF_INT8 = static_cast<int32_t>(sizeof(int8_t));
263    static constexpr int32_t SIZE_OF_INT32 = static_cast<int32_t>(sizeof(int32_t));
264
265    static uint8_t GetModrm(int32_t mode, Register rm)
266    {
267        // [r/m]
268        // [r/m + disp8]
269        // [r/m + disp32]
270        // 6: offset of mode
271        return (static_cast<uint32_t>(mode) << 6) | LowBits(rm);
272    }
273    static uint8_t GetModrmRex(Register rm)
274    {
275        return HighBit(rm);
276    }
277    // +---+---+---+---+---+---+---+---+
278    // | scale |   index   |    base   |
279    // +---+---+---+---+---+---+---+---+
280    static uint8_t GetSIB(Scale scale, Register index, Register base)
281    {
282        // 6: offset of scale
283        return (static_cast<uint8_t>(scale) << 6) | (LowBits(index) << LOW_BITS_SIZE) |
284            LowBits(base);
285    }
286    static uint8_t GetSIBRex(Register index, Register base)
287    {
288        return (HighBit(index) << 1) | HighBit(base);
289    }
290    static uint32_t LowBits(Register x)
291    {
292        return static_cast<uint8_t>(x) & LOW_BITS_MASK;
293    }
294    static uint32_t HighBit(Register x)
295    {
296        return static_cast<uint8_t>(x) >> LOW_BITS_SIZE;
297    }
298    friend class Operand;
299};
300}  // panda::ecmascript::x64
301#endif  // ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
302