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 
20 namespace panda::ecmascript::x64 {
21 enum 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 
41 enum Scale : uint8_t {
42     Times1 = 0,
43     Times2,
44     Times4,
45     Times8
46 };
47 
48 class Immediate {
49 public:
Immediate(int32_t value)50     Immediate(int32_t value) : value_(value) {}
51     ~Immediate() = default;
52 
Value() const53     int32_t Value() const
54     {
55         return value_;
56     }
57 private:
58     int32_t value_;
59 };
60 
61 class Operand {
62 public:
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|
83 class AssemblerX64 : public Assembler {
84 public:
AssemblerX64(Chunk *chunk)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 
162 private:
EmitRexPrefix(const Register &x)163     void EmitRexPrefix(const Register &x)
164     {
165         if (HighBit(x) != 0) {
166             EmitU8(REX_PREFIX_B);
167         }
168     }
169 
EmitRexPrefixW(const Register &rm)170     void EmitRexPrefixW(const Register &rm)
171     {
172         EmitU8(REX_PREFIX_W | HighBit(rm));
173     }
174 
EmitRexPrefixL(const Register &rm)175     void EmitRexPrefixL(const Register &rm)
176     {
177         EmitU8(REX_PREFIX_FIXED_BITS | HighBit(rm));
178     }
179 
EmitRexPrefix(const Operand &rm)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 
EmitRexPrefix(Register reg, Register rm)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 
EmitRexPrefixl(Register reg, Register rm)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 
EmitRexPrefix(Register reg, Operand rm)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 
EmitRexPrefixl(Register reg, Operand rm)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     // +---+---+---+---+---+---+---+---+
EmitModrm(int32_t reg, Register rm)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 
EmitModrm(Register reg, Register rm)226     void EmitModrm(Register reg, Register rm)
227     {
228         EmitModrm(LowBits(reg), rm);
229     }
230 
EmitOperand(Register reg, Operand rm)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 
GetModrm(int32_t mode, Register rm)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     }
GetModrmRex(Register rm)273     static uint8_t GetModrmRex(Register rm)
274     {
275         return HighBit(rm);
276     }
277     // +---+---+---+---+---+---+---+---+
278     // | scale |   index   |    base   |
279     // +---+---+---+---+---+---+---+---+
GetSIB(Scale scale, Register index, Register base)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     }
GetSIBRex(Register index, Register base)286     static uint8_t GetSIBRex(Register index, Register base)
287     {
288         return (HighBit(index) << 1) | HighBit(base);
289     }
LowBits(Register x)290     static uint32_t LowBits(Register x)
291     {
292         return static_cast<uint8_t>(x) & LOW_BITS_MASK;
293     }
HighBit(Register x)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