• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()53     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 Movzbq(const Operand &src, Register dst);
147     void Movabs(uint64_t src, Register dst);
148     void Shrq(Immediate src, Register dst);
149     void Shr(Immediate src, Register dst);
150     void Shll(Immediate src, Register dst);
151     void Shlq(Immediate src, Register dst);
152     void Testq(Immediate src, Register dst);
153     void Testb(Immediate src, Register dst);
154     void Int3();
155     void Movzwq(const Operand &src, Register dst);
156 
157 private:
EmitRexPrefix(const Register & x)158     void EmitRexPrefix(const Register &x)
159     {
160         if (HighBit(x) != 0) {
161             EmitU8(REX_PREFIX_B);
162         }
163     }
164 
EmitRexPrefixW(const Register & rm)165     void EmitRexPrefixW(const Register &rm)
166     {
167         EmitU8(REX_PREFIX_W | HighBit(rm));
168     }
169 
EmitRexPrefixL(const Register & rm)170     void EmitRexPrefixL(const Register &rm)
171     {
172         EmitU8(REX_PREFIX_FIXED_BITS | HighBit(rm));
173     }
174 
EmitRexPrefix(const Operand & rm)175     void EmitRexPrefix(const Operand &rm)
176     {
177         // 0: Extension to the MODRM.rm field B
178         EmitU8(REX_PREFIX_W | rm.rex_);
179     }
180 
EmitRexPrefix(Register reg,Register rm)181     void EmitRexPrefix(Register reg, Register rm)
182     {
183         // 0: Extension to the MODRM.rm field B
184         // 2: Extension to the MODRM.reg field R
185         EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | HighBit(rm));
186     }
187 
EmitRexPrefixl(Register reg,Register rm)188     void EmitRexPrefixl(Register reg, Register rm)
189     {
190         // 0: Extension to the MODRM.rm field B
191         if (HighBit(reg) != 0 || HighBit(rm) != 0) {
192             // 2: Extension to the MODRM.reg field R
193             EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | HighBit(rm));
194         }
195     }
196 
EmitRexPrefix(Register reg,Operand rm)197     void EmitRexPrefix(Register reg, Operand rm)
198     {
199         // 0: Extension to the MODRM.rm field B
200         // 2: Extension to the MODRM.reg field R
201         EmitU8(REX_PREFIX_W | (HighBit(reg) << 2) | rm.rex_);
202     }
203 
EmitRexPrefixl(Register reg,Operand rm)204     void EmitRexPrefixl(Register reg, Operand rm)
205     {
206         // 0: Extension to the MODRM.rm field B
207         if (HighBit(reg) != 0 || rm.rex_ != 0) {
208             // 2: Extension to the MODRM.reg field R
209             EmitU8(REX_PREFIX_FIXED_BITS | (HighBit(reg) << 2) | rm.rex_);
210         }
211     }
212 
213     // +---+---+---+---+---+---+---+---+
214     // |  mod  |    reg    |     rm    |
215     // +---+---+---+---+---+---+---+---+
EmitModrm(int32_t reg,Register rm)216     void EmitModrm(int32_t reg, Register rm)
217     {
218         EmitU8(MODE_RM | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE) | LowBits(rm));
219     }
220 
EmitModrm(Register reg,Register rm)221     void EmitModrm(Register reg, Register rm)
222     {
223         EmitModrm(LowBits(reg), rm);
224     }
225 
EmitOperand(Register reg,Operand rm)226     void EmitOperand(Register reg, Operand rm)
227     {
228         EmitOperand(LowBits(reg), rm);
229     }
230     void EmitOperand(int32_t reg, Operand rm);
231     void EmitJmp(int32_t offset);
232     void EmitJa(int32_t offset);
233     void EmitJb(int32_t offset);
234     void EmitJz(int32_t offset);
235     void EmitJne(int32_t offset);
236     void EmitJbe(int32_t offset);
237     void EmitJnz(int32_t offset);
238     void EmitJle(int32_t offset);
239     void EmitJae(int32_t offset);
240     void EmitJg(int32_t offset);
241     void EmitJge(int32_t offset);
242     void EmitJe(int32_t offset);
243     void EmitCall(int32_t offset);
244     void EmitJnb(int32_t offset);
245     // +---+---+---+---+---+---+---+---+
246     // | 0   1   0   0 | W | R | X | B |
247     // +---+---+---+---+---+---+---+---+
248     static constexpr uint8_t REX_PREFIX_FIXED_BITS = 0x40;
249     static constexpr uint8_t REX_PREFIX_B = 0x41;
250     static constexpr uint8_t REX_PREFIX_W = 0x48;
251     // b11
252     static constexpr uint8_t MODE_RM = 0xC0;
253     // low bits: 3, high bit 1
254     static constexpr size_t LOW_BITS_SIZE = 3;
255     static constexpr size_t LOW_BITS_MASK = (1 << LOW_BITS_SIZE) - 1;
256 
GetModrm(int32_t mode,Register rm)257     static uint8_t GetModrm(int32_t mode, Register rm)
258     {
259         // [r/m]
260         // [r/m + disp8]
261         // [r/m + disp32]
262         // 6: offset of mode
263         return (static_cast<uint32_t>(mode) << 6) | LowBits(rm);
264     }
GetModrmRex(Register rm)265     static uint8_t GetModrmRex(Register rm)
266     {
267         return HighBit(rm);
268     }
269     // +---+---+---+---+---+---+---+---+
270     // | scale |   index   |    base   |
271     // +---+---+---+---+---+---+---+---+
GetSIB(Scale scale,Register index,Register base)272     static uint8_t GetSIB(Scale scale, Register index, Register base)
273     {
274         // 6: offset of scale
275         return (static_cast<uint8_t>(scale) << 6) | (LowBits(index) << LOW_BITS_SIZE) |
276             LowBits(base);
277     }
GetSIBRex(Register index,Register base)278     static uint8_t GetSIBRex(Register index, Register base)
279     {
280         return (HighBit(index) << 1) | HighBit(base);
281     }
LowBits(Register x)282     static uint32_t LowBits(Register x)
283     {
284         return static_cast<uint8_t>(x) & LOW_BITS_MASK;
285     }
HighBit(Register x)286     static uint32_t HighBit(Register x)
287     {
288         return static_cast<uint8_t>(x) >> LOW_BITS_SIZE;
289     }
290     friend class Operand;
291 };
292 }  // panda::ecmascript::x64
293 #endif  // ECMASCRIPT_COMPILER_ASSEMBLER_X64_H
294