x86-64: remove pushes and pops arounf pointer_dereference and
[ajla.git] / c1-x86.inc
blob74f6a90f7b430a25a6183b690e5fab220ef538a9
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(size, alu, is_mem, is_imm, imm)        ((alu) == ALU_ADD && (size) >= OP_SIZE_2 && !(is_mem) ? 0 : ((alu) == ALU_ADD || (alu) == ALU_SUB) && (is_imm) && ((imm) == -1 || (imm) == 1) ? 1 : 3)
36 #define ALU1_WRITES_FLAGS(alu)          ((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_entry(struct codegen_context *ctx)
317 #if defined(ARCH_X86_32)
318         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
319         gen_one(R_BX);
321         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
322         gen_one(R_BP);
324         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
325         gen_one(R_SI);
327         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
328         gen_one(R_DI);
330         gen_insn(INSN_ALU, OP_SIZE_4, ALU_SUB, 1);
331         gen_one(R_SP);
332         gen_one(R_SP);
333         gen_one(ARG_IMM);
334         gen_eight(ARG_SPACE);
336         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
337         gen_one(R_FRAME);
338         gen_one(ARG_ADDRESS_1);
339         gen_one(R_SP);
340         gen_eight(ARG_SPACE + ARG_OFFSET);
342         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
343         gen_one(ARG_ADDRESS_1);
344         gen_one(R_SP);
345         gen_eight(ARG_SPACE + ARG_OFFSET + 12);
346 #elif defined(ARCH_X86_WIN_ABI)
347         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
348         gen_one(R_BX);
350         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
351         gen_one(R_BP);
353         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
354         gen_one(R_SI);
356         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
357         gen_one(R_DI);
359         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
360         gen_one(R_R12);
362         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
363         gen_one(R_R13);
365         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
366         gen_one(R_R14);
368         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
369         gen_one(R_R15);
371         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
372         gen_one(R_ARG0);
373 #ifndef TIMESTAMP_IN_REGISTER
374         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
375         gen_one(R_ARG3);
376 #endif
377         gen_insn(INSN_ALU, OP_SIZE_8, ALU_SUB, 1);
378         gen_one(R_SP);
379         gen_one(R_SP);
380         gen_one(ARG_IMM);
381         gen_eight(ARG_SPACE);
383         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
384         gen_one(R_FRAME);
385         gen_one(R_ARG1);
387         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
388         gen_one(R_UPCALL);
389         gen_one(R_ARG2);
390 #ifdef TIMESTAMP_IN_REGISTER
391         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
392         gen_one(R_TIMESTAMP);
393         gen_one(R_ARG3);
394 #endif
395         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
396         gen_one(ARG_ADDRESS_1);
397         gen_one(R_SP);
398         gen_eight(ARG_OFFSET);
399 #else
400         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
401         gen_one(R_BX);
403         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
404         gen_one(R_BP);
406         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
407         gen_one(R_R12);
409         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
410         gen_one(R_R13);
412         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
413         gen_one(R_R14);
415         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
416         gen_one(R_R15);
418         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
419         gen_one(R_ARG2);
420         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
421         gen_one(R_FRAME);
422         gen_one(R_ARG0);
424         if (!reg_is_segment(R_UPCALL)) {
425                 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
426                 gen_one(R_UPCALL);
427                 gen_one(R_ARG1);
428         }
429 #ifdef TIMESTAMP_IN_REGISTER
430         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
431         gen_one(R_TIMESTAMP);
432         gen_one(R_ARG2);
433 #endif
434 #if defined(ARCH_X86_X32)
435         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
436         gen_one(R_ARG3);
437         gen_one(R_ARG3);
438 #endif
439         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
440         gen_one(R_ARG3);
441 #endif
442         return true;
445 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
447 #if defined(ARCH_X86_32) || defined(ARCH_X86_64)
448         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
449         gen_one(R_DX);
450         gen_one(ARG_IMM);
451         gen_eight(ip);
452 #else
453         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
454         gen_one(R_AX);
455         gen_one(ARG_IMM);
456         gen_eight((uint64_t)ip << 32);
457 #endif
458         gen_insn(INSN_JMP, 0, 0, 0);
459         gen_four(escape_label);
461         return true;
464 static bool attr_w gen_escape(struct codegen_context *ctx)
466 #if defined(ARCH_X86_32)
467         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
468         gen_one(R_AX);
469         gen_one(R_FRAME);
471         gen_insn(INSN_ALU, OP_SIZE_4, ALU_ADD, 1);
472         gen_one(R_SP);
473         gen_one(R_SP);
474         gen_one(ARG_IMM);
475         gen_eight(ARG_SPACE);
477         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
478         gen_one(R_DI);
480         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
481         gen_one(R_SI);
483         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
484         gen_one(R_BP);
486         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
487         gen_one(R_BX);
489         gen_insn(INSN_RET, 0, 0, 0);
490 #elif defined(ARCH_X86_WIN_ABI)
491         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
492         gen_one(R_SP);
493         gen_one(R_SP);
494         gen_one(ARG_IMM);
495 #if defined(TIMESTAMP_IN_REGISTER)
496         gen_eight(ARG_SPACE);
497 #else
498         gen_eight(ARG_SPACE + 8);
499 #endif
500         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
501         gen_one(R_AX);
503         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
504         gen_one(ARG_ADDRESS_1);
505         gen_one(R_AX);
506         gen_eight(0);
507         gen_one(R_FRAME);
509         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
510         gen_one(ARG_ADDRESS_1);
511         gen_one(R_AX);
512         gen_eight(8);
513         gen_one(R_DX);
515         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
516         gen_one(R_R15);
518         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
519         gen_one(R_R14);
521         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
522         gen_one(R_R13);
524         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
525         gen_one(R_R12);
527         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
528         gen_one(R_DI);
530         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
531         gen_one(R_SI);
533         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
534         gen_one(R_BP);
536         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
537         gen_one(R_BX);
539         gen_insn(INSN_RET, 0, 0, 0);
540 #else
541 #if defined(ARCH_X86_X32)
542         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
543         gen_one(R_AX);
544         gen_one(R_AX);
545         gen_one(R_FRAME);
546 #else
547         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
548         gen_one(R_AX);
549         gen_one(R_FRAME);
550 #endif
551         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
552         gen_one(R_CX);
554         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
555         gen_one(R_R15);
557         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
558         gen_one(R_R14);
560         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
561         gen_one(R_R13);
563         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
564         gen_one(R_R12);
566         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
567         gen_one(R_BP);
569         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
570         gen_one(R_BX);
572         gen_insn(INSN_RET, 0, 0, 0);
573 #endif
574         return true;
577 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
579 #if defined(ARCH_X86_32)
580         ajla_assert_lo(arg * 4 < ARG_SPACE, (file_line, "gen_upcall_argument: argument %u", arg));
581         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
582         gen_one(ARG_ADDRESS_1);
583         gen_one(R_SP);
584         gen_eight(arg * 4);
585         gen_one(R_ARG0);
586 #endif
587         return true;
590 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
592 #if defined(ARCH_X86_32)
593         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
594         gen_one(R_AX);
595         gen_one(ARG_ADDRESS_1);
596         gen_one(R_SP);
597         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
599         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_4, 0, 0);
600         gen_one(ARG_ADDRESS_1);
601         gen_one(R_AX);
602         gen_eight(offset);
603 #elif defined(ARCH_X86_X32)
604         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
605         gen_one(R_AX);
606         gen_one(ARG_ADDRESS_1);
607         gen_one(R_UPCALL);
608         gen_eight(offset);
610         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
611         gen_one(R_AX);
612 #else
613         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
614         gen_one(ARG_ADDRESS_1);
615         gen_one(R_UPCALL);
616         gen_eight(offset);
617 #endif
618         g(gen_upcall_end(ctx, offset, n_args));
620         return true;
623 static bool attr_w gen_get_upcall_pointer(struct codegen_context *ctx, unsigned offset, unsigned reg)
625 #if defined(ARCH_X86_32)
626         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
627         gen_one(reg);
628         gen_one(ARG_ADDRESS_1);
629         gen_one(R_SP);
630         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
632         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
633         gen_one(reg);
634         gen_one(ARG_ADDRESS_1);
635         gen_one(reg);
636         gen_eight(offset);
637 #else
638         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
639         gen_one(reg);
640         gen_one(ARG_ADDRESS_1);
641         gen_one(R_UPCALL);
642         gen_eight(offset);
643 #endif
644         return true;
647 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
649 #if defined(ARCH_X86_32)
650         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
651         gen_one(R_AX);
652         gen_one(ARG_ADDRESS_1);
653         gen_one(R_SP);
654         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
656         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
657         gen_one(R_DX);
658         gen_one(ARG_ADDRESS_1);
659         gen_one(R_SP);
660         gen_eight(ARG_SPACE + ARG_OFFSET + 8);
662         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
663         gen_one(R_DX);
664         gen_one(ARG_ADDRESS_1);
665         gen_one(R_AX);
666         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
667 #elif defined(TIMESTAMP_IN_REGISTER)
668         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
669         gen_one(R_TIMESTAMP);
670         gen_one(ARG_ADDRESS_1);
671         gen_one(R_UPCALL);
672         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
673 #else
674         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
675         gen_one(R_AX);
676         gen_one(ARG_ADDRESS_1);
677         gen_one(R_SP);
678 #if defined(ARCH_X86_WIN_ABI)
679         gen_eight(ARG_SPACE);
680 #else
681         gen_eight(0);
682 #endif
683         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
684         gen_one(R_AX);
685         gen_one(ARG_ADDRESS_1);
686         gen_one(R_UPCALL);
687         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
688 #endif
689         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_NE, 0);
690         gen_four(escape_label);
692         return true;