codegen: a small improvement in do_bswap and do_brev
[ajla.git] / c1-x86.inc
blob805f9b0a0362faa3dc1a171bec3ef87a4a39dc01
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_FLAGS                  1
48 #define ARCH_PREFERS_SX(size)           0
49 #define ARCH_HAS_BWX                    1
50 #define ARCH_HAS_MUL                    1
51 #define ARCH_HAS_DIV                    1
52 #define ARCH_HAS_ANDN                   0
53 #define ARCH_HAS_BTX(btx, size, cnst)   ((btx) != BTX_BTEXT && (size) >= OP_SIZE_2)
54 #define ARCH_HAS_SHIFTED_ADD(bits)      ((bits) <= 3)
55 #define ARCH_SHIFT_SIZE                 OP_SIZE_4
56 #define ARCH_NEEDS_BARRIER              0
58 #define i_size(size)                    (size)
59 #define i_size_rot(size)                (size)
60 #define i_size_cmp(size)                (size)
62 #define R_AX            0x0
63 #define R_CX            0x1
64 #define R_DX            0x2
65 #define R_BX            0x3
66 #define R_SP            0x4
67 #define R_BP            0x5
68 #define R_SI            0x6
69 #define R_DI            0x7
70 #define R_R8            0x8
71 #define R_R9            0x9
72 #define R_R10           0xa
73 #define R_R11           0xb
74 #define R_R12           0xc
75 #define R_R13           0xd
76 #define R_R14           0xe
77 #define R_R15           0xf
79 #define R_ST0           0x10
80 #define R_ST1           0x11
81 #define R_ST2           0x12
82 #define R_ST3           0x13
83 #define R_ST4           0x14
84 #define R_ST5           0x15
85 #define R_ST6           0x16
86 #define R_ST7           0x17
88 #define R_ES            0x18
89 #define R_CS            0x19
90 #define R_SS            0x1a
91 #define R_DS            0x1b
92 #define R_FS            0x1c
93 #define R_GS            0x1d
95 #define R_XMM0          0x20
96 #define R_XMM1          0x21
97 #define R_XMM2          0x22
98 #define R_XMM3          0x23
99 #define R_XMM4          0x24
100 #define R_XMM5          0x25
101 #define R_XMM6          0x26
102 #define R_XMM7          0x27
103 #define R_XMM8          0x28
104 #define R_XMM9          0x29
105 #define R_XMM10         0x2a
106 #define R_XMM11         0x2b
107 #define R_XMM12         0x2c
108 #define R_XMM13         0x2d
109 #define R_XMM14         0x2e
110 #define R_XMM15         0x2f
111 #define R_XMM16         0x30
112 #define R_XMM17         0x31
113 #define R_XMM18         0x32
114 #define R_XMM19         0x33
115 #define R_XMM20         0x34
116 #define R_XMM21         0x35
117 #define R_XMM22         0x36
118 #define R_XMM23         0x37
119 #define R_XMM24         0x38
120 #define R_XMM25         0x39
121 #define R_XMM26         0x3a
122 #define R_XMM27         0x3b
123 #define R_XMM28         0x3c
124 #define R_XMM29         0x3d
125 #define R_XMM30         0x3e
126 #define R_XMM31         0x3f
128 #define R_IS_GPR(r)     ((r) < 16)
129 #define R_IS_XMM(r)     ((r) >= R_XMM0 && (r) <= R_XMM31)
131 /*#define TIMESTAMP_IN_REGISTER*/
133 #ifndef ARCH_X86_32
134 static uint8_t upcall_register = R_R15;
135 #define R_UPCALL        upcall_register
136 #ifdef TIMESTAMP_IN_REGISTER
137 #define R_TIMESTAMP     R_R14
138 #endif
139 #define R_CONST_IMM     R_R11
140 #else
141 #define R_CONST_IMM     255     /* this should not be used */
142 #endif
143 #define R_OFFSET_IMM    255     /* this should not be used */
145 #if defined(ARCH_X86_32)
146 #define R_FRAME         R_BP
147 #define R_SCRATCH_1     R_AX
148 #define R_SCRATCH_2     R_DX
149 #define R_SCRATCH_3     R_CX
150 #define R_SCRATCH_4     R_SAVED_2
151 #define R_SAVED_1       R_SI
152 #define R_SAVED_2       R_DI
153 #elif defined(ARCH_X86_WIN_ABI)
154 #define R_FRAME         R_BP
155 #define R_SCRATCH_1     R_AX
156 #define R_SCRATCH_2     R_DX
157 #define R_SCRATCH_3     R_CX
158 #define R_SCRATCH_4     R_SAVED_2
159 #define R_SAVED_1       R_SI
160 #define R_SAVED_2       R_DI
161 #else
162 #define R_FRAME         R_BX
163 #define R_SCRATCH_1     R_AX
164 #define R_SCRATCH_2     R_DX
165 #define R_SCRATCH_3     R_CX
166 #define R_SCRATCH_4     R_SAVED_2
167 #define R_SAVED_1       R_BP
168 #define R_SAVED_2       R_R12
169 #endif
171 #define FR_SCRATCH_1    R_XMM0
172 #define FR_SCRATCH_2    R_XMM1
174 #if defined(ARCH_X86_32)
175 #define R_ARG0          R_AX
176 #define R_ARG1          R_AX
177 #define R_ARG2          R_AX
178 #define R_ARG3          R_AX
179 #elif defined(ARCH_X86_WIN_ABI)
180 #define R_ARG0          R_CX
181 #define R_ARG1          R_DX
182 #define R_ARG2          R_R8
183 #define R_ARG3          R_R9
184 #else
185 #define R_ARG0          R_DI
186 #define R_ARG1          R_SI
187 #define R_ARG2          R_DX
188 #define R_ARG3          R_CX
189 #endif
190 #define R_RET0          R_AX
192 #if defined(ARCH_X86_32)
193 #define ARG_SPACE       0x1c            /* must be 0xc modulo 0x10 */
194 #define ARG_OFFSET      0x14
195 #elif defined(ARCH_X86_WIN_ABI) && !defined(TIMESTAMP_IN_REGISTER)
196 #define ARG_SPACE       0x28            /* must be 0x8 modulo 0x10 */
197 #define ARG_OFFSET      0xa0
198 #elif defined(ARCH_X86_WIN_ABI)
199 #define ARG_SPACE       0x20            /* must be 0x0 modulo 0x10 */
200 #define ARG_OFFSET      0x90
201 #endif
203 #define SUPPORTED_FP            (cpu_test_feature(CPU_FEATURE_sse) * 0x2 + cpu_test_feature(CPU_FEATURE_sse2) * 0x4)
204 #define SUPPORTED_FP_X87        0xe
205 #define SUPPORTED_FP_HALF_CVT   (cpu_test_feature(CPU_FEATURE_f16c) * 0x1)
207 static bool reg_is_fp(unsigned reg)
209         return reg >= 0x20 && reg < 0x40;
212 static bool reg_is_segment(unsigned reg)
214         return reg >= 0x18 && reg < 0x1e;
217 #if defined(ARCH_X86_32)
219 static const uint8_t regs_saved[] = { R_BX };
220 static const uint8_t regs_volatile[] = { 0 };
221 #define n_regs_volatile 0U
222 static const uint8_t fp_saved[] = { 0 };
223 #define n_fp_saved 0U
224 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7 };
225 #define reg_is_saved(r) ((r) == R_BX)
227 #elif defined(ARCH_X86_WIN_ABI)
229 static const uint8_t regs_saved[] = { R_BX, R_R12, R_R13,
230 #ifndef TIMESTAMP_IN_REGISTER
231         R_R14,
232 #endif
233         };
234 static const uint8_t regs_volatile[] = { R_R8, R_R9, R_R10 };
235 static const uint8_t fp_saved[] = { 0 };
236 #define n_fp_saved 0U
237 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5 };
238 #define reg_is_saved(r) ((r) == R_BX || ((r) >= R_R12 && ((r) <= R_R15)))
240 #else
242 static const uint8_t regs_saved[] = { R_R13,
243 #ifndef TIMESTAMP_IN_REGISTER
244         R_R14,
245 #endif
246         R_R15,
247         };
248 #define n_regs_saved (n_array_elements(regs_saved) - !reg_is_segment(R_UPCALL))
249 static const uint8_t regs_volatile[] = { R_SI, R_DI, R_R8, R_R9, R_R10 };
250 static const uint8_t fp_saved[] = { 0 };
251 #define n_fp_saved 0U
252 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 };
253 #define reg_is_saved(r) ((r) >= R_R13 && (r) <= R_R15)
254 #endif
256 static bool attr_w imm_is_8bit(int64_t imm)
258         return imm >= -0x80 && imm < 0x80;
261 static bool attr_w imm_is_32bit(int64_t attr_unused imm)
263 #ifdef ARCH_X86_32
264         return true;
265 #else
266         return imm >= -0x80000000LL && imm < 0x80000000LL;
267 #endif
270 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
272         if (OP_SIZE_NATIVE == OP_SIZE_4)
273                 c = (int32_t)c;
274         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
275         gen_one(reg);
276         gen_one(ARG_IMM);
277         gen_eight(c);
278         return true;
281 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned attr_unused size)
283         ctx->offset_imm = imm;
284         ctx->offset_reg = false;
285         ctx->base_reg = base;
286         switch (purpose) {
287                 case IMM_PURPOSE_LDR_OFFSET:
288                 case IMM_PURPOSE_LDR_SX_OFFSET:
289                 case IMM_PURPOSE_STR_OFFSET:
290                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
291                 case IMM_PURPOSE_MVI_CLI_OFFSET:
292                         break;
293                 default:
294                         internal(file_line, "gen_address: invalid purpose %d", purpose);
295         }
296 #ifndef ARCH_X86_32
297         if (unlikely(!imm_is_32bit(imm)))
298                 return false;
299 #endif
300         return true;
303 static bool is_direct_const(int64_t attr_unused imm, unsigned attr_unused purpose, unsigned attr_unused size)
305 #ifdef ARCH_X86_32
306         return true;
307 #else
308         return imm_is_32bit(imm);
309 #endif
312 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
314 #if 0
315         if (size == OP_SIZE_1 && (unlikely(imm < -0x80LL) || unlikely(imm >= 0x80LL)))
316                 internal(file_line, "invalid imm for size 1: %016llx", (long long)imm);
317         if (size == OP_SIZE_2 && (unlikely(imm < -0x8000LL) || unlikely(imm >= 0x8000LL)))
318                 internal(file_line, "invalid imm for size 2 : %016llx", (long long)imm);
319         if (size == OP_SIZE_4 && (unlikely(imm < -0x80000000LL) || unlikely(imm >= 0x80000000LL)))
320                 internal(file_line, "invalid imm for size 3: %016llx", (long long)imm);
321 #endif
322         if (is_direct_const(imm, purpose, size)) {
323                 ctx->const_imm = imm;
324                 ctx->const_reg = false;
325         } else {
326                 gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
327                 gen_one(R_CONST_IMM);
328                 gen_one(ARG_IMM);
329                 gen_eight(imm);
330                 ctx->const_reg = true;
331         }
332         return true;
335 static bool attr_w gen_entry(struct codegen_context *ctx)
337 #if defined(ARCH_X86_32)
338         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
339         gen_one(R_BX);
341         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
342         gen_one(R_BP);
344         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
345         gen_one(R_SI);
347         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
348         gen_one(R_DI);
350         gen_insn(INSN_ALU, OP_SIZE_4, ALU_SUB, 1);
351         gen_one(R_SP);
352         gen_one(R_SP);
353         gen_one(ARG_IMM);
354         gen_eight(ARG_SPACE);
356         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
357         gen_one(R_FRAME);
358         gen_one(ARG_ADDRESS_1);
359         gen_one(R_SP);
360         gen_eight(ARG_SPACE + ARG_OFFSET);
362         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
363         gen_one(ARG_ADDRESS_1);
364         gen_one(R_SP);
365         gen_eight(ARG_SPACE + ARG_OFFSET + 12);
366 #elif defined(ARCH_X86_WIN_ABI)
367         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
368         gen_one(R_BX);
370         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
371         gen_one(R_BP);
373         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
374         gen_one(R_SI);
376         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
377         gen_one(R_DI);
379         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
380         gen_one(R_R12);
382         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
383         gen_one(R_R13);
385         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
386         gen_one(R_R14);
388         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
389         gen_one(R_R15);
391         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
392         gen_one(R_ARG0);
393 #ifndef TIMESTAMP_IN_REGISTER
394         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
395         gen_one(R_ARG3);
396 #endif
397         gen_insn(INSN_ALU, OP_SIZE_8, ALU_SUB, 1);
398         gen_one(R_SP);
399         gen_one(R_SP);
400         gen_one(ARG_IMM);
401         gen_eight(ARG_SPACE);
403         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
404         gen_one(R_FRAME);
405         gen_one(R_ARG1);
407         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
408         gen_one(R_UPCALL);
409         gen_one(R_ARG2);
410 #ifdef TIMESTAMP_IN_REGISTER
411         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
412         gen_one(R_TIMESTAMP);
413         gen_one(R_ARG3);
414 #endif
415         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
416         gen_one(ARG_ADDRESS_1);
417         gen_one(R_SP);
418         gen_eight(ARG_OFFSET);
419 #else
420         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
421         gen_one(R_BX);
423         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
424         gen_one(R_BP);
426         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
427         gen_one(R_R12);
429         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
430         gen_one(R_R13);
432         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
433         gen_one(R_R14);
435         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
436         gen_one(R_R15);
438         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
439         gen_one(R_ARG2);
440         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
441         gen_one(R_FRAME);
442         gen_one(R_ARG0);
444         if (!reg_is_segment(R_UPCALL)) {
445                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
446                 gen_one(R_UPCALL);
447                 gen_one(R_ARG1);
448         }
449 #ifdef TIMESTAMP_IN_REGISTER
450         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
451         gen_one(R_TIMESTAMP);
452         gen_one(R_ARG2);
453 #endif
454         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
455         gen_one(R_ARG3);
456 #endif
457         return true;
460 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
462 #if defined(ARCH_X86_32) || defined(ARCH_X86_64)
463         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
464         gen_one(R_DX);
465         gen_one(ARG_IMM);
466         gen_eight(ip);
467 #else
468         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
469         gen_one(R_AX);
470         gen_one(ARG_IMM);
471         gen_eight((uint64_t)ip << 32);
472 #endif
473         gen_insn(INSN_JMP, 0, 0, 0);
474         gen_four(escape_label);
476         return true;
479 static bool attr_w gen_escape(struct codegen_context *ctx)
481 #if defined(ARCH_X86_32)
482         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
483         gen_one(R_AX);
484         gen_one(R_FRAME);
486         gen_insn(INSN_ALU, OP_SIZE_4, ALU_ADD, 1);
487         gen_one(R_SP);
488         gen_one(R_SP);
489         gen_one(ARG_IMM);
490         gen_eight(ARG_SPACE);
492         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
493         gen_one(R_DI);
495         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
496         gen_one(R_SI);
498         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
499         gen_one(R_BP);
501         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
502         gen_one(R_BX);
504         gen_insn(INSN_RET, 0, 0, 0);
505 #elif defined(ARCH_X86_WIN_ABI)
506         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
507         gen_one(R_SP);
508         gen_one(R_SP);
509         gen_one(ARG_IMM);
510 #if defined(TIMESTAMP_IN_REGISTER)
511         gen_eight(ARG_SPACE);
512 #else
513         gen_eight(ARG_SPACE + 8);
514 #endif
515         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
516         gen_one(R_AX);
518         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
519         gen_one(ARG_ADDRESS_1);
520         gen_one(R_AX);
521         gen_eight(0);
522         gen_one(R_FRAME);
524         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
525         gen_one(ARG_ADDRESS_1);
526         gen_one(R_AX);
527         gen_eight(8);
528         gen_one(R_DX);
530         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
531         gen_one(R_R15);
533         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
534         gen_one(R_R14);
536         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
537         gen_one(R_R13);
539         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
540         gen_one(R_R12);
542         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
543         gen_one(R_DI);
545         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
546         gen_one(R_SI);
548         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
549         gen_one(R_BP);
551         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
552         gen_one(R_BX);
554         gen_insn(INSN_RET, 0, 0, 0);
555 #else
556 #if defined(ARCH_X86_X32)
557         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
558         gen_one(R_AX);
559         gen_one(R_AX);
560         gen_one(R_FRAME);
561 #else
562         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
563         gen_one(R_AX);
564         gen_one(R_FRAME);
565 #endif
566         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
567         gen_one(R_CX);
569         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
570         gen_one(R_R15);
572         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
573         gen_one(R_R14);
575         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
576         gen_one(R_R13);
578         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
579         gen_one(R_R12);
581         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
582         gen_one(R_BP);
584         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
585         gen_one(R_BX);
587         gen_insn(INSN_RET, 0, 0, 0);
588 #endif
589         return true;
592 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
594 #if defined(ARCH_X86_32)
595         ajla_assert_lo(arg * 4 < ARG_SPACE, (file_line, "gen_upcall_argument: argument %u", arg));
596         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
597         gen_one(ARG_ADDRESS_1);
598         gen_one(R_SP);
599         gen_eight(arg * 4);
600         gen_one(R_ARG0);
601 #endif
602         return true;
605 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
607 #if defined(ARCH_X86_32)
608         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
609         gen_one(R_AX);
610         gen_one(ARG_ADDRESS_1);
611         gen_one(R_SP);
612         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
614         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_4, 0, 0);
615         gen_one(ARG_ADDRESS_1);
616         gen_one(R_AX);
617         gen_eight(offset);
618 #elif defined(ARCH_X86_X32)
619         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
620         gen_one(R_AX);
621         gen_one(ARG_ADDRESS_1);
622         gen_one(R_UPCALL);
623         gen_eight(offset);
625         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
626         gen_one(R_AX);
627 #else
628         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
629         gen_one(ARG_ADDRESS_1);
630         gen_one(R_UPCALL);
631         gen_eight(offset);
632 #endif
633         g(gen_upcall_end(ctx, n_args));
635         return true;
638 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
640 #if defined(ARCH_X86_32)
641         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
642         gen_one(R_AX);
643         gen_one(ARG_ADDRESS_1);
644         gen_one(R_SP);
645         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
647         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
648         gen_one(R_DX);
649         gen_one(ARG_ADDRESS_1);
650         gen_one(R_SP);
651         gen_eight(ARG_SPACE + ARG_OFFSET + 8);
653         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
654         gen_one(R_DX);
655         gen_one(ARG_ADDRESS_1);
656         gen_one(R_AX);
657         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
658 #elif defined(TIMESTAMP_IN_REGISTER)
659         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
660         gen_one(R_TIMESTAMP);
661         gen_one(ARG_ADDRESS_1);
662         gen_one(R_UPCALL);
663         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
664 #else
665         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
666         gen_one(R_AX);
667         gen_one(ARG_ADDRESS_1);
668         gen_one(R_SP);
669 #if defined(ARCH_X86_WIN_ABI)
670         gen_eight(ARG_SPACE);
671 #else
672         gen_eight(0);
673 #endif
674         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
675         gen_one(R_AX);
676         gen_one(ARG_ADDRESS_1);
677         gen_one(R_UPCALL);
678         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
679 #endif
680         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
681         gen_four(escape_label);
683         return true;