x86: x87 FPU may be used as fallback for operations that are not
[ajla.git] / codegen.c
blob2ad0c589e14b5f7dbfa8e84fd615805ec284a457
1 /*
2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
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.
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.
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/>.
19 #include "ajla.h"
21 #ifndef FILE_OMIT
23 #include "data.h"
24 #include "os.h"
25 #include "os_util.h"
26 #include "util.h"
27 #include "ipfn.h"
28 #include "ipret.h"
29 #include "funct.h"
30 #include "thread.h"
31 #include "task.h"
32 #include "save.h"
34 #include "codegen.h"
36 #ifdef HAVE_CODEGEN
38 #define flag_cache_chicken 0
39 #define must_be_flat_chicken 0
40 #define ra_chicken 0
42 #define INLINE_BITMAP_SLOTS 16
43 #define INLINE_COPY_SIZE 64
45 /*#define DEBUG_INSNS*/
46 /*#define DEBUG_GARBAGE*/
48 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
49 #if defined(HAVE_SYSCALL) && defined(HAVE_ASM_PRCTL_H) && defined(HAVE_SYS_SYSCALL_H)
50 #include <asm/prctl.h>
51 #include <sys/syscall.h>
52 #include <unistd.h>
53 #endif
54 #if (defined(HAVE_AMD64_SET_GSBASE) || defined(HAVE_SYSARCH)) && defined(HAVE_X86_SYSARCH_H)
55 #include <x86/sysarch.h>
56 #endif
57 #endif
59 code_return_t (*codegen_entry)(frame_s *, struct cg_upcall_vector_s *, tick_stamp_t, void *);
60 static void *codegen_ptr;
61 static size_t codegen_size;
63 #ifdef DEBUG_ENV
64 static mutex_t dump_mutex;
65 static uint64_t dump_seq = 0;
66 #endif
69 * insn:
70 * opcode - 16 bits
71 * op_size - 3 bits
72 * aux - 7 bits
73 * writes flags - 2 bit
74 * jmp size - 2 bits
77 #define INSN_OPCODE 0x0000ffffUL
78 #define INSN_OP_SIZE 0x00070000UL
79 #define INSN_AUX 0x03f80000UL
80 #define INSN_WRITES_FLAGS 0x0c000000UL
81 #define INSN_JUMP_SIZE 0x30000000UL
83 #define INSN_OPCODE_SHIFT 0
84 #define INSN_OP_SIZE_SHIFT 16
85 #define INSN_AUX_SHIFT 19
86 #define INSN_WRITES_FLAGS_SHIFT 26
87 #define INSN_JUMP_SIZE_SHIFT 28
89 #define insn_opcode(insn) (((insn) >> INSN_OPCODE_SHIFT) & (INSN_OPCODE >> INSN_OPCODE_SHIFT))
90 #define insn_op_size(insn) (((insn) >> INSN_OP_SIZE_SHIFT) & (INSN_OP_SIZE >> INSN_OP_SIZE_SHIFT))
91 #define insn_aux(insn) (((insn) >> INSN_AUX_SHIFT) & (INSN_AUX >> INSN_AUX_SHIFT))
92 #define insn_writes_flags(insn) (((insn) >> INSN_WRITES_FLAGS_SHIFT) & (INSN_WRITES_FLAGS >> INSN_WRITES_FLAGS_SHIFT))
93 #define insn_jump_size(insn) (((insn) >> INSN_JUMP_SIZE_SHIFT) & (INSN_JUMP_SIZE >> INSN_JUMP_SIZE_SHIFT))
95 #define ALU_ADD 0x00
96 #define ALU_OR 0x01
97 #define ALU_ADC 0x02
98 #define ALU_SBB 0x03
99 #define ALU_AND 0x04
100 #define ALU_SUB 0x05
101 #define ALU_XOR 0x06
102 #define ALU_ORN 0x08
103 #define ALU_ANDN 0x09
104 #define ALU_XORN 0x0a
105 #define ALU_MUL 0x10
106 #define ALU_UMULH 0x11
107 #define ALU_SMULH 0x12
108 #define ALU_UDIV 0x13
109 #define ALU_SDIV 0x14
110 #define ALU_UREM 0x15
111 #define ALU_SREM 0x16
112 #define ALU_SAVE 0x17
113 #define ALU_EXTBL 0x18
114 #define ALU_EXTWL 0x19
115 #define ALU_EXTLL 0x1a
116 #define ALU_EXTLH 0x1b
117 #define ALU_INSBL 0x1c
118 #define ALU_MSKBL 0x1d
119 #define ALU_ZAP 0x20
120 #define ALU_ZAPNOT 0x21
122 #define ALU1_NOT 0x00
123 #define ALU1_NEG 0x01
124 #define ALU1_NGC 0x02
125 #define ALU1_INC 0x03
126 #define ALU1_DEC 0x04
127 #define ALU1_BSWAP 0x05
128 #define ALU1_BSWAP16 0x06
129 #define ALU1_BREV 0x07
130 #define ALU1_BSF 0x08
131 #define ALU1_BSR 0x09
132 #define ALU1_LZCNT 0x0a
133 #define ALU1_POPCNT 0x0b
135 #define FP_ALU_ADD 0
136 #define FP_ALU_SUB 1
137 #define FP_ALU_MUL 2
138 #define FP_ALU_DIV 3
139 #define FP_ALU1_NEG 0
140 #define FP_ALU1_SQRT 1
141 #define FP_ALU1_ROUND 2
142 #define FP_ALU1_FLOOR 3
143 #define FP_ALU1_CEIL 4
144 #define FP_ALU1_TRUNC 5
145 #define FP_ALU1_VCNT8 6
146 #define FP_ALU1_VPADDL 7
147 #define FP_ALU1_ADDV 8
149 #define COND_O 0x0
150 #define COND_NO 0x1
151 #define COND_B 0x2
152 #define COND_AE 0x3
153 #define COND_E 0x4
154 #define COND_NE 0x5
155 #define COND_BE 0x6
156 #define COND_A 0x7
157 #define COND_S 0x8
158 #define COND_NS 0x9
159 #define COND_P 0xa
160 #define COND_NP 0xb
161 #define COND_L 0xc
162 #define COND_GE 0xd
163 #define COND_LE 0xe
164 #define COND_G 0xf
165 #define COND_BLBC 0x10
166 #define COND_BLBS 0x11
167 #define COND_ALWAYS 0x12
169 #define COND_FP 0x20
170 #define FP_COND_P (COND_FP | COND_P)
171 #define FP_COND_NP (COND_FP | COND_NP)
172 #define FP_COND_E (COND_FP | COND_E)
173 #define FP_COND_NE (COND_FP | COND_NE)
174 #define FP_COND_A (COND_FP | COND_A)
175 #define FP_COND_BE (COND_FP | COND_BE)
176 #define FP_COND_B (COND_FP | COND_B)
177 #define FP_COND_AE (COND_FP | COND_AE)
179 #define ROT_ROL 0x0
180 #define ROT_ROR 0x1
181 #define ROT_RCL 0x2
182 #define ROT_RCR 0x3
183 #define ROT_SHL 0x4
184 #define ROT_SHR 0x5
185 #define ROT_SAR 0x7
186 #define ROT_SAL 0x8
188 #define BTX_BT 0x0
189 #define BTX_BTS 0x1
190 #define BTX_BTR 0x2
191 #define BTX_BTC 0x3
192 #define BTX_BTEXT 0x4
194 #define OP_SIZE_1 0
195 #define OP_SIZE_2 1
196 #define OP_SIZE_4 2
197 #define OP_SIZE_8 3
198 #define OP_SIZE_16 4
199 #define OP_SIZE_10 7
201 #define MOV_MASK_0_16 0x0
202 #define MOV_MASK_16_32 0x1
203 #define MOV_MASK_32_48 0x2
204 #define MOV_MASK_48_64 0x3
205 #define MOV_MASK_0_8 0x4
206 #define MOV_MASK_32_64 0x5
207 #define MOV_MASK_52_64 0x6
209 #define JMP_SHORTEST 0x0000
210 #define JMP_SHORT 0x0001
211 #define JMP_LONG 0x0002
212 #define JMP_EXTRA_LONG 0x0003
214 enum {
215 INSN_ENTRY,
216 INSN_LABEL,
217 INSN_RET,
218 INSN_RET_IMM,
219 INSN_ARM_PUSH,
220 INSN_ARM_POP,
221 INSN_S390_PUSH,
222 INSN_S390_POP,
223 INSN_IA64_ALLOC,
224 INSN_IA64_DEALLOC,
225 INSN_PUSH,
226 INSN_POP,
227 INSN_CALL,
228 INSN_CALL_INDIRECT,
229 INSN_MOV,
230 INSN_MOVSX,
231 INSN_MOV_U,
232 INSN_MOV_LR,
233 INSN_CMP,
234 INSN_CMP_DEST_REG,
235 INSN_CMN,
236 INSN_TEST,
237 INSN_TEST_DEST_REG,
238 INSN_ALU,
239 INSN_ALU_PARTIAL,
240 INSN_ALU_FLAGS,
241 INSN_ALU_FLAGS_PARTIAL,
242 INSN_ALU_TRAP,
243 INSN_ALU_FLAGS_TRAP,
244 INSN_ALU1,
245 INSN_ALU1_PARTIAL,
246 INSN_ALU1_FLAGS,
247 INSN_ALU1_FLAGS_PARTIAL,
248 INSN_ALU1_TRAP,
249 INSN_LEA3,
250 INSN_ROT,
251 INSN_ROT_PARTIAL,
252 INSN_BT,
253 INSN_BTX,
254 INSN_MUL_L,
255 INSN_DIV_L,
256 INSN_MADD,
257 INSN_CBW,
258 INSN_CBW_PARTIAL,
259 INSN_CWD,
260 INSN_CWD_PARTIAL,
261 INSN_SET_COND,
262 INSN_SET_COND_PARTIAL,
263 INSN_CMOV,
264 INSN_CMOV_XCC,
265 INSN_CMP_CMOV,
266 INSN_MOVR,
267 INSN_CSEL_SEL,
268 INSN_CSEL_INC,
269 INSN_CSEL_INV,
270 INSN_CSEL_NEG,
271 INSN_STP,
272 INSN_LDP,
273 INSN_MOV_MASK,
274 INSN_MEMCPY,
275 INSN_MEMSET,
276 INSN_FP_CMP,
277 INSN_FP_CMP_DEST_REG,
278 INSN_FP_CMP_DEST_REG_TRAP,
279 INSN_FP_CMP_UNORDERED_DEST_REG,
280 INSN_FP_CMP_COND,
281 INSN_FP_TEST_REG,
282 INSN_FP_TO_INT_FLAGS,
283 INSN_FP_ALU,
284 INSN_FP_ALU1,
285 INSN_FP_TO_INT32,
286 INSN_FP_TO_INT64,
287 INSN_FP_TO_INT64_TRAP,
288 INSN_FP_FROM_INT32,
289 INSN_FP_FROM_INT64,
290 INSN_FP_INT64_TO_INT32_TRAP,
291 INSN_FP_CVT,
292 INSN_X87_FLD,
293 INSN_X87_FILD,
294 INSN_X87_FSTP,
295 INSN_X87_FISTP,
296 INSN_X87_FISTTP,
297 INSN_X87_FCOMP,
298 INSN_X87_FCOMPP,
299 INSN_X87_FCOMIP,
300 INSN_X87_ALU,
301 INSN_X87_ALUP,
302 INSN_X87_FCHS,
303 INSN_X87_FSQRT,
304 INSN_X87_FRNDINT,
305 INSN_X87_FNSTSW,
306 INSN_X87_FLDCW,
307 INSN_JMP,
308 INSN_JMP_COND,
309 INSN_JMP_COND_LOGICAL,
310 INSN_JMP_REG,
311 INSN_JMP_REG_BIT,
312 INSN_JMP_2REGS,
313 INSN_JMP_FP_TEST,
314 INSN_JMP_INDIRECT,
315 INSN_MB,
316 INSN_CALL_MILLICODE,
319 #define ARG_REGS_MAX 0xc0
320 #define ARG_SHIFTED_REGISTER 0xc0
321 #define ARG_SHIFT_AMOUNT 0x3f
322 #define ARG_SHIFT_MODE 0xc0
323 #define ARG_SHIFT_LSL 0x00
324 #define ARG_SHIFT_LSR 0x40
325 #define ARG_SHIFT_ASR 0x80
326 #define ARG_SHIFT_ROR 0xc0
327 #define ARG_EXTENDED_REGISTER 0xc1
328 #define ARG_EXTEND_SHIFT 0x07
329 #define ARG_EXTEND_MODE 0x38
330 #define ARG_EXTEND_UXTB 0x00
331 #define ARG_EXTEND_UXTH 0x08
332 #define ARG_EXTEND_UXTW 0x10
333 #define ARG_EXTEND_UXTX 0x18
334 #define ARG_EXTEND_SXTB 0x20
335 #define ARG_EXTEND_SXTH 0x28
336 #define ARG_EXTEND_SXTW 0x30
337 #define ARG_EXTEND_SXTX 0x38
338 #define ARG_ADDRESS_0 0xd0
339 #define ARG_ADDRESS_1 0xd1
340 #define ARG_ADDRESS_1_2 0xd2
341 #define ARG_ADDRESS_1_4 0xd3
342 #define ARG_ADDRESS_1_8 0xd4
343 #define ARG_ADDRESS_1_PRE_I 0xd5
344 #define ARG_ADDRESS_1_POST_I 0xd6
345 #define ARG_ADDRESS_2 0xd7
346 #define ARG_ADDRESS_2_2 0xd8
347 #define ARG_ADDRESS_2_4 0xd9
348 #define ARG_ADDRESS_2_8 0xda
349 #define ARG_ADDRESS_2_UXTW 0xdb
350 #define ARG_ADDRESS_2_SXTW 0xdc
351 #define ARG_IMM 0xe0
353 #define ARG_IS_ADDRESS(a) ((a) >= ARG_ADDRESS_0 && (a) <= ARG_ADDRESS_2_SXTW)
355 #ifdef POINTER_COMPRESSION
356 #define OP_SIZE_SLOT OP_SIZE_4
357 #else
358 #define OP_SIZE_SLOT OP_SIZE_ADDRESS
359 #endif
361 #define OP_SIZE_BITMAP (bitmap_64bit ? OP_SIZE_8 : OP_SIZE_4)
363 #define OP_SIZE_INT log_2(sizeof(int_default_t))
365 #define check_insn(insn) \
366 do { \
367 /*if ((insn_opcode(insn) == INSN_ALU || insn_opcode(insn) == INSN_ALU1) && insn_op_size(insn) != OP_SIZE_NATIVE) internal(file_line, "invalid insn %08x", (unsigned)(insn));*/\
368 /*if (insn == 0x001a000e) internal(file_line, "invalid insn %08x", insn);*/\
369 } while (0)
371 #ifdef DEBUG_INSNS
372 #define gen_line() gen_four(__LINE__)
373 #else
374 #define gen_line() do { } while (0)
375 #endif
377 #ifdef ARCH_IA64
378 #define ARCH_CONTEXT struct { \
379 uint64_t insns[3]; \
380 uint8_t insn_units[3]; \
381 bool insn_stops[3]; \
382 uint64_t wr_mask[4]; \
384 #endif
386 #define gen_insn(opcode, op_size, aux, writes_flags) \
387 do { \
388 uint32_t dword = \
389 (uint32_t)(opcode) << INSN_OPCODE_SHIFT | \
390 (uint32_t)(op_size) << INSN_OP_SIZE_SHIFT | \
391 (uint32_t)(aux) << INSN_AUX_SHIFT | \
392 (uint32_t)(writes_flags) << INSN_WRITES_FLAGS_SHIFT; \
393 check_insn(dword); \
394 gen_line(); \
395 gen_four(dword); \
396 } while (0)
398 static size_t arg_size(uint8_t arg)
400 if (arg < ARG_REGS_MAX)
401 return 1;
402 if (arg >= ARG_SHIFTED_REGISTER && arg <= ARG_EXTENDED_REGISTER)
403 return 3;
404 if (arg == ARG_ADDRESS_0)
405 return 9;
406 if (arg >= ARG_ADDRESS_1 && arg <= ARG_ADDRESS_1_POST_I)
407 return 10;
408 if (arg >= ARG_ADDRESS_2 && arg <= ARG_ADDRESS_2_SXTW)
409 return 11;
410 if (arg == ARG_IMM)
411 return 9;
412 internal(file_line, "arg_size: invalid argument %02x", arg);
413 return 0;
416 struct relocation {
417 uint32_t label_id;
418 uint8_t length;
419 size_t position;
420 size_t jmp_instr;
423 struct code_arg {
424 frame_t slot;
425 frame_t flags;
426 frame_t type;
429 struct cg_entry {
430 size_t entry_to_pos;
431 frame_t *variables;
432 size_t n_variables;
433 uint32_t entry_label;
434 uint32_t nonflat_label;
437 struct cg_exit {
438 uint32_t undo_label;
439 uint8_t undo_opcode;
440 uint8_t undo_op_size;
441 uint8_t undo_aux;
442 uint8_t undo_writes_flags;
443 uint8_t undo_parameters[35];
444 uint8_t undo_parameters_len;
445 uint32_t escape_label;
448 #define FLAG_CACHE_IS_FLAT 0x01
449 #define FLAG_CACHE_IS_NOT_FLAT 0x02
450 #define FLAG_CACHE_IS_NOT_THUNK 0x04
452 struct codegen_context {
453 struct data *fn;
454 struct data **local_directory;
456 const code_t *instr_start;
457 const code_t *current_position;
458 uchar_efficient_t arg_mode;
460 uint32_t label_id;
461 struct cg_entry *entries;
462 frame_t n_entries;
464 uint8_t *code;
465 size_t code_size;
467 uint8_t *code_position;
469 uint32_t *code_labels;
470 struct cg_exit **code_exits;
471 uint32_t escape_nospill_label;
472 uint32_t call_label;
473 uint32_t reload_label;
475 uint8_t *mcode;
476 size_t mcode_size;
478 size_t *label_to_pos;
479 struct relocation *reloc;
480 size_t reloc_size;
482 struct trap_record *trap_records;
483 size_t trap_records_size;
485 struct code_arg *args;
486 size_t args_l;
487 const code_t *return_values;
489 uint8_t *flag_cache;
490 short *registers;
491 frame_t *need_spill;
492 size_t need_spill_l;
494 unsigned base_reg;
495 bool offset_reg;
496 int64_t offset_imm;
498 bool const_reg;
499 int64_t const_imm;
501 struct data *codegen;
503 int upcall_args;
504 frame_t *var_aux;
506 ajla_error_t err;
508 #ifdef ARCH_CONTEXT
509 ARCH_CONTEXT a;
510 #endif
513 static void init_ctx(struct codegen_context *ctx)
515 ctx->local_directory = NULL;
516 ctx->label_id = 0;
517 ctx->entries = NULL;
518 ctx->n_entries = 0;
519 ctx->code = NULL;
520 ctx->code_labels = NULL;
521 ctx->code_exits = NULL;
522 ctx->escape_nospill_label = 0;
523 ctx->call_label = 0;
524 ctx->reload_label = 0;
525 ctx->mcode = NULL;
526 ctx->label_to_pos = NULL;
527 ctx->reloc = NULL;
528 ctx->trap_records = NULL;
529 ctx->args = NULL;
530 ctx->flag_cache = NULL;
531 ctx->registers = NULL;
532 ctx->need_spill = NULL;
533 ctx->codegen = NULL;
534 ctx->upcall_args = -1;
535 ctx->var_aux = NULL;
538 static void done_ctx(struct codegen_context *ctx)
540 if (ctx->local_directory)
541 mem_free(ctx->local_directory);
542 if (ctx->entries) {
543 size_t i;
544 for (i = 0; i < ctx->n_entries; i++) {
545 struct cg_entry *ce = &ctx->entries[i];
546 if (ce->variables)
547 mem_free(ce->variables);
549 mem_free(ctx->entries);
551 if (ctx->code)
552 mem_free(ctx->code);
553 if (ctx->code_labels)
554 mem_free(ctx->code_labels);
555 if (ctx->code_exits) {
556 ip_t ip;
557 ip_t cs = da(ctx->fn,function)->code_size;
558 for (ip = 0; ip < cs; ip++) {
559 if (ctx->code_exits[ip])
560 mem_free(ctx->code_exits[ip]);
562 mem_free(ctx->code_exits);
564 if (ctx->mcode)
565 mem_free(ctx->mcode);
566 if (ctx->label_to_pos)
567 mem_free(ctx->label_to_pos);
568 if (ctx->reloc)
569 mem_free(ctx->reloc);
570 if (ctx->trap_records)
571 mem_free(ctx->trap_records);
572 if (ctx->args)
573 mem_free(ctx->args);
574 if (ctx->flag_cache)
575 mem_free(ctx->flag_cache);
576 if (ctx->registers)
577 mem_free(ctx->registers);
578 if (ctx->need_spill)
579 mem_free(ctx->need_spill);
580 if (ctx->codegen)
581 data_free(ctx->codegen);
582 if (ctx->var_aux)
583 mem_free(ctx->var_aux);
587 static inline code_t get_code(struct codegen_context *ctx)
589 ajla_assert(ctx->current_position < da(ctx->fn,function)->code + da(ctx->fn,function)->code_size, (file_line, "get_code: ran out of code"));
590 return *ctx->current_position++;
593 static inline uint32_t get_uint32(struct codegen_context *ctx)
595 uint32_t a1 = get_code(ctx);
596 uint32_t a2 = get_code(ctx);
597 #if !CODE_ENDIAN
598 return a1 + (a2 << 16);
599 #else
600 return a2 + (a1 << 16);
601 #endif
604 static int32_t get_jump_offset(struct codegen_context *ctx)
606 if (SIZEOF_IP_T == 2) {
607 return (int32_t)(int16_t)get_code(ctx);
608 } else if (SIZEOF_IP_T == 4) {
609 return (int32_t)get_uint32(ctx);
610 } else {
611 not_reached();
612 return -1;
616 static inline void get_one(struct codegen_context *ctx, frame_t *v)
618 if (!ctx->arg_mode) {
619 code_t c = get_code(ctx);
620 ajla_assert(!(c & ~0xff), (file_line, "get_one: high byte is not cleared: %u", (unsigned)c));
621 *v = c & 0xff;
622 } else if (ctx->arg_mode == 1) {
623 *v = get_code(ctx);
624 #if ARG_MODE_N >= 2
625 } else if (ctx->arg_mode == 2) {
626 *v = get_uint32(ctx);
627 #endif
628 } else {
629 internal(file_line, "get_one: invalid arg mode %u", ctx->arg_mode);
633 static inline void get_two(struct codegen_context *ctx, frame_t *v1, frame_t *v2)
635 if (!ctx->arg_mode) {
636 code_t c = get_code(ctx);
637 *v1 = c & 0xff;
638 *v2 = c >> 8;
639 } else if (ctx->arg_mode == 1) {
640 *v1 = get_code(ctx);
641 *v2 = get_code(ctx);
642 #if ARG_MODE_N >= 2
643 } else if (ctx->arg_mode == 2) {
644 *v1 = get_uint32(ctx);
645 *v2 = get_uint32(ctx);
646 #endif
647 } else {
648 internal(file_line, "get_two: invalid arg mode %u", ctx->arg_mode);
653 static uint32_t alloc_label(struct codegen_context *ctx)
655 return ++ctx->label_id;
658 static struct cg_exit *alloc_cg_exit_for_ip(struct codegen_context *ctx, const code_t *code)
660 ip_t ip = code - da(ctx->fn,function)->code;
661 struct cg_exit *ce = ctx->code_exits[ip];
662 if (!ce) {
663 ce = mem_calloc_mayfail(struct cg_exit *, sizeof(struct cg_exit), &ctx->err);
664 if (unlikely(!ce))
665 return NULL;
666 ctx->code_exits[ip] = ce;
668 return ce;
671 static struct cg_exit *alloc_undo_label(struct codegen_context *ctx)
673 struct cg_exit *ce = alloc_cg_exit_for_ip(ctx, ctx->instr_start);
674 if (unlikely(!ce))
675 return NULL;
676 if (unlikely(ce->undo_label != 0))
677 internal(file_line, "alloc_cg_exit: undo label already allocated");
678 ce->undo_label = alloc_label(ctx);
679 if (unlikely(!ce->undo_label))
680 return NULL;
681 return ce;
684 static uint32_t alloc_escape_label_for_ip(struct codegen_context *ctx, const code_t *code)
686 struct cg_exit *ce = alloc_cg_exit_for_ip(ctx, code);
687 if (!ce)
688 return 0;
689 if (!ce->escape_label)
690 ce->escape_label = alloc_label(ctx);
691 return ce->escape_label;
694 static uint32_t alloc_escape_label(struct codegen_context *ctx)
696 return alloc_escape_label_for_ip(ctx, ctx->instr_start);
699 static uint32_t attr_unused alloc_call_label(struct codegen_context *ctx)
701 if (!ctx->call_label) {
702 ctx->call_label = alloc_label(ctx);
704 return ctx->call_label;
707 static uint32_t alloc_reload_label(struct codegen_context *ctx)
709 if (!ctx->reload_label) {
710 ctx->reload_label = alloc_label(ctx);
712 return ctx->reload_label;
715 static size_t attr_unused mark_params(struct codegen_context *ctx)
717 return ctx->code_size;
720 static void attr_unused copy_params(struct codegen_context *ctx, struct cg_exit *ce, size_t mark)
722 if (ctx->code_size - mark > n_array_elements(ce->undo_parameters))
723 internal(file_line, "undo_parameters is too small: %"PRIuMAX" > %"PRIuMAX"", (uintmax_t)(ctx->code_size - mark), (uintmax_t)n_array_elements(ce->undo_parameters));
724 memcpy(ce->undo_parameters, ctx->code + mark, ctx->code_size - mark);
725 ce->undo_parameters_len = ctx->code_size - mark;
726 ctx->code_size = mark;
729 #define g(call) \
730 do { \
731 if (unlikely(!call)) \
732 return false; \
733 } while (0)
735 #define gen_one(byte) \
736 do { \
737 /*debug("gen %d: %02x", __LINE__, (uint8_t)(byte))*/; \
738 if (unlikely(!array_add_mayfail(uint8_t, &ctx->code, &ctx->code_size, byte, NULL, &ctx->err)))\
739 return false; \
740 } while (0)
742 #if defined(C_LITTLE_ENDIAN)
743 #define gen_two(word) \
744 do { \
745 uint16_t word_ = (word); \
746 /*debug("gen %d: %04x", __LINE__, (uint16_t)(word_));*/ \
747 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
748 return false; \
749 } while (0)
750 #define gen_four(dword) \
751 do { \
752 uint32_t dword_ = (dword); \
753 /*debug("gen %d: %08x", __LINE__, (uint32_t)(dword_));*/ \
754 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
755 return false; \
756 } while (0)
757 #define gen_eight(qword) \
758 do { \
759 uint64_t qword_ = (qword); \
760 /*debug("gen %d: %016lx", __LINE__, (uint64_t)(qword_));*/ \
761 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
762 return false; \
763 } while (0)
764 #else
765 #define gen_two(word) \
766 do { \
767 uint16_t word_ = (word); \
768 gen_one(word_ & 0xffU); \
769 gen_one(word_ >> 8); \
770 } while (0)
771 #define gen_four(dword) \
772 do { \
773 uint32_t dword_ = (dword); \
774 gen_two(dword_ & 0xffffU); \
775 gen_two(dword_ >> 15 >> 1); \
776 } while (0)
777 #define gen_eight(qword) \
778 do { \
779 uint64_t qword_ = (qword); \
780 gen_four(qword_ & 0xffffffffUL); \
781 gen_four(qword_ >> 15 >> 15 >> 2); \
782 } while (0)
783 #endif
785 #define gen_label(label_id) \
786 do { \
787 gen_insn(INSN_LABEL, 0, 0, 0); \
788 gen_four(label_id); \
789 } while (0)
792 static uint8_t attr_unused cget_one(struct codegen_context *ctx)
794 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_one: ran out of code"));
795 return *ctx->code_position++;
798 static uint16_t attr_unused cget_two(struct codegen_context *ctx)
800 #if defined(C_LITTLE_ENDIAN)
801 uint16_t r;
802 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_two: ran out of code"));
803 memcpy(&r, ctx->code_position, 2);
804 ctx->code_position += 2;
805 return r;
806 #else
807 uint16_t r = cget_one(ctx);
808 r |= cget_one(ctx) << 8;
809 return r;
810 #endif
813 static uint32_t cget_four(struct codegen_context *ctx)
815 #if defined(C_LITTLE_ENDIAN)
816 uint32_t r;
817 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_four: ran out of code"));
818 memcpy(&r, ctx->code_position, 4);
819 ctx->code_position += 4;
820 return r;
821 #else
822 uint32_t r = cget_two(ctx);
823 r |= (uint32_t)cget_two(ctx) << 16;
824 return r;
825 #endif
828 static uint64_t attr_unused cget_eight(struct codegen_context *ctx)
830 #if defined(C_LITTLE_ENDIAN)
831 uint64_t r;
832 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_eight: ran out of code"));
833 memcpy(&r, ctx->code_position, 8);
834 ctx->code_position += 8;
835 return r;
836 #else
837 uint64_t r = cget_four(ctx);
838 r |= (uint64_t)cget_four(ctx) << 32;
839 return r;
840 #endif
843 static int64_t get_imm(uint8_t *ptr)
845 #if defined(C_LITTLE_ENDIAN)
846 int64_t r;
847 memcpy(&r, ptr, 8);
848 return r;
849 #else
850 int64_t r;
851 r = (uint64_t)ptr[0] |
852 ((uint64_t)ptr[1] << 8) |
853 ((uint64_t)ptr[2] << 16) |
854 ((uint64_t)ptr[3] << 24) |
855 ((uint64_t)ptr[4] << 32) |
856 ((uint64_t)ptr[5] << 40) |
857 ((uint64_t)ptr[6] << 48) |
858 ((uint64_t)ptr[7] << 56);
859 return r;
860 #endif
863 #define cgen_one(byte) \
864 do { \
865 if (unlikely(!array_add_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, byte, NULL, &ctx->err)))\
866 return false; \
867 } while (0)
869 #if defined(C_LITTLE_ENDIAN) || 1
870 #define cgen_two(word) \
871 do { \
872 uint16_t word_ = (word); \
873 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
874 return false; \
875 } while (0)
876 #define cgen_four(dword) \
877 do { \
878 uint32_t dword_ = (dword); \
879 /*if (dword_ == 0x1ee02000) internal(file_line, "invalid instruction");*/\
880 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
881 return false; \
882 } while (0)
883 #define cgen_eight(qword) \
884 do { \
885 uint64_t qword_ = (qword); \
886 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
887 return false; \
888 } while (0)
889 #else
890 #define cgen_two(word) \
891 do { \
892 cgen_one((word) & 0xff); \
893 cgen_one((word) >> 8); \
894 } while (0)
895 #define cgen_four(dword) \
896 do { \
897 cgen_two((dword) & 0xffff); \
898 cgen_two((dword) >> 15 >> 1); \
899 } while (0)
900 #define cgen_eight(qword) \
901 do { \
902 cgen_four((qword) & 0xffffffff); \
903 cgen_four((qword) >> 15 >> 15 >> 2); \
904 } while (0)
905 #endif
908 #define IMM_PURPOSE_LDR_OFFSET 1
909 #define IMM_PURPOSE_LDR_SX_OFFSET 2
910 #define IMM_PURPOSE_STR_OFFSET 3
911 #define IMM_PURPOSE_LDP_STP_OFFSET 4
912 #define IMM_PURPOSE_VLDR_VSTR_OFFSET 5
913 #define IMM_PURPOSE_MVI_CLI_OFFSET 6
914 #define IMM_PURPOSE_STORE_VALUE 7
915 #define IMM_PURPOSE_ADD 8
916 #define IMM_PURPOSE_SUB 9
917 #define IMM_PURPOSE_CMP 10
918 #define IMM_PURPOSE_CMP_LOGICAL 11
919 #define IMM_PURPOSE_AND 12
920 #define IMM_PURPOSE_OR 13
921 #define IMM_PURPOSE_XOR 14
922 #define IMM_PURPOSE_ANDN 15
923 #define IMM_PURPOSE_TEST 16
924 #define IMM_PURPOSE_JMP_2REGS 17
925 #define IMM_PURPOSE_MUL 18
926 #define IMM_PURPOSE_CMOV 19
927 #define IMM_PURPOSE_MOVR 20
928 #define IMM_PURPOSE_BITWISE 21
931 static bool attr_w gen_upcall_end(struct codegen_context *ctx, unsigned args);
933 #define gen_address_offset() \
934 do { \
935 if (likely(!ctx->offset_reg)) { \
936 gen_one(ARG_ADDRESS_1); \
937 gen_one(ctx->base_reg); \
938 gen_eight(ctx->offset_imm); \
939 } else { \
940 gen_one(ARG_ADDRESS_2); \
941 gen_one(ctx->base_reg); \
942 gen_one(R_OFFSET_IMM); \
943 gen_eight(0); \
945 } while (0)
947 #define gen_imm_offset() \
948 do { \
949 if (likely(!ctx->const_reg)) { \
950 gen_one(ARG_IMM); \
951 gen_eight(ctx->const_imm); \
952 } else { \
953 gen_one(R_CONST_IMM); \
955 } while (0)
957 #define is_imm() (!ctx->const_reg)
960 #if defined(ARCH_ALPHA)
961 #include "c1-alpha.inc"
962 #elif defined(ARCH_ARM32)
963 #include "c1-arm.inc"
964 #elif defined(ARCH_ARM64)
965 #include "c1-arm64.inc"
966 #elif defined(ARCH_IA64)
967 #include "c1-ia64.inc"
968 #elif defined(ARCH_LOONGARCH64)
969 #include "c1-loong.inc"
970 #elif defined(ARCH_MIPS)
971 #include "c1-mips.inc"
972 #elif defined(ARCH_PARISC)
973 #include "c1-hppa.inc"
974 #elif defined(ARCH_POWER)
975 #include "c1-power.inc"
976 #elif defined(ARCH_S390)
977 #include "c1-s390.inc"
978 #elif defined(ARCH_SPARC)
979 #include "c1-sparc.inc"
980 #elif defined(ARCH_RISCV64)
981 #include "c1-riscv.inc"
982 #elif defined(ARCH_X86)
983 #include "c1-x86.inc"
984 #endif
987 #ifndef ARCH_SUPPORTS_TRAPS
988 #define ARCH_SUPPORTS_TRAPS 0
989 #define ARCH_TRAP_BEFORE 0
990 #endif
993 #include "cg-util.inc"
995 #include "cg-frame.inc"
997 #include "cg-flags.inc"
999 #include "cg-flcch.inc"
1001 #include "cg-ptr.inc"
1003 #include "cg-alu.inc"
1005 #include "cg-ops.inc"
1008 #ifndef n_regs_saved
1009 #define n_regs_saved n_array_elements(regs_saved)
1010 #endif
1012 #ifndef n_regs_volatile
1013 #define n_regs_volatile n_array_elements(regs_volatile)
1014 #endif
1016 #ifndef n_fp_saved
1017 #define n_fp_saved n_array_elements(fp_saved)
1018 #endif
1020 #ifndef n_fp_volatile
1021 #define n_fp_volatile n_array_elements(fp_volatile)
1022 #endif
1024 #ifndef n_vector_volatile
1025 #define n_vector_volatile n_array_elements(vector_volatile)
1026 #endif
1028 static bool attr_w gen_registers(struct codegen_context *ctx)
1030 frame_t v;
1031 size_t index_saved = 0;
1032 size_t index_volatile = 0;
1033 size_t index_fp_saved = 0;
1034 size_t index_fp_volatile = 0;
1035 size_t attr_unused index_vector_volatile = 0;
1036 #ifdef ARCH_S390
1037 bool uses_x = false;
1038 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
1039 const struct type *t = get_type_of_local(ctx, v);
1040 if (t && TYPE_TAG_IS_REAL(t->tag) && TYPE_TAG_IDX_REAL(t->tag) == 4) {
1041 uses_x = true;
1042 break;
1045 #endif
1046 /*for (v = function_n_variables(ctx->fn) - 1; v >= MIN_USEABLE_SLOT; v--)*/
1047 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
1048 const struct type *t;
1049 ctx->registers[v] = -1;
1050 if (ra_chicken)
1051 continue;
1052 t = get_type_of_local(ctx, v);
1053 if (unlikely(!t))
1054 continue;
1055 if (!da(ctx->fn,function)->local_variables_flags[v].must_be_flat)
1056 continue;
1057 if (!ARCH_HAS_BWX && t->size < 1U << OP_SIZE_4)
1058 continue;
1059 if (TYPE_TAG_IS_FIXED(t->tag) || TYPE_TAG_IS_INT(t->tag) || t->tag == TYPE_TAG_flat_option) {
1060 if (!is_power_of_2(t->size) || t->size > 1U << OP_SIZE_NATIVE)
1061 continue;
1062 if (index_saved < n_regs_saved + zero
1063 #if defined(ARCH_PARISC) || defined(ARCH_SPARC)
1064 && t->size <= 1U << OP_SIZE_ADDRESS
1065 #endif
1067 ctx->registers[v] = regs_saved[index_saved++];
1068 } else if (index_volatile < n_regs_volatile + zero) {
1069 ctx->registers[v] = regs_volatile[index_volatile++];
1070 } else {
1071 continue;
1073 } else if (TYPE_TAG_IS_REAL(t->tag)) {
1074 unsigned real_type = TYPE_TAG_IDX_REAL(t->tag);
1075 if ((SUPPORTED_FP >> real_type) & 1) {
1076 #ifdef ARCH_POWER
1077 if (real_type == 4) {
1078 if (index_vector_volatile < n_vector_volatile + zero) {
1079 ctx->registers[v] = vector_volatile[index_vector_volatile++];
1080 goto success;
1082 continue;
1084 #endif
1085 #ifdef ARCH_S390
1086 if (real_type == 4) {
1087 if (!(index_fp_saved & 1) && index_fp_saved + 1 < n_fp_saved + zero) {
1088 ctx->registers[v] = fp_saved[index_fp_saved++];
1089 index_fp_saved++;
1090 goto success;
1092 if (index_fp_saved & 1 && index_fp_saved + 2 < n_fp_saved + zero) {
1093 index_fp_saved++;
1094 ctx->registers[v] = fp_saved[index_fp_saved++];
1095 index_fp_saved++;
1096 goto success;
1098 if (!(index_fp_volatile & 1) && index_fp_volatile + 1 < n_fp_volatile + zero) {
1099 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1100 index_fp_volatile++;
1101 goto success;
1103 if (index_fp_volatile & 1 && index_fp_volatile + 2 < n_fp_volatile + zero) {
1104 index_fp_volatile++;
1105 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1106 index_fp_volatile++;
1107 goto success;
1109 continue;
1111 #endif
1112 if (index_fp_saved < n_fp_saved + zero) {
1113 ctx->registers[v] = fp_saved[index_fp_saved++];
1114 } else if (index_fp_volatile < n_fp_volatile + zero) {
1115 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1116 } else {
1117 continue;
1119 } else {
1120 continue;
1122 } else {
1123 continue;
1125 goto success;
1126 success:
1127 if (!reg_is_saved(ctx->registers[v])) {
1128 if (unlikely(!array_add_mayfail(frame_t, &ctx->need_spill, &ctx->need_spill_l, v, NULL, &ctx->err)))
1129 return false;
1133 return true;
1136 static bool attr_w gen_fused_binary(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, uint32_t escape_label, frame_t slot_1, frame_t slot_2, frame_t slot_r, bool *failed)
1138 const code_t *backup = ctx->current_position;
1139 code_t code;
1140 frame_t slot_dr, slot_test;
1141 int32_t offs_false;
1143 *failed = false;
1145 next_code:
1146 code = get_code(ctx);
1147 ctx->arg_mode = code / OPCODE_MODE_MULT;
1148 code %= OPCODE_MODE_MULT;
1149 ajla_assert_lo(ctx->arg_mode < ARG_MODE_N, (file_line, "gen_fused_binary: invalid opcode %04x", (unsigned)*ctx->instr_start));
1151 if (code == OPCODE_DEREFERENCE) {
1152 get_one(ctx, &slot_dr);
1153 const struct type *t = get_type_of_local(ctx, slot_dr);
1154 if (!TYPE_TAG_IS_BUILTIN(t->tag)) {
1155 *failed = true;
1156 goto fail;
1158 if (unlikely(!flag_is_clear(ctx, slot_dr))) {
1159 *failed = true;
1160 goto fail;
1162 goto next_code;
1164 if (code == OPCODE_DEREFERENCE_CLEAR) {
1165 *failed = true;
1166 goto fail;
1168 if (unlikely(code != OPCODE_JMP_FALSE))
1169 internal(file_line, "gen_fused_binary: binary operation is not followed by jmp false: %x, %s", code, decode_opcode(code, true));
1170 get_one(ctx, &slot_test);
1171 if (unlikely(slot_test != slot_r))
1172 internal(file_line, "gen_fused_binary: the result of the binary operation and the tested variable do not match");
1173 offs_false = get_jump_offset(ctx);
1174 get_jump_offset(ctx);
1176 if (mode == MODE_ARRAY_LEN_GT) {
1177 g(gen_array_len(ctx, slot_1, slot_2, slot_r, true, offs_false));
1178 } else if (mode == MODE_REAL) {
1179 g(gen_fp_alu_jmp(ctx, op_size, op, escape_label, slot_1, slot_2, offs_false, failed));
1180 } else {
1181 g(gen_alu_jmp(ctx, mode, op_size, op, slot_1, slot_2, offs_false, failed));
1184 fail:
1185 if (*failed)
1186 ctx->current_position = backup;
1188 return true;
1191 static bool attr_w gen_function(struct codegen_context *ctx)
1193 ctx->current_position = da(ctx->fn,function)->code;
1195 ctx->escape_nospill_label = alloc_label(ctx);
1196 if (unlikely(!ctx->escape_nospill_label))
1197 return false;
1199 while (ctx->current_position != da(ctx->fn,function)->code + da(ctx->fn,function)->code_size) {
1200 ip_t ip;
1201 code_t code;
1202 unsigned op, type;
1203 frame_t slot_1, slot_2, slot_3, slot_r, flags, fn_idx, opt;
1204 arg_t n_args, n_ret, i_arg;
1205 uint32_t label_id;
1206 uint32_t escape_label;
1207 bool failed;
1209 ajla_assert_lo(ctx->current_position < da(ctx->fn,function)->code + da(ctx->fn,function)->code_size, (file_line, "gen_function: ran out of code in %s", da(ctx->fn,function)->function_name));
1211 ctx->instr_start = ctx->current_position;
1213 /*debug("%s: %04x, %s", da(ctx->fn,function)->function_name, *ctx->instr_start, decode_opcode(*ctx->instr_start, true));*/
1215 ip = ctx->instr_start - da(ctx->fn,function)->code;
1216 if (likely(!ctx->code_labels[ip])) {
1217 ctx->code_labels[ip] = alloc_label(ctx);
1218 if (unlikely(!ctx->code_labels[ip]))
1219 return false;
1221 gen_label(ctx->code_labels[ip]);
1223 code = get_code(ctx);
1224 ctx->arg_mode = code / OPCODE_MODE_MULT;
1225 code %= OPCODE_MODE_MULT;
1226 ajla_assert_lo(ctx->arg_mode < ARG_MODE_N, (file_line, "gen_function: invalid opcode %04x", (unsigned)*ctx->instr_start));
1228 if (code >= OPCODE_FIXED_OP + uzero && code < OPCODE_INT_OP) {
1229 code -= OPCODE_FIXED_OP;
1230 op = (code / OPCODE_FIXED_OP_MULT) % OPCODE_FIXED_TYPE_MULT;
1231 type = code / OPCODE_FIXED_TYPE_MULT;
1232 if (op < OPCODE_FIXED_OP_UNARY) {
1233 get_two(ctx, &slot_1, &slot_2);
1234 get_two(ctx, &slot_r, &flags);
1235 escape_label = alloc_escape_label(ctx);
1236 if (unlikely(!escape_label))
1237 return false;
1238 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1239 flag_set(ctx, slot_1, false);
1240 flag_set(ctx, slot_2, false);
1241 flag_set(ctx, slot_r, false);
1242 if (flags & OPCODE_FLAG_FUSED) {
1243 g(gen_fused_binary(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1244 if (unlikely(!failed))
1245 continue;
1247 g(gen_alu(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_2, slot_r));
1248 continue;
1249 } else if (op < OPCODE_FIXED_OP_N) {
1250 get_two(ctx, &slot_1, &slot_r);
1251 get_one(ctx, &flags);
1252 escape_label = alloc_escape_label(ctx);
1253 if (unlikely(!escape_label))
1254 return false;
1255 g(gen_test_1_cached(ctx, slot_1, escape_label));
1256 flag_set(ctx, slot_1, false);
1257 flag_set(ctx, slot_r, false);
1258 g(gen_alu1(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_r));
1259 continue;
1260 } else if (op == OPCODE_FIXED_OP_ldc) {
1261 unsigned i;
1262 get_one(ctx, &slot_r);
1263 g(gen_constant(ctx, false, type, false, slot_r));
1264 for (i = 0; i < 1U << type; i += 2)
1265 get_code(ctx);
1266 flag_set(ctx, slot_r, false);
1267 continue;
1268 } else if (op == OPCODE_FIXED_OP_ldc16) {
1269 get_one(ctx, &slot_r);
1270 g(gen_constant(ctx, false, type, true, slot_r));
1271 get_code(ctx);
1272 flag_set(ctx, slot_r, false);
1273 continue;
1274 } else if (op == OPCODE_FIXED_OP_move || op == OPCODE_FIXED_OP_copy) {
1275 get_two(ctx, &slot_1, &slot_r);
1276 escape_label = alloc_escape_label(ctx);
1277 if (unlikely(!escape_label))
1278 return false;
1279 g(gen_test_1_cached(ctx, slot_1, escape_label));
1280 flag_set(ctx, slot_1, false);
1281 flag_set(ctx, slot_r, false);
1282 g(gen_copy(ctx, type, slot_1, slot_r));
1283 continue;
1284 } else {
1285 internal(file_line, "gen_function: bad fixed code %04x", *ctx->instr_start);
1287 } else if (code >= OPCODE_INT_OP && code < OPCODE_REAL_OP) {
1288 code -= OPCODE_INT_OP;
1289 op = (code / OPCODE_INT_OP_MULT) % OPCODE_INT_TYPE_MULT;
1290 type = code / OPCODE_INT_TYPE_MULT;
1291 if (op < OPCODE_INT_OP_UNARY) {
1292 get_two(ctx, &slot_1, &slot_2);
1293 get_two(ctx, &slot_r, &flags);
1294 escape_label = alloc_escape_label(ctx);
1295 if (unlikely(!escape_label))
1296 return false;
1297 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1298 flag_set(ctx, slot_1, false);
1299 flag_set(ctx, slot_2, false);
1300 flag_set(ctx, slot_r, false);
1301 if (flags & OPCODE_FLAG_FUSED) {
1302 g(gen_fused_binary(ctx, MODE_INT, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1303 if (unlikely(!failed))
1304 continue;
1306 g(gen_alu(ctx, MODE_INT, type, op, escape_label, slot_1, slot_2, slot_r));
1307 continue;
1308 } else if (op < OPCODE_INT_OP_N) {
1309 get_two(ctx, &slot_1, &slot_r);
1310 get_one(ctx, &flags);
1311 if ((op == OPCODE_INT_OP_to_int || op == OPCODE_INT_OP_from_int) && slot_1 == slot_r)
1312 continue;
1313 escape_label = alloc_escape_label(ctx);
1314 if (unlikely(!escape_label))
1315 return false;
1316 g(gen_test_1_cached(ctx, slot_1, escape_label));
1317 flag_set(ctx, slot_1, false);
1318 flag_set(ctx, slot_r, false);
1319 g(gen_alu1(ctx, MODE_INT, type, op, escape_label, slot_1, slot_r));
1320 continue;
1321 } else if (op == OPCODE_INT_OP_ldc) {
1322 unsigned i;
1323 get_one(ctx, &slot_r);
1324 g(gen_constant(ctx, false, type, false, slot_r));
1325 for (i = 0; i < 1U << type; i += 2)
1326 get_code(ctx);
1327 flag_set(ctx, slot_r, false);
1328 continue;
1329 } else if (op == OPCODE_INT_OP_ldc16) {
1330 get_one(ctx, &slot_r);
1331 g(gen_constant(ctx, false, type, true, slot_r));
1332 get_code(ctx);
1333 flag_set(ctx, slot_r, false);
1334 continue;
1335 } else if (op == OPCODE_INT_OP_move || op == OPCODE_INT_OP_copy) {
1336 get_two(ctx, &slot_1, &slot_r);
1337 escape_label = alloc_escape_label(ctx);
1338 if (unlikely(!escape_label))
1339 return false;
1340 g(gen_test_1_cached(ctx, slot_1, escape_label));
1341 flag_set(ctx, slot_1, false);
1342 flag_set(ctx, slot_r, false);
1343 g(gen_copy(ctx, type, slot_1, slot_r));
1344 continue;
1345 } else {
1346 internal(file_line, "gen_function: bad integer code %04x", *ctx->instr_start);
1348 } else if (code >= OPCODE_REAL_OP && code < OPCODE_BOOL_OP) {
1349 code -= OPCODE_REAL_OP;
1350 op = (code / OPCODE_REAL_OP_MULT) % OPCODE_REAL_TYPE_MULT;
1351 type = code / OPCODE_REAL_TYPE_MULT;
1352 if (op < OPCODE_REAL_OP_UNARY) {
1353 get_two(ctx, &slot_1, &slot_2);
1354 get_two(ctx, &slot_r, &flags);
1355 escape_label = alloc_escape_label(ctx);
1356 if (unlikely(!escape_label))
1357 return false;
1358 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1359 flag_set(ctx, slot_1, false);
1360 flag_set(ctx, slot_2, false);
1361 flag_set(ctx, slot_r, false);
1362 if (flags & OPCODE_FLAG_FUSED) {
1363 g(gen_fused_binary(ctx, MODE_REAL, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1364 if (unlikely(!failed))
1365 continue;
1367 g(gen_fp_alu(ctx, type, op, escape_label, slot_1, slot_2, slot_r));
1368 continue;
1369 } else if (op < OPCODE_REAL_OP_N) {
1370 get_two(ctx, &slot_1, &slot_r);
1371 get_one(ctx, &flags);
1372 escape_label = alloc_escape_label(ctx);
1373 if (unlikely(!escape_label))
1374 return false;
1375 g(gen_test_1_cached(ctx, slot_1, escape_label));
1376 flag_set(ctx, slot_1, false);
1377 flag_set(ctx, slot_r, false);
1378 g(gen_fp_alu1(ctx, type, op, escape_label, slot_1, slot_r));
1379 continue;
1380 } else if (op == OPCODE_REAL_OP_ldc) {
1381 const struct type *t;
1382 unsigned i;
1383 get_one(ctx, &slot_r);
1384 t = type_get_real(type);
1385 g(gen_real_constant(ctx, t, slot_r));
1386 for (i = 0; i < t->size; i += 2)
1387 get_code(ctx);
1388 flag_set(ctx, slot_r, false);
1389 continue;
1390 } else if (op == OPCODE_REAL_OP_move || op == OPCODE_REAL_OP_copy) {
1391 get_two(ctx, &slot_1, &slot_r);
1392 escape_label = alloc_escape_label(ctx);
1393 if (unlikely(!escape_label))
1394 return false;
1395 g(gen_test_1_cached(ctx, slot_1, escape_label));
1396 flag_set(ctx, slot_1, false);
1397 flag_set(ctx, slot_r, false);
1398 g(gen_memcpy_slots(ctx, slot_r, slot_1));
1399 continue;
1400 } else {
1401 internal(file_line, "gen_function: bad real code %04x", *ctx->instr_start);
1403 } else if (code >= OPCODE_BOOL_OP && code < OPCODE_EXTRA) {
1404 code -= OPCODE_BOOL_OP;
1405 op = (code / OPCODE_BOOL_OP_MULT) % OPCODE_BOOL_TYPE_MULT;
1406 type = log_2(sizeof(ajla_flat_option_t));
1407 if (op < OPCODE_BOOL_OP_UNARY) {
1408 get_two(ctx, &slot_1, &slot_2);
1409 get_two(ctx, &slot_r, &flags);
1410 escape_label = alloc_escape_label(ctx);
1411 if (unlikely(!escape_label))
1412 return false;
1413 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1414 flag_set(ctx, slot_1, false);
1415 flag_set(ctx, slot_2, false);
1416 flag_set(ctx, slot_r, false);
1417 if (flags & OPCODE_FLAG_FUSED) {
1418 g(gen_fused_binary(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1419 if (unlikely(!failed))
1420 continue;
1422 g(gen_alu(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_2, slot_r));
1423 continue;
1424 } else if (op < OPCODE_BOOL_OP_N) {
1425 get_two(ctx, &slot_1, &slot_r);
1426 get_one(ctx, &flags);
1427 escape_label = alloc_escape_label(ctx);
1428 if (unlikely(!escape_label))
1429 return false;
1430 g(gen_test_1_cached(ctx, slot_1, escape_label));
1431 flag_set(ctx, slot_1, false);
1432 flag_set(ctx, slot_r, false);
1433 g(gen_alu1(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_r));
1434 continue;
1435 } else if (op == OPCODE_BOOL_OP_move || op == OPCODE_BOOL_OP_copy) {
1436 get_two(ctx, &slot_1, &slot_r);
1437 escape_label = alloc_escape_label(ctx);
1438 if (unlikely(!escape_label))
1439 return false;
1440 g(gen_test_1_cached(ctx, slot_1, escape_label));
1441 flag_set(ctx, slot_1, false);
1442 flag_set(ctx, slot_r, false);
1443 g(gen_copy(ctx, type, slot_1, slot_r));
1444 continue;
1445 } else {
1446 internal(file_line, "gen_function: bad boolean code %04x", *ctx->instr_start);
1448 } else switch (code) {
1449 case OPCODE_INT_LDC_LONG: {
1450 uint32_t words, w;
1451 get_one(ctx, &slot_r);
1452 words = get_uint32(ctx);
1453 for (w = 0; w < words; w++)
1454 get_code(ctx);
1455 unconditional_escape:
1456 escape_label = alloc_escape_label(ctx);
1457 if (unlikely(!escape_label))
1458 return false;
1459 gen_insn(INSN_JMP, 0, 0, 0);
1460 gen_four(escape_label);
1461 continue;
1463 case OPCODE_IS_EXCEPTION: {
1464 get_two(ctx, &slot_1, &slot_r);
1465 get_one(ctx, &flags);
1466 g(gen_is_exception(ctx, slot_1, slot_r));
1467 continue;
1469 case OPCODE_EXCEPTION_CLASS:
1470 case OPCODE_EXCEPTION_TYPE:
1471 case OPCODE_EXCEPTION_AUX: {
1472 get_two(ctx, &slot_1, &slot_r);
1473 get_one(ctx, &flags);
1474 goto unconditional_escape;
1476 case OPCODE_SYSTEM_PROPERTY: {
1477 get_two(ctx, &slot_1, &slot_r);
1478 get_one(ctx, &flags);
1479 g(gen_system_property(ctx, slot_1, slot_r));
1480 continue;
1482 case OPCODE_FLAT_MOVE:
1483 case OPCODE_FLAT_COPY: {
1484 get_two(ctx, &slot_1, &slot_r);
1485 g(gen_flat_move_copy(ctx, slot_1, slot_r));
1486 continue;
1488 case OPCODE_REF_MOVE:
1489 case OPCODE_REF_MOVE_CLEAR:
1490 case OPCODE_REF_COPY: {
1491 get_two(ctx, &slot_1, &slot_r);
1492 g(gen_ref_move_copy(ctx, code, slot_1, slot_r));
1493 continue;
1495 case OPCODE_BOX_MOVE_CLEAR:
1496 case OPCODE_BOX_COPY: {
1497 get_two(ctx, &slot_1, &slot_r);
1498 g(gen_box_move_copy(ctx, code, slot_1, slot_r));
1499 continue;
1501 case OPCODE_TAKE_BORROWED:
1502 get_one(ctx, &slot_1);
1503 if (!da(ctx->fn,function)->local_variables_flags[slot_1].may_be_borrowed)
1504 continue;
1505 if (unlikely(!(label_id = alloc_label(ctx))))
1506 return false;
1507 if (flag_is_set(ctx, slot_1))
1508 goto take_borrowed_done;
1509 if (flag_is_clear(ctx, slot_1)) {
1510 g(gen_set_1(ctx, R_FRAME, slot_1, 0, true));
1511 goto do_take_borrowed;
1513 g(gen_test_1(ctx, R_FRAME, slot_1, 0, label_id, false, TEST_SET));
1514 do_take_borrowed:
1515 g(gen_upcall_start(ctx, 1));
1516 g(gen_frame_load(ctx, OP_SIZE_SLOT, garbage, slot_1, 0, R_ARG0));
1517 g(gen_upcall_argument(ctx, 0));
1518 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_pointer_reference_owned), 1));
1519 flag_set(ctx, slot_1, true);
1520 take_borrowed_done:
1521 gen_label(label_id);
1522 continue;
1523 case OPCODE_DEREFERENCE:
1524 case OPCODE_DEREFERENCE_CLEAR: {
1525 bool need_bit_test;
1526 /*const struct type *type;*/
1527 get_one(ctx, &slot_1);
1528 if (flag_is_clear(ctx, slot_1))
1529 goto skip_dereference;
1530 /*type = get_type_of_local(ctx, slot_1);*/
1531 /*need_bit_test = 1 || TYPE_IS_FLAT(type) || da(ctx->fn,function)->local_variables[slot_1].may_be_borrowed;*/
1532 need_bit_test = !flag_is_set(ctx, slot_1);
1533 if (need_bit_test) {
1534 if (unlikely(!(label_id = alloc_label(ctx))))
1535 return false;
1536 g(gen_test_1(ctx, R_FRAME, slot_1, 0, label_id, true, TEST_CLEAR));
1537 } else {
1538 g(gen_set_1(ctx, R_FRAME, slot_1, 0, false));
1539 label_id = 0; /* avoid warning */
1541 g(gen_upcall_start(ctx, 1));
1542 g(gen_frame_load(ctx, OP_SIZE_SLOT, garbage, slot_1, 0, R_ARG0));
1543 g(gen_upcall_argument(ctx, 0));
1544 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_pointer_dereference), 1));
1545 if (need_bit_test)
1546 gen_label(label_id);
1547 skip_dereference:
1548 if (code == OPCODE_DEREFERENCE_CLEAR)
1549 g(gen_frame_clear(ctx, OP_SIZE_SLOT, slot_1));
1550 flag_set_unknown(ctx, slot_1);
1551 flag_set(ctx, slot_1, false);
1552 continue;
1554 case OPCODE_EVAL: {
1555 get_one(ctx, &slot_1);
1556 g(gen_eval(ctx, slot_1));
1557 continue;
1559 case OPCODE_ESCAPE_NONFLAT: {
1560 frame_t n, i;
1561 frame_t *vars;
1563 get_one(ctx, &n);
1564 vars = mem_alloc_array_mayfail(mem_alloc_mayfail, frame_t *, 0, 0, n, sizeof(frame_t), &ctx->err);
1565 if (unlikely(!vars))
1566 return false;
1567 for (i = 0; i < n; i++) {
1568 get_one(ctx, &vars[i]);
1571 escape_label = alloc_escape_label(ctx);
1572 if (unlikely(!escape_label)) {
1573 mem_free(vars);
1574 return false;
1577 if (unlikely(!gen_test_multiple(ctx, vars, n, escape_label))) {
1578 mem_free(vars);
1579 return false;
1581 mem_free(vars);
1583 continue;
1585 case OPCODE_CHECKPOINT: {
1586 frame_t n_vars;
1588 g(clear_flag_cache(ctx));
1590 if (SIZEOF_IP_T == 2) {
1591 slot_1 = get_code(ctx);
1592 } else if (SIZEOF_IP_T == 4) {
1593 slot_1 = get_uint32(ctx);
1594 } else {
1595 not_reached();
1596 continue;
1599 if (unlikely(!(slot_1 + 1)))
1600 return false;
1601 while (slot_1 >= ctx->n_entries) {
1602 void *err_entries;
1603 struct cg_entry e;
1604 if (unlikely(!ctx->entries)) {
1605 if (unlikely(!array_init_mayfail(struct cg_entry, &ctx->entries, &ctx->n_entries, &ctx->err)))
1606 return false;
1608 memset(&e, 0, sizeof(struct cg_entry));
1609 if (unlikely(!array_add_mayfail(struct cg_entry, &ctx->entries, &ctx->n_entries, e, &err_entries, &ctx->err))) {
1610 ctx->entries = err_entries;
1611 return false;
1615 get_one(ctx, &n_vars);
1617 escape_label = 0; /* avoid warning */
1618 if (likely(slot_1 != 0)) {
1619 escape_label = alloc_escape_label(ctx);
1620 if (unlikely(!escape_label))
1621 return false;
1624 if (n_vars || !slot_1) {
1625 frame_t i;
1626 uint32_t entry_label, nonflat_label;
1627 struct cg_entry *ce = &ctx->entries[slot_1];
1629 if (unlikely(!array_init_mayfail(frame_t, &ce->variables, &ce->n_variables, &ctx->err)))
1630 return false;
1631 for (i = 0; i < n_vars; i++) {
1632 frame_t v;
1633 get_one(ctx, &v);
1634 if (unlikely(!array_add_mayfail(frame_t, &ce->variables, &ce->n_variables, v, NULL, &ctx->err)))
1635 return false;
1637 if (!slot_1) {
1638 g(gen_test_multiple(ctx, ce->variables, ce->n_variables, ctx->escape_nospill_label));
1640 entry_label = alloc_label(ctx);
1641 if (unlikely(!entry_label))
1642 return false;
1643 gen_label(entry_label);
1644 ce->entry_label = entry_label;
1646 nonflat_label = alloc_escape_label_for_ip(ctx, ctx->current_position);
1647 if (unlikely(!nonflat_label))
1648 return false;
1649 ce->nonflat_label = nonflat_label;
1651 if (unlikely(!slot_1))
1652 g(gen_timestamp_test(ctx, ctx->escape_nospill_label));
1653 else
1654 g(gen_timestamp_test(ctx, escape_label));
1655 } else {
1656 g(gen_timestamp_test(ctx, escape_label));
1658 gen_insn(INSN_ENTRY, 0, 0, 0);
1659 gen_four(slot_1);
1661 continue;
1663 case OPCODE_JMP: {
1664 int32_t x = get_jump_offset(ctx);
1665 g(gen_jump(ctx, x, OP_SIZE_NATIVE, COND_ALWAYS, -1U, -1U));
1666 continue;
1668 case OPCODE_JMP_BACK_16: {
1669 int32_t x = get_code(ctx);
1670 g(gen_jump(ctx, -x - (int)(2 * sizeof(code_t)), OP_SIZE_NATIVE, COND_ALWAYS, -1U, -1U));
1671 continue;
1673 case OPCODE_JMP_FALSE: {
1674 int32_t offs_false;
1675 get_one(ctx, &slot_1);
1676 offs_false = get_jump_offset(ctx);
1677 get_jump_offset(ctx);
1678 escape_label = alloc_escape_label(ctx);
1679 if (unlikely(!escape_label))
1680 return false;
1681 g(gen_test_1_cached(ctx, slot_1, escape_label));
1682 flag_set(ctx, slot_1, false);
1683 g(gen_cond_jump(ctx, slot_1, offs_false));
1684 continue;
1686 case OPCODE_LABEL: {
1687 g(clear_flag_cache(ctx));
1688 continue;
1690 #define init_args \
1691 do { \
1692 if (ctx->args != NULL) \
1693 mem_free(ctx->args); \
1694 g(array_init_mayfail(struct code_arg, &ctx->args, &ctx->args_l, &ctx->err));\
1695 } while (0)
1696 #define load_args \
1697 do { \
1698 init_args; \
1699 for (i_arg = 0; i_arg < n_args; i_arg++) { \
1700 struct code_arg a; \
1701 get_two(ctx, &a.slot, &a.flags); \
1702 a.type = 0; \
1703 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));\
1705 } while (0)
1706 case OPCODE_LOAD_FN:
1707 get_two(ctx, &n_args, &slot_r);
1708 get_one(ctx, &fn_idx);
1709 load_args;
1710 g(gen_load_fn_or_curry(ctx, fn_idx, NO_FRAME_T, slot_r, 0));
1711 continue;
1712 case OPCODE_CURRY:
1713 get_two(ctx, &n_args, &slot_r);
1714 get_two(ctx, &slot_1, &flags);
1715 load_args;
1716 g(gen_load_fn_or_curry(ctx, NO_FRAME_T, slot_1, slot_r, flags));
1717 continue;
1718 case OPCODE_CALL:
1719 case OPCODE_CALL_STRICT:
1720 case OPCODE_CALL_SPARK:
1721 case OPCODE_CALL_LAZY:
1722 case OPCODE_CALL_CACHE:
1723 case OPCODE_CALL_SAVE: {
1724 get_two(ctx, &n_args, &n_ret);
1725 get_one(ctx, &fn_idx);
1726 jump_over_arguments_and_return:
1727 load_args;
1728 ctx->return_values = ctx->current_position;
1729 for (i_arg = 0; i_arg < n_ret; i_arg++) {
1730 #if ARG_MODE_N >= 3
1731 get_uint32(ctx);
1732 #else
1733 get_code(ctx);
1734 #endif
1735 get_code(ctx);
1737 if (unlikely(profiling))
1738 goto unconditional_escape;
1739 if (code == OPCODE_CALL || code == OPCODE_CALL_STRICT) {
1740 g(gen_call(ctx, code, fn_idx));
1741 continue;
1743 /*if (code == OPCODE_CALL_INDIRECT || code == OPCODE_CALL_INDIRECT_STRICT) {
1744 if (unlikely(!gen_call_indirect(ctx, code, slot_1, flags)))
1745 return false;
1746 continue;
1748 goto unconditional_escape;
1750 case OPCODE_CALL_INDIRECT:
1751 case OPCODE_CALL_INDIRECT_STRICT:
1752 case OPCODE_CALL_INDIRECT_SPARK:
1753 case OPCODE_CALL_INDIRECT_LAZY:
1754 case OPCODE_CALL_INDIRECT_CACHE:
1755 case OPCODE_CALL_INDIRECT_SAVE: {
1756 fn_idx = 0; /* avoid warning */
1757 get_two(ctx, &n_args, &n_ret);
1758 get_two(ctx, &slot_1, &flags);
1759 goto jump_over_arguments_and_return;
1761 case OPCODE_RETURN: {
1762 n_args = da(ctx->fn,function)->n_return_values;
1763 load_args;
1764 if (unlikely(profiling))
1765 goto unconditional_escape;
1766 g(gen_return(ctx));
1767 continue;
1769 case OPCODE_STRUCTURED: {
1770 init_args;
1771 get_two(ctx, &slot_1, &slot_2);
1772 do {
1773 struct code_arg a;
1774 get_two(ctx, &flags, &slot_r);
1775 get_one(ctx, &opt);
1776 a.slot = slot_r;
1777 a.flags = flags;
1778 a.type = opt;
1779 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1780 } while (!(flags & OPCODE_STRUCTURED_FLAG_END));
1781 g(gen_structured(ctx, slot_1, slot_2));
1782 continue;
1784 case OPCODE_RECORD_CREATE: {
1785 init_args;
1786 get_two(ctx, &slot_r, &n_args);
1787 for (i_arg = 0; i_arg < n_args; i_arg++) {
1788 struct code_arg a;
1789 get_two(ctx, &slot_1, &flags);
1790 a.slot = slot_1;
1791 a.flags = flags;
1792 a.type = 0;
1793 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1795 g(gen_record_create(ctx, slot_r));
1796 continue;
1798 case OPCODE_RECORD_LOAD: {
1799 get_two(ctx, &slot_1, &opt);
1800 get_two(ctx, &slot_r, &flags);
1801 g(gen_record_load(ctx, slot_1, slot_r, opt, flags));
1802 continue;
1804 case OPCODE_OPTION_CREATE_EMPTY_FLAT: {
1805 get_two(ctx, &slot_r, &opt);
1806 g(gen_option_create_empty_flat(ctx, opt, slot_r));
1807 continue;
1809 case OPCODE_OPTION_CREATE_EMPTY: {
1810 get_two(ctx, &slot_r, &opt);
1811 g(gen_option_create_empty(ctx, opt, slot_r));
1812 continue;
1814 case OPCODE_OPTION_CREATE: {
1815 get_two(ctx, &slot_r, &opt);
1816 get_two(ctx, &slot_1, &flags);
1817 g(gen_option_create(ctx, opt, slot_1, slot_r, flags));
1818 continue;
1820 case OPCODE_OPTION_LOAD: {
1821 get_two(ctx, &slot_1, &opt);
1822 get_two(ctx, &slot_r, &flags);
1823 g(gen_option_load(ctx, slot_1, slot_r, opt, flags));
1824 continue;
1826 case OPCODE_OPTION_TEST_FLAT: {
1827 get_two(ctx, &slot_1, &opt);
1828 get_one(ctx, &slot_r);
1829 g(gen_option_test_flat(ctx, slot_1, opt, slot_r));
1830 continue;
1832 case OPCODE_OPTION_TEST: {
1833 get_two(ctx, &slot_1, &opt);
1834 get_one(ctx, &slot_r);
1835 g(gen_option_test(ctx, slot_1, opt, slot_r));
1836 continue;
1838 case OPCODE_OPTION_ORD_FLAT: {
1839 get_two(ctx, &slot_1, &slot_r);
1840 g(gen_option_ord(ctx, slot_1, slot_r, true));
1841 continue;
1843 case OPCODE_OPTION_ORD: {
1844 get_two(ctx, &slot_1, &slot_r);
1845 g(gen_option_ord(ctx, slot_1, slot_r, false));
1846 continue;
1848 case OPCODE_ARRAY_CREATE: {
1849 init_args;
1850 get_two(ctx, &slot_r, &n_args);
1851 for (i_arg = 0; i_arg < n_args; i_arg++) {
1852 struct code_arg a;
1853 get_two(ctx, &slot_1, &flags);
1854 a.slot = slot_1;
1855 a.flags = flags;
1856 a.type = 0;
1857 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1859 g(gen_array_create(ctx, slot_r));
1860 continue;
1862 case OPCODE_ARRAY_CREATE_EMPTY_FLAT: {
1863 get_two(ctx, &slot_r, &flags);
1864 g(gen_array_create_empty_flat(ctx, slot_r, flags));
1865 continue;
1867 case OPCODE_ARRAY_CREATE_EMPTY: {
1868 get_one(ctx, &slot_r);
1869 g(gen_array_create_empty(ctx, slot_r));
1870 continue;
1872 case OPCODE_ARRAY_FILL: {
1873 get_two(ctx, &slot_1, &flags);
1874 get_two(ctx, &slot_2, &slot_r);
1875 g(gen_array_fill(ctx, slot_1, flags, slot_2, slot_r));
1876 continue;
1878 case OPCODE_ARRAY_STRING: {
1879 frame_t i;
1880 get_two(ctx, &slot_r, &i);
1881 g(gen_array_string(ctx, type_get_fixed(0, true)->tag, cast_ptr(uint8_t *, ctx->current_position), i, slot_r));
1882 ctx->current_position += (i + 1) >> 1;
1883 continue;
1885 case OPCODE_ARRAY_UNICODE: {
1886 frame_t i;
1887 get_two(ctx, &slot_r, &i);
1888 g(gen_array_string(ctx, type_get_int(2)->tag, cast_ptr(uint8_t *, ctx->current_position), i, slot_r));
1889 ctx->current_position += i * 2;
1890 continue;
1892 case OPCODE_ARRAY_LOAD: {
1893 get_two(ctx, &slot_1, &slot_2);
1894 get_two(ctx, &slot_r, &flags);
1895 g(gen_array_load(ctx, slot_1, slot_2, slot_r, flags));
1896 continue;
1898 case OPCODE_ARRAY_LEN: {
1899 get_two(ctx, &slot_1, &slot_r);
1900 get_one(ctx, &flags);
1901 g(gen_array_len(ctx, slot_1, NO_FRAME_T, slot_r, false, 0));
1902 continue;
1904 case OPCODE_ARRAY_LEN_GREATER_THAN: {
1905 get_two(ctx, &slot_1, &slot_2);
1906 get_two(ctx, &slot_r, &flags);
1907 escape_label = alloc_escape_label(ctx);
1908 if (unlikely(!escape_label))
1909 return false;
1910 if (flags & OPCODE_FLAG_FUSED) {
1911 g(gen_fused_binary(ctx, MODE_ARRAY_LEN_GT, 0, 0, escape_label, slot_1, slot_2, slot_r, &failed));
1912 if (unlikely(!failed))
1913 continue;
1915 g(gen_array_len(ctx, slot_1, slot_2, slot_r, false, 0));
1916 continue;
1918 case OPCODE_ARRAY_SUB: {
1919 get_two(ctx, &slot_1, &slot_2);
1920 get_two(ctx, &slot_3, &slot_r);
1921 get_one(ctx, &flags);
1922 g(gen_array_sub(ctx, slot_1, slot_2, slot_3, slot_r, flags));
1923 continue;
1925 case OPCODE_ARRAY_SKIP: {
1926 get_two(ctx, &slot_1, &slot_2);
1927 get_two(ctx, &slot_r, &flags);
1928 g(gen_array_skip(ctx, slot_1, slot_2, slot_r, flags));
1929 continue;
1931 case OPCODE_ARRAY_APPEND: {
1932 get_two(ctx, &slot_r, &flags);
1933 get_two(ctx, &slot_1, &slot_2);
1934 g(gen_array_append(ctx, slot_1, slot_2, slot_r, flags));
1935 continue;
1937 case OPCODE_ARRAY_APPEND_ONE_FLAT: {
1938 get_two(ctx, &slot_r, &flags);
1939 get_two(ctx, &slot_1, &slot_2);
1940 g(gen_array_append_one_flat(ctx, slot_1, slot_2, slot_r, flags));
1941 continue;
1943 case OPCODE_ARRAY_APPEND_ONE: {
1944 get_two(ctx, &slot_r, &flags);
1945 get_two(ctx, &slot_1, &slot_2);
1946 g(gen_array_append_one(ctx, slot_1, slot_2, slot_r, flags));
1947 continue;
1949 case OPCODE_ARRAY_FLATTEN: {
1950 get_two(ctx, &slot_r, &flags);
1951 get_one(ctx, &slot_1);
1952 goto unconditional_escape;
1954 case OPCODE_IO: {
1955 get_two(ctx, &flags, &slot_1);
1956 get_two(ctx, &slot_2, &slot_3);
1957 g(gen_io(ctx, flags, slot_1, slot_2, slot_3));
1958 continue;
1960 case OPCODE_INTERNAL_FUNCTION:
1961 case OPCODE_EXIT_THREAD:
1962 case OPCODE_UNREACHABLE: {
1963 goto unconditional_escape;
1965 default: {
1966 #if 1
1967 /*if (getenv("DUMP") && !strcmp(da(ctx->fn,function)->function_name, getenv("DUMP")))*/
1968 warning("gen_function: %s: unknown opcode %04x, %s", da(ctx->fn,function)->function_name, *ctx->instr_start, decode_opcode(*ctx->instr_start, false));
1969 #endif
1970 return false;
1975 return true;
1978 static bool attr_w gen_entries(struct codegen_context *ctx)
1980 size_t i;
1981 for (i = 0; i < ctx->n_entries; i++) {
1982 struct cg_entry *ce = &ctx->entries[i];
1983 if (ce->entry_label) {
1984 gen_insn(INSN_ENTRY, 0, 0, 0);
1985 gen_four(i);
1987 g(gen_test_multiple(ctx, ce->variables, ce->n_variables, ce->nonflat_label));
1989 gen_insn(INSN_JMP, 0, 0, 0);
1990 gen_four(ce->entry_label);
1993 return true;
1996 static bool attr_w gen_epilogues(struct codegen_context *ctx)
1998 frame_t v;
1999 ip_t ip;
2000 uint32_t escape_label, nospill_label;
2001 escape_label = alloc_label(ctx);
2002 if (unlikely(!escape_label))
2003 return false;
2004 nospill_label = alloc_label(ctx);
2005 if (unlikely(!nospill_label))
2006 return false;
2007 #if defined(ARCH_PARISC)
2008 if (ctx->call_label) {
2009 gen_label(ctx->call_label);
2010 g(gen_call_millicode(ctx));
2012 #endif
2013 if (ctx->reload_label) {
2014 gen_label(ctx->reload_label);
2015 g(gen_mov(ctx, i_size(OP_SIZE_ADDRESS), R_FRAME, R_RET0));
2016 g(gen_escape_arg(ctx, (ip_t)-1, escape_label));
2018 gen_label(ctx->escape_nospill_label);
2019 g(gen_escape_arg(ctx, 0, nospill_label));
2020 for (ip = 0; ip < da(ctx->fn,function)->code_size; ip++) {
2021 struct cg_exit *ce = ctx->code_exits[ip];
2022 if (ce && (ce->undo_label || ce->escape_label)) {
2023 if (ce->undo_label) {
2024 size_t i;
2025 gen_label(ce->undo_label);
2026 gen_insn(ce->undo_opcode, ce->undo_op_size, ce->undo_aux, ce->undo_writes_flags);
2027 for (i = 0; i < ce->undo_parameters_len; i++)
2028 gen_one(ce->undo_parameters[i]);
2030 if (ce->escape_label) {
2031 gen_label(ce->escape_label);
2033 g(gen_escape_arg(ctx, ip, escape_label));
2036 gen_label(escape_label);
2037 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
2038 if (ctx->registers[v] >= 0) {
2039 g(spill(ctx, v));
2042 gen_label(nospill_label);
2043 g(gen_escape(ctx));
2044 return true;
2047 static bool attr_w cgen_entry(struct codegen_context *ctx)
2049 uint32_t entry_id = cget_four(ctx);
2050 ajla_assert_lo(entry_id < ctx->n_entries, (file_line, "cgen_entry: invalid entry %lx", (unsigned long)entry_id));
2051 ctx->entries[entry_id].entry_to_pos = ctx->mcode_size;
2052 return true;
2055 static bool attr_w cgen_label(struct codegen_context *ctx)
2057 uint32_t label_id = cget_four(ctx);
2058 ctx->label_to_pos[label_id] = ctx->mcode_size;
2059 return true;
2062 static bool attr_w attr_unused cgen_trap(struct codegen_context *ctx, uint32_t label)
2064 struct trap_record tr;
2065 tr.source_ip = ctx->mcode_size;
2066 tr.destination_ip = label;
2067 if (unlikely(!array_add_mayfail(struct trap_record, &ctx->trap_records, &ctx->trap_records_size, tr, NULL, &ctx->err)))
2068 return false;
2069 return true;
2072 static bool attr_w add_relocation(struct codegen_context *ctx, unsigned length, int offset, bool *known)
2074 struct relocation rel;
2075 rel.label_id = cget_four(ctx);
2076 rel.length = length;
2077 rel.position = ctx->mcode_size;
2078 rel.jmp_instr = ctx->code_position - 8 - offset - ctx->code;
2079 if (unlikely(!array_add_mayfail(struct relocation, &ctx->reloc, &ctx->reloc_size, rel, NULL, &ctx->err)))
2080 return false;
2081 if (known)
2082 *known = ctx->label_to_pos[rel.label_id] != (size_t)-1;
2083 return true;
2087 #if defined(ARCH_ALPHA)
2088 #include "c2-alpha.inc"
2089 #elif defined(ARCH_ARM32)
2090 #include "c2-arm.inc"
2091 #elif defined(ARCH_ARM64)
2092 #include "c2-arm64.inc"
2093 #elif defined(ARCH_IA64)
2094 #include "c2-ia64.inc"
2095 #elif defined(ARCH_LOONGARCH64)
2096 #include "c2-loong.inc"
2097 #elif defined(ARCH_MIPS)
2098 #include "c2-mips.inc"
2099 #elif defined(ARCH_PARISC)
2100 #include "c2-hppa.inc"
2101 #elif defined(ARCH_POWER)
2102 #include "c2-power.inc"
2103 #elif defined(ARCH_S390)
2104 #include "c2-s390.inc"
2105 #elif defined(ARCH_SPARC)
2106 #include "c2-sparc.inc"
2107 #elif defined(ARCH_RISCV64)
2108 #include "c2-riscv.inc"
2109 #elif defined(ARCH_X86)
2110 #include "c2-x86.inc"
2111 #endif
2114 static bool attr_w gen_mcode(struct codegen_context *ctx)
2116 ctx->code_position = ctx->code;
2118 while (ctx->code_position != ctx->code + ctx->code_size) {
2119 uint32_t insn;
2120 ajla_assert_lo(ctx->code_position < ctx->code + ctx->code_size, (file_line, "gen_mcode: ran out of code"));
2121 #ifdef DEBUG_INSNS
2122 insn = cget_four(ctx);
2123 debug("line: %u", insn);
2124 #endif
2125 insn = cget_four(ctx);
2126 g(cgen_insn(ctx, insn));
2129 return true;
2132 #define RELOCS_RETRY -1
2133 #define RELOCS_FAIL 0
2134 #define RELOCS_OK 1
2136 static int8_t resolve_relocs(struct codegen_context *ctx)
2138 size_t i;
2139 int8_t status = RELOCS_OK;
2140 for (i = 0; i < ctx->reloc_size; i++) {
2141 struct relocation *reloc = &ctx->reloc[i];
2142 if (!resolve_relocation(ctx, reloc)) {
2143 uint8_t *jmp_instr;
2144 uint32_t insn;
2145 uint32_t new_length;
2146 status = RELOCS_RETRY;
2147 if (unlikely(reloc->length + zero >= JMP_LIMIT))
2148 return RELOCS_FAIL;
2149 new_length = reloc->length + 1;
2150 jmp_instr = ctx->code + reloc->jmp_instr;
2151 insn = (uint32_t)jmp_instr[0] +
2152 ((uint32_t)jmp_instr[1] << 8) +
2153 ((uint32_t)jmp_instr[2] << 16) +
2154 ((uint32_t)jmp_instr[3] << 24);
2155 insn &= ~INSN_JUMP_SIZE;
2156 insn |= (uint32_t)new_length << INSN_JUMP_SIZE_SHIFT;
2157 jmp_instr[0] = insn;
2158 jmp_instr[1] = insn >> 8;
2159 jmp_instr[2] = insn >> 16;
2160 jmp_instr[3] = insn >> 24;
2163 return status;
2166 static void resolve_traps(struct codegen_context *ctx)
2168 size_t i;
2169 for (i = 0; i < ctx->trap_records_size; i++) {
2170 struct trap_record *tr = &ctx->trap_records[i];
2171 tr->destination_ip = ctx->label_to_pos[tr->destination_ip];
2176 static bool attr_w codegen_map(struct codegen_context *ctx)
2178 void *ptr;
2179 frame_t i;
2180 array_finish(uint8_t, &ctx->mcode, &ctx->mcode_size);
2181 ptr = os_code_map(ctx->mcode, ctx->mcode_size, &ctx->err);
2182 ctx->mcode = NULL;
2183 if (unlikely(!ptr)) {
2184 return false;
2186 for (i = 0; i < ctx->n_entries; i++) {
2187 char *entry = cast_ptr(char *, ptr) + ctx->entries[i].entry_to_pos;
2188 da(ctx->codegen,codegen)->unoptimized_code[i] = entry;
2189 da(ctx->codegen,codegen)->n_entries++;
2191 da(ctx->codegen,codegen)->unoptimized_code_base = ptr;
2192 da(ctx->codegen,codegen)->unoptimized_code_size = ctx->mcode_size;
2194 return true;
2198 void *codegen_fn(frame_s *fp, const code_t *ip, union internal_arg ia[])
2200 struct codegen_context ctx_;
2201 struct codegen_context *ctx = &ctx_;
2202 frame_t i;
2203 int8_t rr;
2204 struct data *codegen;
2205 uint32_t l;
2207 init_ctx(ctx);
2208 ctx->fn = ia[0].ptr;
2210 #ifdef DEBUG_ENV
2211 if (getenv("CG") && strcmp(da(ctx->fn,function)->function_name, getenv("CG")))
2212 goto fail;
2213 #endif
2215 ctx->local_directory = mem_alloc_array_mayfail(mem_calloc_mayfail, struct data **, 0, 0, da(ctx->fn,function)->local_directory_size, sizeof(struct data *), &ctx->err);
2216 if (unlikely(!ctx->local_directory))
2217 goto fail;
2219 if (0) for (i = 0; i < da(ctx->fn,function)->local_directory_size; i++) {
2220 struct data *callee;
2221 pointer_t *ptr;
2222 ptr = da(ctx->fn,function)->local_directory[i];
2223 pointer_follow(ptr, false, callee, PF_SPARK, NULL, 0,
2224 SUBMIT_EX(ex_);
2225 goto next_one,
2226 goto next_one;
2228 ctx->local_directory[i] = callee;
2229 next_one:;
2231 for (i = 0; i < da(ctx->fn,function)->local_directory_size; i++) {
2232 struct data *callee;
2233 pointer_t *ptr;
2234 if (ctx->local_directory[i])
2235 continue;
2236 ptr = da(ctx->fn,function)->local_directory[i];
2237 pointer_follow(ptr, false, callee, PF_WAIT, fp, ip,
2238 done_ctx(ctx);
2239 return ex_,
2240 goto fail
2242 ctx->local_directory[i] = callee;
2243 /*debug("processing call: %s -> %s", da(ctx->fn,function)->function_name, da(callee,function)->function_name);*/
2246 if (da(ctx->fn,function)->module_designator) {
2247 struct function_descriptor *sfd = save_find_function_descriptor(da(ctx->fn,function)->module_designator, da(ctx->fn,function)->function_designator);
2248 if (sfd && sfd->unoptimized_code_size) {
2249 codegen = data_alloc_flexible(codegen, unoptimized_code, sfd->n_entries, &ctx->err);
2250 if (unlikely(!codegen))
2251 goto fail;
2252 da(codegen,codegen)->unoptimized_code_base = sfd->unoptimized_code_base;
2253 da(codegen,codegen)->unoptimized_code_size = sfd->unoptimized_code_size;
2254 da(codegen,codegen)->function = ctx->fn;
2255 da(codegen,codegen)->is_saved = true;
2256 da(codegen,codegen)->n_entries = sfd->n_entries;
2257 da(codegen,codegen)->offsets = NULL;
2258 for (i = 0; i < sfd->n_entries; i++) {
2259 da(codegen,codegen)->unoptimized_code[i] = cast_ptr(char *, da(codegen,codegen)->unoptimized_code_base) + sfd->entries[i];
2260 /*debug("%s: %p + %lx -> %p", da(ctx->fn,function)->function_name, da(codegen,codegen)->unoptimized_code_base, sfd->entries[i], da(codegen,codegen)->unoptimized_code[i]);*/
2262 #ifdef HAVE_CODEGEN_TRAPS
2263 da(codegen,codegen)->trap_records = sfd->trap_records;
2264 da(codegen,codegen)->trap_records_size = sfd->trap_records_size;
2265 data_trap_insert(codegen);
2266 #endif
2267 goto have_codegen;
2271 /*debug("trying: %s", da(ctx->fn,function)->function_name);*/
2272 if (unlikely(!array_init_mayfail(uint8_t, &ctx->code, &ctx->code_size, &ctx->err)))
2273 goto fail;
2275 ctx->code_labels = mem_alloc_array_mayfail(mem_calloc_mayfail, uint32_t *, 0, 0, da(ctx->fn,function)->code_size, sizeof(uint32_t), &ctx->err);
2276 if (unlikely(!ctx->code_labels))
2277 goto fail;
2279 ctx->code_exits = mem_alloc_array_mayfail(mem_calloc_mayfail, struct cg_exit **, 0, 0, da(ctx->fn,function)->code_size, sizeof(struct cg_exit *), &ctx->err);
2280 if (unlikely(!ctx->code_exits))
2281 goto fail;
2283 ctx->flag_cache = mem_alloc_array_mayfail(mem_calloc_mayfail, uint8_t *, 0, 0, function_n_variables(ctx->fn), sizeof(int8_t), &ctx->err);
2284 if (unlikely(!ctx->flag_cache))
2285 goto fail;
2287 ctx->registers = mem_alloc_array_mayfail(mem_alloc_mayfail, short *, 0, 0, function_n_variables(ctx->fn), sizeof(short), &ctx->err);
2288 if (unlikely(!ctx->registers))
2289 goto fail;
2291 if (unlikely(!array_init_mayfail(frame_t, &ctx->need_spill, &ctx->need_spill_l, &ctx->err)))
2292 goto fail;
2294 if (unlikely(!gen_registers(ctx)))
2295 goto fail;
2297 if (unlikely(!gen_function(ctx)))
2298 goto fail;
2300 if (unlikely(!gen_entries(ctx)))
2301 goto fail;
2303 if (unlikely(!gen_epilogues(ctx)))
2304 goto fail;
2306 if (unlikely(!(ctx->label_id + 1)))
2307 goto fail;
2308 if (unlikely(!(ctx->label_to_pos = mem_alloc_array_mayfail(mem_alloc_mayfail, size_t *, 0, 0, ctx->label_id + 1, sizeof(size_t), &ctx->err))))
2309 goto fail;
2311 again:
2312 for (l = 0; l < ctx->label_id + 1; l++)
2313 ctx->label_to_pos[l] = (size_t)-1;
2315 if (unlikely(!array_init_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, &ctx->err)))
2316 goto fail;
2318 if (unlikely(!array_init_mayfail(struct relocation, &ctx->reloc, &ctx->reloc_size, &ctx->err)))
2319 goto fail;
2321 if (unlikely(!array_init_mayfail(struct trap_record, &ctx->trap_records, &ctx->trap_records_size, &ctx->err)))
2322 goto fail;
2324 #ifdef ARCH_CONTEXT
2325 init_arch_context(ctx);
2326 #endif
2328 if (unlikely(!gen_mcode(ctx)))
2329 goto fail;
2331 rr = resolve_relocs(ctx);
2332 if (unlikely(rr == RELOCS_FAIL)) {
2333 /*debug("relocation fail: %s", da(ctx->fn,function)->function_name);*/
2334 goto fail;
2336 if (rr == RELOCS_RETRY) {
2337 mem_free(ctx->mcode);
2338 ctx->mcode = NULL;
2339 mem_free(ctx->reloc);
2340 ctx->reloc = NULL;
2341 mem_free(ctx->trap_records);
2342 ctx->trap_records = NULL;
2343 goto again;
2346 resolve_traps(ctx);
2348 #ifdef DEBUG_ENV
2349 if ((getenv("DUMP") && !strcmp(getenv("DUMP"), da(ctx->fn,function)->function_name)) || getenv("DUMP_ALL")) {
2350 char *hex;
2351 size_t hexl;
2352 size_t i;
2353 handle_t h;
2355 mutex_lock(&dump_mutex);
2356 str_init(&hex, &hexl);
2357 str_add_string(&hex, &hexl, "_");
2358 str_add_unsigned(&hex, &hexl, dump_seq++, 10);
2359 str_add_string(&hex, &hexl, "_");
2360 str_add_string(&hex, &hexl, da(ctx->fn,function)->function_name);
2361 str_add_string(&hex, &hexl, ":");
2362 for (i = 0; i < hexl; i++)
2363 if (hex[i] == '/')
2364 hex[i] = '_';
2365 for (i = 0; i < ctx->mcode_size; i++) {
2366 uint8_t a = ctx->mcode[i];
2367 if (!(i & 0xff))
2368 str_add_string(&hex, &hexl, "\n .byte 0x");
2369 else
2370 str_add_string(&hex, &hexl, ",0x");
2371 if (a < 16)
2372 str_add_char(&hex, &hexl, '0');
2373 str_add_unsigned(&hex, &hexl, a, 16);
2375 str_add_string(&hex, &hexl, "\n");
2376 h = os_open(os_cwd, "dump.s", O_WRONLY | O_APPEND, 0600, NULL);
2377 os_write_all(h, hex, hexl, NULL);
2378 os_close(h);
2379 mem_free(hex);
2380 mutex_unlock(&dump_mutex);
2382 #endif
2384 ctx->codegen = data_alloc_flexible(codegen, unoptimized_code, ctx->n_entries, &ctx->err);
2385 if (unlikely(!ctx->codegen))
2386 goto fail;
2387 da(ctx->codegen,codegen)->function = ctx->fn;
2388 da(ctx->codegen,codegen)->is_saved = false;
2389 da(ctx->codegen,codegen)->n_entries = 0;
2390 da(ctx->codegen,codegen)->offsets = NULL;
2392 if (unlikely(!codegen_map(ctx)))
2393 goto fail;
2395 codegen = ctx->codegen;
2396 ctx->codegen = NULL;
2398 #ifdef HAVE_CODEGEN_TRAPS
2399 da(codegen,codegen)->trap_records = ctx->trap_records;
2400 da(codegen,codegen)->trap_records_size = ctx->trap_records_size;
2401 ctx->trap_records = NULL;
2402 data_trap_insert(codegen);
2403 #endif
2405 have_codegen:
2406 done_ctx(ctx);
2407 return function_return(fp, pointer_data(codegen));
2409 fail:
2410 /*debug("FAILED: %s", da(ctx->fn,function)->function_name);*/
2411 done_ctx(ctx);
2412 return function_return(fp, pointer_thunk(thunk_alloc_exception_error(error_ajla(EC_SYNC, AJLA_ERROR_NOT_SUPPORTED), NULL, NULL, NULL pass_file_line)));
2415 void codegen_free(struct data *codegen)
2417 if (unlikely(da(codegen,codegen)->offsets != NULL))
2418 mem_free(da(codegen,codegen)->offsets);
2419 if (likely(da(codegen,codegen)->is_saved))
2420 return;
2421 #ifdef HAVE_CODEGEN_TRAPS
2422 mem_free(da(codegen,codegen)->trap_records);
2423 #endif
2424 os_code_unmap(da(codegen,codegen)->unoptimized_code_base, da(codegen,codegen)->unoptimized_code_size);
2427 #if defined(ARCH_IA64)
2428 static uintptr_t ia64_stub[2];
2429 #endif
2430 #if defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2431 static uintptr_t parisc_stub[2];
2432 #endif
2433 #if defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2434 static uintptr_t parisc_stub[4];
2435 #endif
2436 #if defined(ARCH_POWER) && defined(AIX_CALL)
2437 static uintptr_t ppc_stub[3];
2438 #endif
2440 void name(codegen_init)(void)
2442 struct codegen_context ctx_;
2443 struct codegen_context *ctx = &ctx_;
2444 void *ptr;
2446 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
2447 #if defined(HAVE_SYSCALL) && defined(HAVE_ASM_PRCTL_H) && defined(HAVE_SYS_SYSCALL_H)
2448 if (!dll) {
2449 int r;
2450 EINTR_LOOP(r, syscall(SYS_arch_prctl, ARCH_SET_GS, &cg_upcall_vector));
2451 if (!r)
2452 upcall_register = R_GS;
2454 #elif defined(HAVE_AMD64_SET_GSBASE) && defined(HAVE_X86_SYSARCH_H)
2455 if (!dll) {
2456 int r;
2457 EINTR_LOOP(r, amd64_set_gsbase(&cg_upcall_vector));
2458 if (!r)
2459 upcall_register = R_GS;
2461 #elif defined(HAVE_SYSARCH) && defined(HAVE_X86_SYSARCH_H) && defined(X86_64_SET_GSBASE)
2462 if (!dll) {
2463 int r;
2464 void *ptr = &cg_upcall_vector;
2465 EINTR_LOOP(r, sysarch(X86_64_SET_GSBASE, &ptr));
2466 if (!r)
2467 upcall_register = R_GS;
2469 #endif
2470 #endif
2472 init_ctx(ctx);
2473 ctx->fn = NULL;
2475 array_init(uint8_t, &ctx->code, &ctx->code_size);
2477 if (unlikely(!gen_entry(ctx)))
2478 goto fail;
2480 array_init(uint8_t, &ctx->mcode, &ctx->mcode_size);
2482 #ifdef ARCH_CONTEXT
2483 init_arch_context(ctx);
2484 #endif
2486 if (unlikely(!gen_mcode(ctx)))
2487 goto fail;
2489 array_finish(uint8_t, &ctx->mcode, &ctx->mcode_size);
2490 ptr = os_code_map(ctx->mcode, ctx->mcode_size, NULL);
2491 codegen_ptr = ptr;
2492 codegen_size = ctx->mcode_size;
2493 ctx->mcode = NULL;
2494 #if defined(ARCH_IA64)
2495 ia64_stub[0] = ptr_to_num(ptr);
2496 ia64_stub[1] = 0;
2497 codegen_entry = cast_ptr(codegen_type, ia64_stub);
2498 #elif defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2499 parisc_stub[0] = ptr_to_num(ptr);
2500 parisc_stub[1] = 0;
2501 codegen_entry = cast_ptr(codegen_type, cast_ptr(char *, parisc_stub) + 2);
2502 #elif defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2503 parisc_stub[0] = 0;
2504 parisc_stub[1] = 0;
2505 parisc_stub[2] = ptr_to_num(ptr);
2506 parisc_stub[3] = 0;
2507 codegen_entry = cast_ptr(codegen_type, parisc_stub);
2508 #elif defined(ARCH_POWER) && defined(AIX_CALL)
2509 ppc_stub[0] = ptr_to_num(ptr);
2510 ppc_stub[1] = 0;
2511 ppc_stub[2] = 0;
2512 codegen_entry = cast_ptr(codegen_type, ppc_stub);
2513 #else
2514 codegen_entry = ptr;
2515 #endif
2516 done_ctx(ctx);
2518 #ifdef DEBUG_ENV
2519 mutex_init(&dump_mutex);
2520 if (getenv("DUMP") || getenv("DUMP_ALL")) {
2521 size_t i;
2522 char *hex;
2523 size_t hexl;
2524 str_init(&hex, &hexl);
2525 #if defined(ARCH_RISCV64)
2526 str_add_string(&hex, &hexl, " .attribute arch, \"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zba1p0_zbb1p0_zbc1p0_zbs1p0\"\n");
2527 #endif
2528 for (i = 0; i < codegen_size; i++) {
2529 uint8_t a = cast_ptr(uint8_t *, codegen_ptr)[i];
2530 str_add_string(&hex, &hexl, " .byte 0x");
2531 if (a < 16)
2532 str_add_char(&hex, &hexl, '0');
2533 str_add_unsigned(&hex, &hexl, a, 16);
2534 str_add_char(&hex, &hexl, '\n');
2536 os_write_atomic(".", "dump.s", hex, hexl, NULL);
2537 mem_free(hex);
2539 #endif
2541 return;
2543 fail:
2544 fatal("couldn't compile global entry");
2547 void name(codegen_done)(void)
2549 os_code_unmap(codegen_ptr, codegen_size);
2550 #ifdef DEBUG_ENV
2551 mutex_done(&dump_mutex);
2552 #endif
2555 #else
2557 void name(codegen_init)(void)
2561 void name(codegen_done)(void)
2565 #endif
2567 #endif