Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <stdint.h>
28 : : #include <stdio.h>
29 : : #include <assert.h>
30 : : #include <string.h>
31 : :
32 : : #include "py/mpconfig.h"
33 : :
34 : : // wrapper around everything in this file
35 : : #if MICROPY_EMIT_X64
36 : :
37 : : #include "py/asmx64.h"
38 : :
39 : : /* all offsets are measured in multiples of 8 bytes */
40 : : #define WORD_SIZE (8)
41 : :
42 : : #define OPCODE_NOP (0x90)
43 : : #define OPCODE_PUSH_R64 (0x50) /* +rq */
44 : : #define OPCODE_PUSH_I64 (0x68)
45 : : #define OPCODE_PUSH_M64 (0xff) /* /6 */
46 : : #define OPCODE_POP_R64 (0x58) /* +rq */
47 : : #define OPCODE_RET (0xc3)
48 : : #define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */
49 : : #define OPCODE_MOV_I64_TO_R64 (0xb8) /* +rq */
50 : : #define OPCODE_MOV_I32_TO_RM32 (0xc7)
51 : : #define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */
52 : : #define OPCODE_MOV_R64_TO_RM64 (0x89) /* /r */
53 : : #define OPCODE_MOV_RM64_TO_R64 (0x8b) /* /r */
54 : : #define OPCODE_MOVZX_RM8_TO_R64 (0xb6) /* 0x0f 0xb6/r */
55 : : #define OPCODE_MOVZX_RM16_TO_R64 (0xb7) /* 0x0f 0xb7/r */
56 : : #define OPCODE_LEA_MEM_TO_R64 (0x8d) /* /r */
57 : : #define OPCODE_NOT_RM64 (0xf7) /* /2 */
58 : : #define OPCODE_NEG_RM64 (0xf7) /* /3 */
59 : : #define OPCODE_AND_R64_TO_RM64 (0x21) /* /r */
60 : : #define OPCODE_OR_R64_TO_RM64 (0x09) /* /r */
61 : : #define OPCODE_XOR_R64_TO_RM64 (0x31) /* /r */
62 : : #define OPCODE_ADD_R64_TO_RM64 (0x01) /* /r */
63 : : #define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
64 : : #define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */
65 : : #define OPCODE_SUB_R64_FROM_RM64 (0x29)
66 : : #define OPCODE_SUB_I32_FROM_RM64 (0x81) /* /5 */
67 : : #define OPCODE_SUB_I8_FROM_RM64 (0x83) /* /5 */
68 : : // #define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */
69 : : // #define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */
70 : : // #define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */
71 : : #define OPCODE_SHL_RM64_CL (0xd3) /* /4 */
72 : : #define OPCODE_SHR_RM64_CL (0xd3) /* /5 */
73 : : #define OPCODE_SAR_RM64_CL (0xd3) /* /7 */
74 : : // #define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
75 : : // #define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */
76 : : #define OPCODE_CMP_R64_WITH_RM64 (0x39) /* /r */
77 : : // #define OPCODE_CMP_RM32_WITH_R32 (0x3b)
78 : : #define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */
79 : : #define OPCODE_TEST_R64_WITH_RM64 (0x85) /* /r */
80 : : #define OPCODE_JMP_REL8 (0xeb)
81 : : #define OPCODE_JMP_REL32 (0xe9)
82 : : #define OPCODE_JMP_RM64 (0xff) /* /4 */
83 : : #define OPCODE_JCC_REL8 (0x70) /* | jcc type */
84 : : #define OPCODE_JCC_REL32_A (0x0f)
85 : : #define OPCODE_JCC_REL32_B (0x80) /* | jcc type */
86 : : #define OPCODE_SETCC_RM8_A (0x0f)
87 : : #define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */
88 : : #define OPCODE_CALL_REL32 (0xe8)
89 : : #define OPCODE_CALL_RM32 (0xff) /* /2 */
90 : : #define OPCODE_LEAVE (0xc9)
91 : :
92 : : #define MODRM_R64(x) (((x) & 0x7) << 3)
93 : : #define MODRM_RM_DISP0 (0x00)
94 : : #define MODRM_RM_DISP8 (0x40)
95 : : #define MODRM_RM_DISP32 (0x80)
96 : : #define MODRM_RM_REG (0xc0)
97 : : #define MODRM_RM_R64(x) ((x) & 0x7)
98 : :
99 : : #define OP_SIZE_PREFIX (0x66)
100 : :
101 : : #define REX_PREFIX (0x40)
102 : : #define REX_W (0x08) // width
103 : : #define REX_R (0x04) // register
104 : : #define REX_X (0x02) // index
105 : : #define REX_B (0x01) // base
106 : : #define REX_W_FROM_R64(r64) ((r64) >> 0 & 0x08)
107 : : #define REX_R_FROM_R64(r64) ((r64) >> 1 & 0x04)
108 : : #define REX_X_FROM_R64(r64) ((r64) >> 2 & 0x02)
109 : : #define REX_B_FROM_R64(r64) ((r64) >> 3 & 0x01)
110 : :
111 : : #define IMM32_L0(x) ((x) & 0xff)
112 : : #define IMM32_L1(x) (((x) >> 8) & 0xff)
113 : : #define IMM32_L2(x) (((x) >> 16) & 0xff)
114 : : #define IMM32_L3(x) (((x) >> 24) & 0xff)
115 : : #define IMM64_L4(x) (((x) >> 32) & 0xff)
116 : : #define IMM64_L5(x) (((x) >> 40) & 0xff)
117 : : #define IMM64_L6(x) (((x) >> 48) & 0xff)
118 : : #define IMM64_L7(x) (((x) >> 56) & 0xff)
119 : :
120 : : #define UNSIGNED_FIT8(x) (((x) & 0xffffffffffffff00) == 0)
121 : : #define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0)
122 : : #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
123 : :
124 : 5199035 : static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) {
125 : 5199035 : return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
126 : : }
127 : :
128 : 2571823 : static void asm_x64_write_byte_1(asm_x64_t *as, byte b1) {
129 : 2571823 : byte *c = asm_x64_get_cur_to_write_bytes(as, 1);
130 [ + + ]: 2571823 : if (c != NULL) {
131 : 846685 : c[0] = b1;
132 : : }
133 : 2571823 : }
134 : :
135 : 1505001 : static void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) {
136 : 1505001 : byte *c = asm_x64_get_cur_to_write_bytes(as, 2);
137 [ + + ]: 1505001 : if (c != NULL) {
138 : 497942 : c[0] = b1;
139 : 497942 : c[1] = b2;
140 : : }
141 : 1505001 : }
142 : :
143 : 203355 : static void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) {
144 : 203355 : byte *c = asm_x64_get_cur_to_write_bytes(as, 3);
145 [ + + ]: 203355 : if (c != NULL) {
146 : 67337 : c[0] = b1;
147 : 67337 : c[1] = b2;
148 : 67337 : c[2] = b3;
149 : : }
150 : 203355 : }
151 : :
152 : 916798 : static void asm_x64_write_word32(asm_x64_t *as, int w32) {
153 : 916798 : byte *c = asm_x64_get_cur_to_write_bytes(as, 4);
154 [ + + ]: 916798 : if (c != NULL) {
155 : 302940 : c[0] = IMM32_L0(w32);
156 : 302940 : c[1] = IMM32_L1(w32);
157 : 302940 : c[2] = IMM32_L2(w32);
158 : 302940 : c[3] = IMM32_L3(w32);
159 : : }
160 : 916798 : }
161 : :
162 : 2058 : static void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {
163 : 2058 : byte *c = asm_x64_get_cur_to_write_bytes(as, 8);
164 [ + + ]: 2058 : if (c != NULL) {
165 : 686 : c[0] = IMM32_L0(w64);
166 : 686 : c[1] = IMM32_L1(w64);
167 : 686 : c[2] = IMM32_L2(w64);
168 : 686 : c[3] = IMM32_L3(w64);
169 : 686 : c[4] = IMM64_L4(w64);
170 : 686 : c[5] = IMM64_L5(w64);
171 : 686 : c[6] = IMM64_L6(w64);
172 : 686 : c[7] = IMM64_L7(w64);
173 : : }
174 : 2058 : }
175 : :
176 : : /* unused
177 : : static void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {
178 : : byte* c;
179 : : assert(offset + 4 <= as->code_size);
180 : : c = as->code_base + offset;
181 : : c[0] = IMM32_L0(w32);
182 : : c[1] = IMM32_L1(w32);
183 : : c[2] = IMM32_L2(w32);
184 : : c[3] = IMM32_L3(w32);
185 : : }
186 : : */
187 : :
188 : 1032670 : static void asm_x64_write_r64_disp(asm_x64_t *as, int r64, int disp_r64, int disp_offset) {
189 : 1032670 : uint8_t rm_disp;
190 [ + + + + ]: 1032670 : if (disp_offset == 0 && (disp_r64 & 7) != ASM_X64_REG_RBP) {
191 : : rm_disp = MODRM_RM_DISP0;
192 [ + + + - ]: 1019595 : } else if (SIGNED_FIT8(disp_offset)) {
193 : : rm_disp = MODRM_RM_DISP8;
194 : : } else {
195 : 458109 : rm_disp = MODRM_RM_DISP32;
196 : : }
197 : 1032670 : asm_x64_write_byte_1(as, MODRM_R64(r64) | rm_disp | MODRM_RM_R64(disp_r64));
198 [ + + ]: 1032670 : if ((disp_r64 & 7) == ASM_X64_REG_RSP) {
199 : : // Special case for rsp and r12, they need a SIB byte
200 : 502317 : asm_x64_write_byte_1(as, 0x24);
201 : : }
202 [ + + ]: 1032670 : if (rm_disp == MODRM_RM_DISP8) {
203 : 561486 : asm_x64_write_byte_1(as, IMM32_L0(disp_offset));
204 [ + + ]: 471184 : } else if (rm_disp == MODRM_RM_DISP32) {
205 : 458109 : asm_x64_write_word32(as, disp_offset);
206 : : }
207 : 1032670 : }
208 : :
209 : 163419 : static void asm_x64_generic_r64_r64(asm_x64_t *as, int dest_r64, int src_r64, int op) {
210 : 163419 : asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), op, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
211 : 163419 : }
212 : :
213 : 0 : void asm_x64_nop(asm_x64_t *as) {
214 : 0 : asm_x64_write_byte_1(as, OPCODE_NOP);
215 : 0 : }
216 : :
217 : 54644 : void asm_x64_push_r64(asm_x64_t *as, int src_r64) {
218 [ + + ]: 54644 : if (src_r64 < 8) {
219 : 27322 : asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64);
220 : : } else {
221 : 27322 : asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_PUSH_R64 | (src_r64 & 7));
222 : : }
223 : 54644 : }
224 : :
225 : : /*
226 : : void asm_x64_push_i32(asm_x64_t *as, int src_i32) {
227 : : asm_x64_write_byte_1(as, OPCODE_PUSH_I64);
228 : : asm_x64_write_word32(as, src_i32); // will be sign extended to 64 bits
229 : : }
230 : : */
231 : :
232 : : /*
233 : : void asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) {
234 : : assert(src_r64 < 8);
235 : : asm_x64_write_byte_1(as, OPCODE_PUSH_M64);
236 : : asm_x64_write_r64_disp(as, 6, src_r64, src_offset);
237 : : }
238 : : */
239 : :
240 : 58680 : void asm_x64_pop_r64(asm_x64_t *as, int dest_r64) {
241 [ + + ]: 58680 : if (dest_r64 < 8) {
242 : 29340 : asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64);
243 : : } else {
244 : 29340 : asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_POP_R64 | (dest_r64 & 7));
245 : : }
246 : 58680 : }
247 : :
248 : 14670 : static void asm_x64_ret(asm_x64_t *as) {
249 : 14670 : asm_x64_write_byte_1(as, OPCODE_RET);
250 : 14670 : }
251 : :
252 : 123173 : void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
253 : 123173 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_MOV_R64_TO_RM64);
254 : 123173 : }
255 : :
256 : 60 : void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
257 [ + - ]: 60 : if (src_r64 < 8 && dest_r64 < 8) {
258 : 60 : asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);
259 : : } else {
260 : 0 : asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R8_TO_RM8);
261 : : }
262 : 60 : asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
263 : 60 : }
264 : :
265 : 24 : void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
266 [ + - ]: 24 : if (src_r64 < 8 && dest_r64 < 8) {
267 : 24 : asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64);
268 : : } else {
269 : 0 : asm_x64_write_byte_3(as, OP_SIZE_PREFIX, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64);
270 : : }
271 : 24 : asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
272 : 24 : }
273 : :
274 : 32 : void asm_x64_mov_r32_to_mem32(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
275 [ + - ]: 32 : if (src_r64 < 8 && dest_r64 < 8) {
276 : 32 : asm_x64_write_byte_1(as, OPCODE_MOV_R64_TO_RM64);
277 : : } else {
278 : 0 : asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64);
279 : : }
280 : 32 : asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
281 : 32 : }
282 : :
283 : 263033 : void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
284 : : // use REX prefix for 64 bit operation
285 : 263033 : asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(src_r64) | REX_B_FROM_R64(dest_r64), OPCODE_MOV_R64_TO_RM64);
286 : 263033 : asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
287 : 263033 : }
288 : :
289 : 90 : void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
290 [ + - ]: 90 : if (src_r64 < 8 && dest_r64 < 8) {
291 : 90 : asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
292 : : } else {
293 : 0 : asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM8_TO_R64);
294 : : }
295 : 90 : asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
296 : 90 : }
297 : :
298 : 24 : void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
299 [ + - ]: 24 : if (src_r64 < 8 && dest_r64 < 8) {
300 : 24 : asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
301 : : } else {
302 : 0 : asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM16_TO_R64);
303 : : }
304 : 24 : asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
305 : 24 : }
306 : :
307 : 24 : void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
308 [ + - ]: 24 : if (src_r64 < 8 && dest_r64 < 8) {
309 : 24 : asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64);
310 : : } else {
311 : 0 : asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64);
312 : : }
313 : 24 : asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
314 : 24 : }
315 : :
316 : 682708 : void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
317 : : // use REX prefix for 64 bit operation
318 : 682708 : asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64);
319 : 682708 : asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
320 : 682708 : }
321 : :
322 : 86675 : static void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
323 : : // use REX prefix for 64 bit operation
324 : 86675 : asm_x64_write_byte_2(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_LEA_MEM_TO_R64);
325 : 86675 : asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
326 : 86675 : }
327 : :
328 : : /*
329 : : void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) {
330 : : assert(dest_r64 < 8);
331 : : asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8);
332 : : }
333 : : */
334 : :
335 : 358416 : size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) {
336 : : // cpu defaults to i32 to r64, with zero extension
337 [ + + ]: 358416 : if (dest_r64 < 8) {
338 : 358353 : asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64);
339 : : } else {
340 : 63 : asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7));
341 : : }
342 : 358416 : size_t loc = mp_asm_base_get_code_pos(&as->base);
343 : 358416 : asm_x64_write_word32(as, src_i32);
344 : 358416 : return loc;
345 : : }
346 : :
347 : 2058 : void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) {
348 : : // cpu defaults to i32 to r64
349 : : // to mov i64 to r64 need to use REX prefix
350 : 2058 : asm_x64_write_byte_2(as,
351 : : REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_B),
352 [ + - ]: 2058 : OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7));
353 : 2058 : asm_x64_write_word64(as, src_i64);
354 : 2058 : }
355 : :
356 : 360474 : void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64) {
357 : : // TODO use movzx, movsx if possible
358 [ + + ]: 360474 : if (UNSIGNED_FIT32(src_i64)) {
359 : : // 5 bytes
360 : 358416 : asm_x64_mov_i32_to_r64(as, src_i64 & 0xffffffff, dest_r64);
361 : : } else {
362 : : // 10 bytes
363 : 2058 : asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);
364 : : }
365 : 360474 : }
366 : :
367 : 6 : void asm_x64_not_r64(asm_x64_t *as, int dest_r64) {
368 : 6 : asm_x64_generic_r64_r64(as, dest_r64, 2, OPCODE_NOT_RM64);
369 : 6 : }
370 : :
371 : 6 : void asm_x64_neg_r64(asm_x64_t *as, int dest_r64) {
372 : 6 : asm_x64_generic_r64_r64(as, dest_r64, 3, OPCODE_NEG_RM64);
373 : 6 : }
374 : :
375 : 60 : void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
376 : 60 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_AND_R64_TO_RM64);
377 : 60 : }
378 : :
379 : 60 : void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
380 : 60 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_OR_R64_TO_RM64);
381 : 60 : }
382 : :
383 : 11296 : void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
384 : 11296 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64);
385 : 11296 : }
386 : :
387 : 48 : void asm_x64_shl_r64_cl(asm_x64_t *as, int dest_r64) {
388 : 48 : asm_x64_generic_r64_r64(as, dest_r64, 4, OPCODE_SHL_RM64_CL);
389 : 48 : }
390 : :
391 : 6 : void asm_x64_shr_r64_cl(asm_x64_t *as, int dest_r64) {
392 : 6 : asm_x64_generic_r64_r64(as, dest_r64, 5, OPCODE_SHR_RM64_CL);
393 : 6 : }
394 : :
395 : 42 : void asm_x64_sar_r64_cl(asm_x64_t *as, int dest_r64) {
396 : 42 : asm_x64_generic_r64_r64(as, dest_r64, 7, OPCODE_SAR_RM64_CL);
397 : 42 : }
398 : :
399 : 10147 : void asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
400 : 10147 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_ADD_R64_TO_RM64);
401 : 10147 : }
402 : :
403 : 24 : void asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
404 : 24 : asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_SUB_R64_FROM_RM64);
405 : 24 : }
406 : :
407 : 24 : void asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
408 : : // imul reg64, reg/mem64 -- 0x0f 0xaf /r
409 : 24 : asm_x64_write_byte_1(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64));
410 : 24 : asm_x64_write_byte_3(as, 0x0f, 0xaf, MODRM_R64(dest_r64) | MODRM_RM_REG | MODRM_RM_R64(src_r64));
411 : 24 : }
412 : :
413 : : /*
414 : : void asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) {
415 : : if (SIGNED_FIT8(src_i32)) {
416 : : // defaults to 32 bit operation
417 : : asm_x64_write_byte_2(as, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));
418 : : asm_x64_write_byte_1(as, src_i32 & 0xff);
419 : : } else {
420 : : // defaults to 32 bit operation
421 : : asm_x64_write_byte_2(as, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));
422 : : asm_x64_write_word32(as, src_i32);
423 : : }
424 : : }
425 : : */
426 : :
427 : 28331 : static void asm_x64_sub_r64_i32(asm_x64_t *as, int dest_r64, int src_i32) {
428 [ - + ]: 28331 : assert(dest_r64 < 8);
429 [ + + + + ]: 28331 : if (SIGNED_FIT8(src_i32)) {
430 : : // use REX prefix for 64 bit operation
431 : 11017 : asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
432 : 11017 : asm_x64_write_byte_1(as, src_i32 & 0xff);
433 : : } else {
434 : : // use REX prefix for 64 bit operation
435 : 17314 : asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I32_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
436 : 17314 : asm_x64_write_word32(as, src_i32);
437 : : }
438 : 28331 : }
439 : :
440 : : /*
441 : : void asm_x64_shl_r32_by_imm(asm_x64_t *as, int r32, int imm) {
442 : : asm_x64_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(r32));
443 : : asm_x64_write_byte_1(as, imm);
444 : : }
445 : :
446 : : void asm_x64_shr_r32_by_imm(asm_x64_t *as, int r32, int imm) {
447 : : asm_x64_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(r32));
448 : : asm_x64_write_byte_1(as, imm);
449 : : }
450 : :
451 : : void asm_x64_sar_r32_by_imm(asm_x64_t *as, int r32, int imm) {
452 : : asm_x64_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(r32));
453 : : asm_x64_write_byte_1(as, imm);
454 : : }
455 : : */
456 : :
457 : 990 : void asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) {
458 : 990 : asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_CMP_R64_WITH_RM64);
459 : 990 : }
460 : :
461 : : /*
462 : : void asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) {
463 : : if (SIGNED_FIT8(src_i32)) {
464 : : asm_x64_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32));
465 : : asm_x64_write_byte_1(as, src_i32 & 0xff);
466 : : } else {
467 : : asm_x64_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32));
468 : : asm_x64_write_word32(as, src_i32);
469 : : }
470 : : }
471 : : */
472 : :
473 : 22643 : void asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b) {
474 [ - + ]: 22643 : assert(src_r64_a < 8);
475 [ - + ]: 22643 : assert(src_r64_b < 8);
476 : 22643 : asm_x64_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R64(src_r64_a) | MODRM_RM_REG | MODRM_RM_R64(src_r64_b));
477 : 22643 : }
478 : :
479 : 17561 : void asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) {
480 : 17561 : asm_x64_generic_r64_r64(as, src_r64_b, src_r64_a, OPCODE_TEST_R64_WITH_RM64);
481 : 17561 : }
482 : :
483 : 268 : void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) {
484 [ - + ]: 268 : assert(dest_r8 < 8);
485 : 268 : asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8));
486 : 268 : }
487 : :
488 : 3812 : void asm_x64_jmp_reg(asm_x64_t *as, int src_r64) {
489 [ - + ]: 3812 : assert(src_r64 < 8);
490 : 3812 : asm_x64_write_byte_2(as, OPCODE_JMP_RM64, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(src_r64));
491 : 3812 : }
492 : :
493 : 87161 : static mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) {
494 [ - + ]: 87161 : assert(label < as->base.max_num_labels);
495 : 87161 : return as->base.label_offsets[label];
496 : : }
497 : :
498 : 34922 : void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {
499 : 34922 : mp_uint_t dest = get_label_dest(as, label);
500 : 34922 : mp_int_t rel = dest - as->base.code_offset;
501 [ + + ]: 34922 : if (dest != (mp_uint_t)-1 && rel < 0) {
502 : : // is a backwards jump, so we know the size of the jump on the first pass
503 : : // calculate rel assuming 8 bit relative jump
504 : 1746 : rel -= 2;
505 [ + + ]: 1746 : if (SIGNED_FIT8(rel)) {
506 : 414 : asm_x64_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff);
507 : : } else {
508 : 1332 : rel += 2;
509 : 1332 : goto large_jump;
510 : : }
511 : : } else {
512 : : // is a forwards jump, so need to assume it's large
513 : 33176 : large_jump:
514 : 34508 : rel -= 5;
515 : 34508 : asm_x64_write_byte_1(as, OPCODE_JMP_REL32);
516 : 34508 : asm_x64_write_word32(as, rel);
517 : : }
518 : 34922 : }
519 : :
520 : 40926 : void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {
521 : 40926 : mp_uint_t dest = get_label_dest(as, label);
522 : 40926 : mp_int_t rel = dest - as->base.code_offset;
523 [ + + ]: 40926 : if (dest != (mp_uint_t)-1 && rel < 0) {
524 : : // is a backwards jump, so we know the size of the jump on the first pass
525 : : // calculate rel assuming 8 bit relative jump
526 : 4818 : rel -= 2;
527 [ + + ]: 4818 : if (SIGNED_FIT8(rel)) {
528 : 3788 : asm_x64_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff);
529 : : } else {
530 : 1030 : rel += 2;
531 : 1030 : goto large_jump;
532 : : }
533 : : } else {
534 : : // is a forwards jump, so need to assume it's large
535 : 36108 : large_jump:
536 : 37138 : rel -= 6;
537 : 37138 : asm_x64_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);
538 : 37138 : asm_x64_write_word32(as, rel);
539 : : }
540 : 40926 : }
541 : :
542 : 13661 : void asm_x64_entry(asm_x64_t *as, int num_locals) {
543 [ - + ]: 13661 : assert(num_locals >= 0);
544 : 13661 : asm_x64_push_r64(as, ASM_X64_REG_RBP);
545 : 13661 : asm_x64_push_r64(as, ASM_X64_REG_RBX);
546 : 13661 : asm_x64_push_r64(as, ASM_X64_REG_R12);
547 : 13661 : asm_x64_push_r64(as, ASM_X64_REG_R13);
548 : 13661 : num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary
549 : 13661 : asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE);
550 : 13661 : as->num_locals = num_locals;
551 : 13661 : }
552 : :
553 : 14670 : void asm_x64_exit(asm_x64_t *as) {
554 : 14670 : asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, -as->num_locals * WORD_SIZE);
555 : 14670 : asm_x64_pop_r64(as, ASM_X64_REG_R13);
556 : 14670 : asm_x64_pop_r64(as, ASM_X64_REG_R12);
557 : 14670 : asm_x64_pop_r64(as, ASM_X64_REG_RBX);
558 : 14670 : asm_x64_pop_r64(as, ASM_X64_REG_RBP);
559 : 14670 : asm_x64_ret(as);
560 : 14670 : }
561 : :
562 : : // locals:
563 : : // - stored on the stack in ascending order
564 : : // - numbered 0 through as->num_locals-1
565 : : // - RSP points to the first local
566 : : //
567 : : // | RSP
568 : : // v
569 : : // l0 l1 l2 ... l(n-1)
570 : : // ^ ^
571 : : // | low address | high address in RAM
572 : : //
573 : 515441 : static int asm_x64_local_offset_from_rsp(asm_x64_t *as, int local_num) {
574 : 515441 : (void)as;
575 : : // Stack is full descending, RSP points to local0
576 : 515441 : return local_num * WORD_SIZE;
577 : : }
578 : :
579 : 173734 : void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64) {
580 : 173734 : asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, src_local_num), dest_r64);
581 : 173734 : }
582 : :
583 : 241731 : void asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num) {
584 : 241731 : asm_x64_mov_r64_to_mem64(as, src_r64, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, dest_local_num));
585 : 241731 : }
586 : :
587 : 99976 : void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) {
588 : 99976 : int offset = asm_x64_local_offset_from_rsp(as, local_num);
589 [ + + ]: 99976 : if (offset == 0) {
590 : 13301 : asm_x64_mov_r64_r64(as, dest_r64, ASM_X64_REG_RSP);
591 : : } else {
592 : 86675 : asm_x64_lea_disp_to_r64(as, ASM_X64_REG_RSP, offset, dest_r64);
593 : : }
594 : 99976 : }
595 : :
596 : 11313 : void asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label) {
597 : 11313 : mp_uint_t dest = get_label_dest(as, label);
598 : 11313 : mp_int_t rel = dest - (as->base.code_offset + 7);
599 : 11313 : asm_x64_write_byte_3(as, REX_PREFIX | REX_W | REX_R_FROM_R64(dest_r64), OPCODE_LEA_MEM_TO_R64, MODRM_R64(dest_r64) | MODRM_RM_R64(5));
600 : 11313 : asm_x64_write_word32(as, rel);
601 : 11313 : }
602 : :
603 : : /*
604 : : void asm_x64_push_local(asm_x64_t *as, int local_num) {
605 : : asm_x64_push_disp(as, ASM_X64_REG_RSP, asm_x64_local_offset_from_rsp(as, local_num));
606 : : }
607 : :
608 : : void asm_x64_push_local_addr(asm_x64_t *as, int local_num, int temp_r64) {
609 : : asm_x64_mov_r64_r64(as, temp_r64, ASM_X64_REG_RSP);
610 : : asm_x64_add_i32_to_r32(as, asm_x64_local_offset_from_rsp(as, local_num), temp_r64);
611 : : asm_x64_push_r64(as, temp_r64);
612 : : }
613 : : */
614 : :
615 : : /*
616 : : can't use these because code might be relocated when resized
617 : :
618 : : void asm_x64_call(asm_x64_t *as, void* func) {
619 : : asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP);
620 : : asm_x64_write_byte_1(as, OPCODE_CALL_REL32);
621 : : asm_x64_write_word32(as, func - (void*)(as->code_cur + 4));
622 : : asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP);
623 : : }
624 : :
625 : : void asm_x64_call_i1(asm_x64_t *as, void* func, int i1) {
626 : : asm_x64_sub_i32_from_r32(as, 8, ASM_X64_REG_RSP);
627 : : asm_x64_sub_i32_from_r32(as, 12, ASM_X64_REG_RSP);
628 : : asm_x64_push_i32(as, i1);
629 : : asm_x64_write_byte_1(as, OPCODE_CALL_REL32);
630 : : asm_x64_write_word32(as, func - (void*)(as->code_cur + 4));
631 : : asm_x64_add_i32_to_r32(as, 16, ASM_X64_REG_RSP);
632 : : asm_x64_mov_r64_r64(as, ASM_X64_REG_RSP, ASM_X64_REG_RBP);
633 : : }
634 : : */
635 : :
636 : 345869 : void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r64) {
637 [ - + ]: 345869 : assert(temp_r64 < 8);
638 : 345869 : asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_FUN_TABLE, fun_id * WORD_SIZE, temp_r64);
639 : 345869 : asm_x64_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R64(2) | MODRM_RM_REG | MODRM_RM_R64(temp_r64));
640 : 345869 : }
641 : :
642 : : #endif // MICROPY_EMIT_X64
|