codegen: fix bug on riscv when --ptrcomp was used
[ajla.git] / c1-x86.inc
blob9fae0282d714db8be0fd46255a610669437edbb5
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_HAS_FP_GP_MOV              cpu_test_feature(CPU_FEATURE_sse2)
57 #define ARCH_NEEDS_BARRIER              0
59 #define i_size(size)                    (size)
60 #define i_size_rot(size)                (size)
61 #define i_size_cmp(size)                (size)
63 #define R_AX            0x0
64 #define R_CX            0x1
65 #define R_DX            0x2
66 #define R_BX            0x3
67 #define R_SP            0x4
68 #define R_BP            0x5
69 #define R_SI            0x6
70 #define R_DI            0x7
71 #define R_R8            0x8
72 #define R_R9            0x9
73 #define R_R10           0xa
74 #define R_R11           0xb
75 #define R_R12           0xc
76 #define R_R13           0xd
77 #define R_R14           0xe
78 #define R_R15           0xf
80 #define R_ST0           0x10
81 #define R_ST1           0x11
82 #define R_ST2           0x12
83 #define R_ST3           0x13
84 #define R_ST4           0x14
85 #define R_ST5           0x15
86 #define R_ST6           0x16
87 #define R_ST7           0x17
89 #define R_ES            0x18
90 #define R_CS            0x19
91 #define R_SS            0x1a
92 #define R_DS            0x1b
93 #define R_FS            0x1c
94 #define R_GS            0x1d
96 #define R_XMM0          0x20
97 #define R_XMM1          0x21
98 #define R_XMM2          0x22
99 #define R_XMM3          0x23
100 #define R_XMM4          0x24
101 #define R_XMM5          0x25
102 #define R_XMM6          0x26
103 #define R_XMM7          0x27
104 #define R_XMM8          0x28
105 #define R_XMM9          0x29
106 #define R_XMM10         0x2a
107 #define R_XMM11         0x2b
108 #define R_XMM12         0x2c
109 #define R_XMM13         0x2d
110 #define R_XMM14         0x2e
111 #define R_XMM15         0x2f
112 #define R_XMM16         0x30
113 #define R_XMM17         0x31
114 #define R_XMM18         0x32
115 #define R_XMM19         0x33
116 #define R_XMM20         0x34
117 #define R_XMM21         0x35
118 #define R_XMM22         0x36
119 #define R_XMM23         0x37
120 #define R_XMM24         0x38
121 #define R_XMM25         0x39
122 #define R_XMM26         0x3a
123 #define R_XMM27         0x3b
124 #define R_XMM28         0x3c
125 #define R_XMM29         0x3d
126 #define R_XMM30         0x3e
127 #define R_XMM31         0x3f
129 #define R_IS_GPR(r)     ((r) < 16)
130 #define R_IS_XMM(r)     ((r) >= R_XMM0 && (r) <= R_XMM31)
132 /*#define TIMESTAMP_IN_REGISTER*/
134 #ifndef ARCH_X86_32
135 static uint8_t upcall_register = R_R15;
136 #define R_UPCALL        upcall_register
137 #ifdef TIMESTAMP_IN_REGISTER
138 #define R_TIMESTAMP     R_R14
139 #endif
140 #define R_CONST_IMM     R_R11
141 #else
142 #define R_CONST_IMM     255     /* this should not be used */
143 #endif
144 #define R_OFFSET_IMM    255     /* this should not be used */
146 #if defined(ARCH_X86_32)
147 #define R_FRAME         R_BP
148 #define R_SCRATCH_1     R_AX
149 #define R_SCRATCH_2     R_DX
150 #define R_SCRATCH_3     R_CX
151 #define R_SCRATCH_4     R_SAVED_2
152 #define R_SAVED_1       R_SI
153 #define R_SAVED_2       R_DI
154 #elif defined(ARCH_X86_WIN_ABI)
155 #define R_FRAME         R_BP
156 #define R_SCRATCH_1     R_AX
157 #define R_SCRATCH_2     R_DX
158 #define R_SCRATCH_3     R_CX
159 #define R_SCRATCH_4     R_SAVED_2
160 #define R_SAVED_1       R_SI
161 #define R_SAVED_2       R_DI
162 #else
163 #define R_FRAME         R_BX
164 #define R_SCRATCH_1     R_AX
165 #define R_SCRATCH_2     R_DX
166 #define R_SCRATCH_3     R_CX
167 #define R_SCRATCH_4     R_SAVED_2
168 #define R_SAVED_1       R_BP
169 #define R_SAVED_2       R_R12
170 #endif
172 #define FR_SCRATCH_1    R_XMM0
173 #define FR_SCRATCH_2    R_XMM1
175 #if defined(ARCH_X86_32)
176 #define R_ARG0          R_AX
177 #define R_ARG1          R_AX
178 #define R_ARG2          R_AX
179 #define R_ARG3          R_AX
180 #elif defined(ARCH_X86_WIN_ABI)
181 #define R_ARG0          R_CX
182 #define R_ARG1          R_DX
183 #define R_ARG2          R_R8
184 #define R_ARG3          R_R9
185 #else
186 #define R_ARG0          R_DI
187 #define R_ARG1          R_SI
188 #define R_ARG2          R_DX
189 #define R_ARG3          R_CX
190 #endif
191 #define R_RET0          R_AX
193 #if defined(ARCH_X86_32)
194 #define ARG_SPACE       0x1c            /* must be 0xc modulo 0x10 */
195 #define ARG_OFFSET      0x14
196 #elif defined(ARCH_X86_WIN_ABI) && !defined(TIMESTAMP_IN_REGISTER)
197 #define ARG_SPACE       0x28            /* must be 0x8 modulo 0x10 */
198 #define ARG_OFFSET      0xa0
199 #elif defined(ARCH_X86_WIN_ABI)
200 #define ARG_SPACE       0x20            /* must be 0x0 modulo 0x10 */
201 #define ARG_OFFSET      0x90
202 #endif
204 #define SUPPORTED_FP            (cpu_test_feature(CPU_FEATURE_sse) * 0x2 + cpu_test_feature(CPU_FEATURE_sse2) * 0x4)
205 #define SUPPORTED_FP_X87        0xe
206 #define SUPPORTED_FP_HALF_CVT   (cpu_test_feature(CPU_FEATURE_f16c) * 0x1)
208 static bool reg_is_fp(unsigned reg)
210         return reg >= 0x20 && reg < 0x40;
213 static bool reg_is_segment(unsigned reg)
215         return reg >= 0x18 && reg < 0x1e;
218 #if defined(ARCH_X86_32)
220 static const uint8_t regs_saved[] = { R_BX };
221 static const uint8_t regs_volatile[] = { 0 };
222 #define n_regs_volatile 0U
223 static const uint8_t fp_saved[] = { 0 };
224 #define n_fp_saved 0U
225 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7 };
226 #define reg_is_saved(r) ((r) == R_BX)
228 #elif defined(ARCH_X86_WIN_ABI)
230 static const uint8_t regs_saved[] = { R_BX, R_R12, R_R13,
231 #ifndef TIMESTAMP_IN_REGISTER
232         R_R14,
233 #endif
234         };
235 static const uint8_t regs_volatile[] = { R_R8, R_R9, R_R10 };
236 static const uint8_t fp_saved[] = { 0 };
237 #define n_fp_saved 0U
238 static const uint8_t fp_volatile[] = { R_XMM2, R_XMM3, R_XMM4, R_XMM5 };
239 #define reg_is_saved(r) ((r) == R_BX || ((r) >= R_R12 && ((r) <= R_R15)))
241 #else
243 static const uint8_t regs_saved[] = { R_R13,
244 #ifndef TIMESTAMP_IN_REGISTER
245         R_R14,
246 #endif
247         R_R15,
248         };
249 #define n_regs_saved (n_array_elements(regs_saved) - !reg_is_segment(R_UPCALL))
250 static const uint8_t regs_volatile[] = { R_SI, R_DI, R_R8, R_R9, R_R10 };
251 static const uint8_t fp_saved[] = { 0 };
252 #define n_fp_saved 0U
253 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 };
254 #define reg_is_saved(r) ((r) >= R_R13 && (r) <= R_R15)
255 #endif
257 static bool attr_w imm_is_8bit(int64_t imm)
259         return imm >= -0x80 && imm < 0x80;
262 static bool attr_w imm_is_32bit(int64_t attr_unused imm)
264 #ifdef ARCH_X86_32
265         return true;
266 #else
267         return imm >= -0x80000000LL && imm < 0x80000000LL;
268 #endif
271 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
273         if (OP_SIZE_NATIVE == OP_SIZE_4)
274                 c = (int32_t)c;
275         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
276         gen_one(reg);
277         gen_one(ARG_IMM);
278         gen_eight(c);
279         return true;
282 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned attr_unused size)
284         ctx->offset_imm = imm;
285         ctx->offset_reg = false;
286         ctx->base_reg = base;
287         switch (purpose) {
288                 case IMM_PURPOSE_LDR_OFFSET:
289                 case IMM_PURPOSE_LDR_SX_OFFSET:
290                 case IMM_PURPOSE_STR_OFFSET:
291                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
292                 case IMM_PURPOSE_MVI_CLI_OFFSET:
293                         break;
294                 default:
295                         internal(file_line, "gen_address: invalid purpose %d", purpose);
296         }
297 #ifndef ARCH_X86_32
298         if (unlikely(!imm_is_32bit(imm)))
299                 return false;
300 #endif
301         return true;
304 static bool is_direct_const(int64_t attr_unused imm, unsigned attr_unused purpose, unsigned attr_unused size)
306 #ifdef ARCH_X86_32
307         return true;
308 #else
309         return imm_is_32bit(imm);
310 #endif
313 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
315 #if 0
316         if (size == OP_SIZE_1 && (unlikely(imm < -0x80LL) || unlikely(imm >= 0x80LL)))
317                 internal(file_line, "invalid imm for size 1: %016llx", (long long)imm);
318         if (size == OP_SIZE_2 && (unlikely(imm < -0x8000LL) || unlikely(imm >= 0x8000LL)))
319                 internal(file_line, "invalid imm for size 2 : %016llx", (long long)imm);
320         if (size == OP_SIZE_4 && (unlikely(imm < -0x80000000LL) || unlikely(imm >= 0x80000000LL)))
321                 internal(file_line, "invalid imm for size 3: %016llx", (long long)imm);
322 #endif
323         if (is_direct_const(imm, purpose, size)) {
324                 ctx->const_imm = imm;
325                 ctx->const_reg = false;
326         } else {
327                 gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
328                 gen_one(R_CONST_IMM);
329                 gen_one(ARG_IMM);
330                 gen_eight(imm);
331                 ctx->const_reg = true;
332         }
333         return true;
336 static bool attr_w gen_entry(struct codegen_context *ctx)
338 #if defined(ARCH_X86_32)
339         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
340         gen_one(R_BX);
342         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
343         gen_one(R_BP);
345         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
346         gen_one(R_SI);
348         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
349         gen_one(R_DI);
351         gen_insn(INSN_ALU, OP_SIZE_4, ALU_SUB, 1);
352         gen_one(R_SP);
353         gen_one(R_SP);
354         gen_one(ARG_IMM);
355         gen_eight(ARG_SPACE);
357         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
358         gen_one(R_FRAME);
359         gen_one(ARG_ADDRESS_1);
360         gen_one(R_SP);
361         gen_eight(ARG_SPACE + ARG_OFFSET);
363         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
364         gen_one(ARG_ADDRESS_1);
365         gen_one(R_SP);
366         gen_eight(ARG_SPACE + ARG_OFFSET + 12);
367 #elif defined(ARCH_X86_WIN_ABI)
368         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
369         gen_one(R_BX);
371         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
372         gen_one(R_BP);
374         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
375         gen_one(R_SI);
377         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
378         gen_one(R_DI);
380         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
381         gen_one(R_R12);
383         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
384         gen_one(R_R13);
386         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
387         gen_one(R_R14);
389         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
390         gen_one(R_R15);
392         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
393         gen_one(R_ARG0);
394 #ifndef TIMESTAMP_IN_REGISTER
395         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
396         gen_one(R_ARG3);
397 #endif
398         gen_insn(INSN_ALU, OP_SIZE_8, ALU_SUB, 1);
399         gen_one(R_SP);
400         gen_one(R_SP);
401         gen_one(ARG_IMM);
402         gen_eight(ARG_SPACE);
404         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
405         gen_one(R_FRAME);
406         gen_one(R_ARG1);
408         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
409         gen_one(R_UPCALL);
410         gen_one(R_ARG2);
411 #ifdef TIMESTAMP_IN_REGISTER
412         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
413         gen_one(R_TIMESTAMP);
414         gen_one(R_ARG3);
415 #endif
416         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
417         gen_one(ARG_ADDRESS_1);
418         gen_one(R_SP);
419         gen_eight(ARG_OFFSET);
420 #else
421         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
422         gen_one(R_BX);
424         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
425         gen_one(R_BP);
427         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
428         gen_one(R_R12);
430         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
431         gen_one(R_R13);
433         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
434         gen_one(R_R14);
436         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
437         gen_one(R_R15);
439         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
440         gen_one(R_ARG2);
441         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
442         gen_one(R_FRAME);
443         gen_one(R_ARG0);
445         if (!reg_is_segment(R_UPCALL)) {
446                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
447                 gen_one(R_UPCALL);
448                 gen_one(R_ARG1);
449         }
450 #ifdef TIMESTAMP_IN_REGISTER
451         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
452         gen_one(R_TIMESTAMP);
453         gen_one(R_ARG2);
454 #endif
455         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
456         gen_one(R_ARG3);
457 #endif
458         return true;
461 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
463 #if defined(ARCH_X86_32) || defined(ARCH_X86_64)
464         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
465         gen_one(R_DX);
466         gen_one(ARG_IMM);
467         gen_eight(ip);
468 #else
469         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
470         gen_one(R_AX);
471         gen_one(ARG_IMM);
472         gen_eight((uint64_t)ip << 32);
473 #endif
474         gen_insn(INSN_JMP, 0, 0, 0);
475         gen_four(escape_label);
477         return true;
480 static bool attr_w gen_escape(struct codegen_context *ctx)
482 #if defined(ARCH_X86_32)
483         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
484         gen_one(R_AX);
485         gen_one(R_FRAME);
487         gen_insn(INSN_ALU, OP_SIZE_4, ALU_ADD, 1);
488         gen_one(R_SP);
489         gen_one(R_SP);
490         gen_one(ARG_IMM);
491         gen_eight(ARG_SPACE);
493         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
494         gen_one(R_DI);
496         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
497         gen_one(R_SI);
499         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
500         gen_one(R_BP);
502         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
503         gen_one(R_BX);
505         gen_insn(INSN_RET, 0, 0, 0);
506 #elif defined(ARCH_X86_WIN_ABI)
507         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
508         gen_one(R_SP);
509         gen_one(R_SP);
510         gen_one(ARG_IMM);
511 #if defined(TIMESTAMP_IN_REGISTER)
512         gen_eight(ARG_SPACE);
513 #else
514         gen_eight(ARG_SPACE + 8);
515 #endif
516         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
517         gen_one(R_AX);
519         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
520         gen_one(ARG_ADDRESS_1);
521         gen_one(R_AX);
522         gen_eight(0);
523         gen_one(R_FRAME);
525         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
526         gen_one(ARG_ADDRESS_1);
527         gen_one(R_AX);
528         gen_eight(8);
529         gen_one(R_DX);
531         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
532         gen_one(R_R15);
534         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
535         gen_one(R_R14);
537         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
538         gen_one(R_R13);
540         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
541         gen_one(R_R12);
543         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
544         gen_one(R_DI);
546         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
547         gen_one(R_SI);
549         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
550         gen_one(R_BP);
552         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
553         gen_one(R_BX);
555         gen_insn(INSN_RET, 0, 0, 0);
556 #else
557 #if defined(ARCH_X86_X32)
558         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
559         gen_one(R_AX);
560         gen_one(R_AX);
561         gen_one(R_FRAME);
562 #else
563         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
564         gen_one(R_AX);
565         gen_one(R_FRAME);
566 #endif
567         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
568         gen_one(R_CX);
570         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
571         gen_one(R_R15);
573         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
574         gen_one(R_R14);
576         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
577         gen_one(R_R13);
579         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
580         gen_one(R_R12);
582         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
583         gen_one(R_BP);
585         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
586         gen_one(R_BX);
588         gen_insn(INSN_RET, 0, 0, 0);
589 #endif
590         return true;
593 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
595 #if defined(ARCH_X86_32)
596         ajla_assert_lo(arg * 4 < ARG_SPACE, (file_line, "gen_upcall_argument: argument %u", arg));
597         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
598         gen_one(ARG_ADDRESS_1);
599         gen_one(R_SP);
600         gen_eight(arg * 4);
601         gen_one(R_ARG0);
602 #endif
603         return true;
606 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
608 #if defined(ARCH_X86_32)
609         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
610         gen_one(R_AX);
611         gen_one(ARG_ADDRESS_1);
612         gen_one(R_SP);
613         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
615         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_4, 0, 0);
616         gen_one(ARG_ADDRESS_1);
617         gen_one(R_AX);
618         gen_eight(offset);
619 #elif defined(ARCH_X86_X32)
620         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
621         gen_one(R_AX);
622         gen_one(ARG_ADDRESS_1);
623         gen_one(R_UPCALL);
624         gen_eight(offset);
626         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
627         gen_one(R_AX);
628 #else
629         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
630         gen_one(ARG_ADDRESS_1);
631         gen_one(R_UPCALL);
632         gen_eight(offset);
633 #endif
634         g(gen_upcall_end(ctx, n_args));
636         return true;
639 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
641 #if defined(ARCH_X86_32)
642         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
643         gen_one(R_AX);
644         gen_one(ARG_ADDRESS_1);
645         gen_one(R_SP);
646         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
648         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
649         gen_one(R_DX);
650         gen_one(ARG_ADDRESS_1);
651         gen_one(R_SP);
652         gen_eight(ARG_SPACE + ARG_OFFSET + 8);
654         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
655         gen_one(R_DX);
656         gen_one(ARG_ADDRESS_1);
657         gen_one(R_AX);
658         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
659 #elif defined(TIMESTAMP_IN_REGISTER)
660         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
661         gen_one(R_TIMESTAMP);
662         gen_one(ARG_ADDRESS_1);
663         gen_one(R_UPCALL);
664         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
665 #else
666         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
667         gen_one(R_AX);
668         gen_one(ARG_ADDRESS_1);
669         gen_one(R_SP);
670 #if defined(ARCH_X86_WIN_ABI)
671         gen_eight(ARG_SPACE);
672 #else
673         gen_eight(0);
674 #endif
675         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
676         gen_one(R_AX);
677         gen_one(ARG_ADDRESS_1);
678         gen_one(R_UPCALL);
679         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
680 #endif
681         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
682         gen_four(escape_label);
684         return true;