codegen: use gen_frame_decompress_slot in gen_option_test
[ajla.git] / c1-x86.inc
blobe2c013b7ab4c0a0ad1bb889b6e9fa4ac8f0b29aa
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #ifdef ARCH_X86_32
20 #define OP_SIZE_NATIVE                  OP_SIZE_4
21 #else
22 #define OP_SIZE_NATIVE                  OP_SIZE_8
23 #endif
25 #ifndef ARCH_X86_64
26 #define OP_SIZE_ADDRESS                 OP_SIZE_4
27 #else
28 #define OP_SIZE_ADDRESS                 OP_SIZE_8
29 #endif
31 #define JMP_LIMIT                       JMP_LONG
33 #define UNALIGNED_TRAP                  0
35 #define ALU_WRITES_FLAGS(alu, im)       ((alu) != ALU_ADD ? 3 : 0)
36 #define ALU1_WRITES_FLAGS(alu)          ((alu) == ALU1_INC || (alu) == ALU1_DEC ? 1 : (alu) == ALU1_NOT || (alu) == ALU1_BSWAP ? 0 : 3)
37 #define ROT_WRITES_FLAGS(alu, size, im) (cpu_test_feature(CPU_FEATURE_bmi2) && (alu == ROT_SHL || alu == ROT_SHR || alu == ROT_SAR) && size >= OP_SIZE_4 && !(im) ? 0 : 1)
38 #define COND_IS_LOGICAL(cond)           0
40 #define ARCH_PARTIAL_ALU(size)          ((size) <= OP_SIZE_2)
41 #define ARCH_IS_3ADDRESS(alu, f)        ((alu) == ALU_ADD && !(f))
42 #define ARCH_IS_3ADDRESS_IMM(alu, f)    ((alu) == ALU_ADD && !(f))
43 #define ARCH_IS_3ADDRESS_ROT(alu, size) (ROT_WRITES_FLAGS(alu, size, false) ? 0 : 1)
44 #define ARCH_IS_3ADDRESS_ROT_IMM(alu)   0
45 #define ARCH_IS_2ADDRESS(alu)           ((alu) == ALU1_BSF || (alu) == ALU1_BSR || (alu) == ALU1_LZCNT || (alu) == ALU1_POPCNT)
46 #define ARCH_IS_3ADDRESS_FP             cpu_test_feature(CPU_FEATURE_avx)
47 #define ARCH_HAS_JMP_2REGS(cond)        0
48 #define ARCH_HAS_FLAGS                  1
49 #define ARCH_PREFERS_SX(size)           0
50 #define ARCH_HAS_BWX                    1
51 #define ARCH_HAS_MUL                    1
52 #define ARCH_HAS_DIV                    1
53 #define ARCH_HAS_ANDN                   0
54 #define ARCH_HAS_BTX(btx, size, cnst)   ((btx) != BTX_BTEXT && (size) >= OP_SIZE_2)
55 #define ARCH_HAS_SHIFTED_ADD(bits)      ((bits) <= 3)
56 #define ARCH_SHIFT_SIZE                 OP_SIZE_4
57 #define ARCH_BOOL_SIZE                  log_2(sizeof(ajla_flat_option_t))
58 #define ARCH_HAS_FP_GP_MOV              cpu_test_feature(CPU_FEATURE_sse2)
59 #define ARCH_NEEDS_BARRIER              0
61 #define i_size(size)                    (size)
62 #define i_size_rot(size)                (size)
63 #define i_size_cmp(size)                (size)
65 #define R_AX            0x0
66 #define R_CX            0x1
67 #define R_DX            0x2
68 #define R_BX            0x3
69 #define R_SP            0x4
70 #define R_BP            0x5
71 #define R_SI            0x6
72 #define R_DI            0x7
73 #define R_R8            0x8
74 #define R_R9            0x9
75 #define R_R10           0xa
76 #define R_R11           0xb
77 #define R_R12           0xc
78 #define R_R13           0xd
79 #define R_R14           0xe
80 #define R_R15           0xf
82 #define R_ST0           0x10
83 #define R_ST1           0x11
84 #define R_ST2           0x12
85 #define R_ST3           0x13
86 #define R_ST4           0x14
87 #define R_ST5           0x15
88 #define R_ST6           0x16
89 #define R_ST7           0x17
91 #define R_ES            0x18
92 #define R_CS            0x19
93 #define R_SS            0x1a
94 #define R_DS            0x1b
95 #define R_FS            0x1c
96 #define R_GS            0x1d
98 #define R_XMM0          0x20
99 #define R_XMM1          0x21
100 #define R_XMM2          0x22
101 #define R_XMM3          0x23
102 #define R_XMM4          0x24
103 #define R_XMM5          0x25
104 #define R_XMM6          0x26
105 #define R_XMM7          0x27
106 #define R_XMM8          0x28
107 #define R_XMM9          0x29
108 #define R_XMM10         0x2a
109 #define R_XMM11         0x2b
110 #define R_XMM12         0x2c
111 #define R_XMM13         0x2d
112 #define R_XMM14         0x2e
113 #define R_XMM15         0x2f
114 #define R_XMM16         0x30
115 #define R_XMM17         0x31
116 #define R_XMM18         0x32
117 #define R_XMM19         0x33
118 #define R_XMM20         0x34
119 #define R_XMM21         0x35
120 #define R_XMM22         0x36
121 #define R_XMM23         0x37
122 #define R_XMM24         0x38
123 #define R_XMM25         0x39
124 #define R_XMM26         0x3a
125 #define R_XMM27         0x3b
126 #define R_XMM28         0x3c
127 #define R_XMM29         0x3d
128 #define R_XMM30         0x3e
129 #define R_XMM31         0x3f
131 #define R_IS_GPR(r)     ((r) < 16)
132 #define R_IS_XMM(r)     ((r) >= R_XMM0 && (r) <= R_XMM31)
134 /*#define TIMESTAMP_IN_REGISTER*/
136 #ifndef ARCH_X86_32
137 static uint8_t upcall_register = R_R15;
138 #define R_UPCALL        upcall_register
139 #ifdef TIMESTAMP_IN_REGISTER
140 #define R_TIMESTAMP     R_R14
141 #endif
142 #define R_CONST_IMM     R_R11
143 #else
144 #define R_CONST_IMM     255     /* this should not be used */
145 #endif
146 #define R_OFFSET_IMM    255     /* this should not be used */
148 #if defined(ARCH_X86_32)
149 #define R_FRAME         R_BP
150 #define R_SCRATCH_1     R_AX
151 #define R_SCRATCH_2     R_DX
152 #define R_SCRATCH_3     R_CX
153 #define R_SCRATCH_4     R_SAVED_2
154 #define R_SAVED_1       R_SI
155 #define R_SAVED_2       R_DI
156 #elif defined(ARCH_X86_WIN_ABI)
157 #define R_FRAME         R_BP
158 #define R_SCRATCH_1     R_AX
159 #define R_SCRATCH_2     R_DX
160 #define R_SCRATCH_3     R_CX
161 #define R_SCRATCH_4     R_SAVED_2
162 #define R_SAVED_1       R_SI
163 #define R_SAVED_2       R_DI
164 #else
165 #define R_FRAME         R_BX
166 #define R_SCRATCH_1     R_AX
167 #define R_SCRATCH_2     R_DX
168 #define R_SCRATCH_3     R_CX
169 #define R_SCRATCH_4     R_SAVED_2
170 #define R_SAVED_1       R_BP
171 #define R_SAVED_2       R_R12
172 #endif
174 #define FR_SCRATCH_1    R_XMM0
175 #define FR_SCRATCH_2    R_XMM1
177 #if defined(ARCH_X86_32)
178 #define R_ARG0          R_AX
179 #define R_ARG1          R_AX
180 #define R_ARG2          R_AX
181 #define R_ARG3          R_AX
182 #elif defined(ARCH_X86_WIN_ABI)
183 #define R_ARG0          R_CX
184 #define R_ARG1          R_DX
185 #define R_ARG2          R_R8
186 #define R_ARG3          R_R9
187 #else
188 #define R_ARG0          R_DI
189 #define R_ARG1          R_SI
190 #define R_ARG2          R_DX
191 #define R_ARG3          R_CX
192 #endif
193 #define R_RET0          R_AX
195 #if defined(ARCH_X86_32)
196 #define ARG_SPACE       0x1c            /* must be 0xc modulo 0x10 */
197 #define ARG_OFFSET      0x14
198 #elif defined(ARCH_X86_WIN_ABI) && !defined(TIMESTAMP_IN_REGISTER)
199 #define ARG_SPACE       0x28            /* must be 0x8 modulo 0x10 */
200 #define ARG_OFFSET      0xa0
201 #elif defined(ARCH_X86_WIN_ABI)
202 #define ARG_SPACE       0x20            /* must be 0x0 modulo 0x10 */
203 #define ARG_OFFSET      0x90
204 #endif
206 #define SUPPORTED_FP            (cpu_test_feature(CPU_FEATURE_sse) * 0x2 + cpu_test_feature(CPU_FEATURE_sse2) * 0x4)
207 #define SUPPORTED_FP_X87        0xe
208 #define SUPPORTED_FP_HALF_CVT   (cpu_test_feature(CPU_FEATURE_f16c) * 0x1)
210 static bool reg_is_fp(unsigned reg)
212         return reg >= 0x20 && reg < 0x40;
215 static bool reg_is_segment(unsigned reg)
217         return reg >= 0x18 && reg < 0x1e;
220 #if defined(ARCH_X86_32)
222 static const uint8_t regs_saved[] = { R_BX };
223 static const uint8_t regs_volatile[] = { 0 };
224 #define n_regs_volatile 0U
225 static const uint8_t fp_saved[] = { 0 };
226 #define n_fp_saved 0U
227 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7 };
228 #define reg_is_saved(r) ((r) == R_BX)
230 #elif defined(ARCH_X86_WIN_ABI)
232 static const uint8_t regs_saved[] = { R_BX, R_R12, R_R13,
233 #ifndef TIMESTAMP_IN_REGISTER
234         R_R14,
235 #endif
236         };
237 static const uint8_t regs_volatile[] = { R_R8, R_R9, R_R10 };
238 static const uint8_t fp_saved[] = { 0 };
239 #define n_fp_saved 0U
240 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5 };
241 #define reg_is_saved(r) ((r) == R_BX || ((r) >= R_R12 && ((r) <= R_R15)))
243 #else
245 static const uint8_t regs_saved[] = { R_R13,
246 #ifndef TIMESTAMP_IN_REGISTER
247         R_R14,
248 #endif
249         R_R15,
250         };
251 #define n_regs_saved (n_array_elements(regs_saved) - !reg_is_segment(R_UPCALL))
252 static const uint8_t regs_volatile[] = { R_SI, R_DI, R_R8, R_R9, R_R10 };
253 static const uint8_t fp_saved[] = { 0 };
254 #define n_fp_saved 0U
255 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7, R_XMM8, R_XMM9, R_XMM10, R_XMM11, R_XMM12, R_XMM13, R_XMM14, R_XMM15 };
256 #define reg_is_saved(r) ((r) >= R_R13 && (r) <= R_R15)
257 #endif
259 static bool attr_w imm_is_8bit(int64_t imm)
261         return imm >= -0x80 && imm < 0x80;
264 static bool attr_w imm_is_32bit(int64_t attr_unused imm)
266 #ifdef ARCH_X86_32
267         return true;
268 #else
269         return imm >= -0x80000000LL && imm < 0x80000000LL;
270 #endif
273 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
275         if (OP_SIZE_NATIVE == OP_SIZE_4)
276                 c = (int32_t)c;
277         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
278         gen_one(reg);
279         gen_one(ARG_IMM);
280         gen_eight(c);
281         return true;
284 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned attr_unused size)
286         ctx->offset_imm = imm;
287         ctx->offset_reg = false;
288         ctx->base_reg = base;
289         switch (purpose) {
290                 case IMM_PURPOSE_LDR_OFFSET:
291                 case IMM_PURPOSE_LDR_SX_OFFSET:
292                 case IMM_PURPOSE_STR_OFFSET:
293                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
294                 case IMM_PURPOSE_MVI_CLI_OFFSET:
295                         break;
296                 default:
297                         internal(file_line, "gen_address: invalid purpose %d", purpose);
298         }
299 #ifndef ARCH_X86_32
300         if (unlikely(!imm_is_32bit(imm)))
301                 return false;
302 #endif
303         return true;
306 static bool is_direct_const(int64_t attr_unused imm, unsigned attr_unused purpose, unsigned attr_unused size)
308 #ifdef ARCH_X86_32
309         return true;
310 #else
311         return imm_is_32bit(imm);
312 #endif
315 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
317 #if 0
318         if (size == OP_SIZE_1 && (unlikely(imm < -0x80LL) || unlikely(imm >= 0x80LL)))
319                 internal(file_line, "invalid imm for size 1: %016llx", (long long)imm);
320         if (size == OP_SIZE_2 && (unlikely(imm < -0x8000LL) || unlikely(imm >= 0x8000LL)))
321                 internal(file_line, "invalid imm for size 2 : %016llx", (long long)imm);
322         if (size == OP_SIZE_4 && (unlikely(imm < -0x80000000LL) || unlikely(imm >= 0x80000000LL)))
323                 internal(file_line, "invalid imm for size 3: %016llx", (long long)imm);
324 #endif
325         if (is_direct_const(imm, purpose, size)) {
326                 ctx->const_imm = imm;
327                 ctx->const_reg = false;
328         } else {
329                 gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
330                 gen_one(R_CONST_IMM);
331                 gen_one(ARG_IMM);
332                 gen_eight(imm);
333                 ctx->const_reg = true;
334         }
335         return true;
338 static bool attr_w gen_entry(struct codegen_context *ctx)
340 #if defined(ARCH_X86_32)
341         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
342         gen_one(R_BX);
344         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
345         gen_one(R_BP);
347         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
348         gen_one(R_SI);
350         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
351         gen_one(R_DI);
353         gen_insn(INSN_ALU, OP_SIZE_4, ALU_SUB, 1);
354         gen_one(R_SP);
355         gen_one(R_SP);
356         gen_one(ARG_IMM);
357         gen_eight(ARG_SPACE);
359         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
360         gen_one(R_FRAME);
361         gen_one(ARG_ADDRESS_1);
362         gen_one(R_SP);
363         gen_eight(ARG_SPACE + ARG_OFFSET);
365         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
366         gen_one(ARG_ADDRESS_1);
367         gen_one(R_SP);
368         gen_eight(ARG_SPACE + ARG_OFFSET + 12);
369 #elif defined(ARCH_X86_WIN_ABI)
370         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
371         gen_one(R_BX);
373         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
374         gen_one(R_BP);
376         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
377         gen_one(R_SI);
379         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
380         gen_one(R_DI);
382         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
383         gen_one(R_R12);
385         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
386         gen_one(R_R13);
388         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
389         gen_one(R_R14);
391         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
392         gen_one(R_R15);
394         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
395         gen_one(R_ARG0);
396 #ifndef TIMESTAMP_IN_REGISTER
397         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
398         gen_one(R_ARG3);
399 #endif
400         gen_insn(INSN_ALU, OP_SIZE_8, ALU_SUB, 1);
401         gen_one(R_SP);
402         gen_one(R_SP);
403         gen_one(ARG_IMM);
404         gen_eight(ARG_SPACE);
406         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
407         gen_one(R_FRAME);
408         gen_one(R_ARG1);
410         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
411         gen_one(R_UPCALL);
412         gen_one(R_ARG2);
413 #ifdef TIMESTAMP_IN_REGISTER
414         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
415         gen_one(R_TIMESTAMP);
416         gen_one(R_ARG3);
417 #endif
418         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
419         gen_one(ARG_ADDRESS_1);
420         gen_one(R_SP);
421         gen_eight(ARG_OFFSET);
422 #else
423         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
424         gen_one(R_BX);
426         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
427         gen_one(R_BP);
429         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
430         gen_one(R_R12);
432         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
433         gen_one(R_R13);
435         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
436         gen_one(R_R14);
438         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
439         gen_one(R_R15);
441         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
442         gen_one(R_ARG2);
443         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
444         gen_one(R_FRAME);
445         gen_one(R_ARG0);
447         if (!reg_is_segment(R_UPCALL)) {
448                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
449                 gen_one(R_UPCALL);
450                 gen_one(R_ARG1);
451         }
452 #ifdef TIMESTAMP_IN_REGISTER
453         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
454         gen_one(R_TIMESTAMP);
455         gen_one(R_ARG2);
456 #endif
457 #if defined(ARCH_X86_X32)
458         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
459         gen_one(R_ARG3);
460         gen_one(R_ARG3);
461 #endif
462         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
463         gen_one(R_ARG3);
464 #endif
465         return true;
468 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
470 #if defined(ARCH_X86_32) || defined(ARCH_X86_64)
471         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
472         gen_one(R_DX);
473         gen_one(ARG_IMM);
474         gen_eight(ip);
475 #else
476         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
477         gen_one(R_AX);
478         gen_one(ARG_IMM);
479         gen_eight((uint64_t)ip << 32);
480 #endif
481         gen_insn(INSN_JMP, 0, 0, 0);
482         gen_four(escape_label);
484         return true;
487 static bool attr_w gen_escape(struct codegen_context *ctx)
489 #if defined(ARCH_X86_32)
490         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
491         gen_one(R_AX);
492         gen_one(R_FRAME);
494         gen_insn(INSN_ALU, OP_SIZE_4, ALU_ADD, 1);
495         gen_one(R_SP);
496         gen_one(R_SP);
497         gen_one(ARG_IMM);
498         gen_eight(ARG_SPACE);
500         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
501         gen_one(R_DI);
503         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
504         gen_one(R_SI);
506         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
507         gen_one(R_BP);
509         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
510         gen_one(R_BX);
512         gen_insn(INSN_RET, 0, 0, 0);
513 #elif defined(ARCH_X86_WIN_ABI)
514         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
515         gen_one(R_SP);
516         gen_one(R_SP);
517         gen_one(ARG_IMM);
518 #if defined(TIMESTAMP_IN_REGISTER)
519         gen_eight(ARG_SPACE);
520 #else
521         gen_eight(ARG_SPACE + 8);
522 #endif
523         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
524         gen_one(R_AX);
526         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
527         gen_one(ARG_ADDRESS_1);
528         gen_one(R_AX);
529         gen_eight(0);
530         gen_one(R_FRAME);
532         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
533         gen_one(ARG_ADDRESS_1);
534         gen_one(R_AX);
535         gen_eight(8);
536         gen_one(R_DX);
538         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
539         gen_one(R_R15);
541         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
542         gen_one(R_R14);
544         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
545         gen_one(R_R13);
547         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
548         gen_one(R_R12);
550         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
551         gen_one(R_DI);
553         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
554         gen_one(R_SI);
556         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
557         gen_one(R_BP);
559         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
560         gen_one(R_BX);
562         gen_insn(INSN_RET, 0, 0, 0);
563 #else
564 #if defined(ARCH_X86_X32)
565         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
566         gen_one(R_AX);
567         gen_one(R_AX);
568         gen_one(R_FRAME);
569 #else
570         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
571         gen_one(R_AX);
572         gen_one(R_FRAME);
573 #endif
574         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
575         gen_one(R_CX);
577         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
578         gen_one(R_R15);
580         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
581         gen_one(R_R14);
583         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
584         gen_one(R_R13);
586         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
587         gen_one(R_R12);
589         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
590         gen_one(R_BP);
592         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
593         gen_one(R_BX);
595         gen_insn(INSN_RET, 0, 0, 0);
596 #endif
597         return true;
600 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
602 #if defined(ARCH_X86_32)
603         ajla_assert_lo(arg * 4 < ARG_SPACE, (file_line, "gen_upcall_argument: argument %u", arg));
604         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
605         gen_one(ARG_ADDRESS_1);
606         gen_one(R_SP);
607         gen_eight(arg * 4);
608         gen_one(R_ARG0);
609 #endif
610         return true;
613 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
615 #if defined(ARCH_X86_32)
616         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
617         gen_one(R_AX);
618         gen_one(ARG_ADDRESS_1);
619         gen_one(R_SP);
620         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
622         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_4, 0, 0);
623         gen_one(ARG_ADDRESS_1);
624         gen_one(R_AX);
625         gen_eight(offset);
626 #elif defined(ARCH_X86_X32)
627         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
628         gen_one(R_AX);
629         gen_one(ARG_ADDRESS_1);
630         gen_one(R_UPCALL);
631         gen_eight(offset);
633         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
634         gen_one(R_AX);
635 #else
636         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
637         gen_one(ARG_ADDRESS_1);
638         gen_one(R_UPCALL);
639         gen_eight(offset);
640 #endif
641         g(gen_upcall_end(ctx, n_args));
643         return true;
646 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
648 #if defined(ARCH_X86_32)
649         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
650         gen_one(R_AX);
651         gen_one(ARG_ADDRESS_1);
652         gen_one(R_SP);
653         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
655         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
656         gen_one(R_DX);
657         gen_one(ARG_ADDRESS_1);
658         gen_one(R_SP);
659         gen_eight(ARG_SPACE + ARG_OFFSET + 8);
661         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
662         gen_one(R_DX);
663         gen_one(ARG_ADDRESS_1);
664         gen_one(R_AX);
665         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
666 #elif defined(TIMESTAMP_IN_REGISTER)
667         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
668         gen_one(R_TIMESTAMP);
669         gen_one(ARG_ADDRESS_1);
670         gen_one(R_UPCALL);
671         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
672 #else
673         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
674         gen_one(R_AX);
675         gen_one(ARG_ADDRESS_1);
676         gen_one(R_SP);
677 #if defined(ARCH_X86_WIN_ABI)
678         gen_eight(ARG_SPACE);
679 #else
680         gen_eight(0);
681 #endif
682         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
683         gen_one(R_AX);
684         gen_one(ARG_ADDRESS_1);
685         gen_one(R_UPCALL);
686         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
687 #endif
688         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
689         gen_four(escape_label);
691         return true;