implement array_len_greater_than+jmp fusion
[ajla.git] / codegen.c
blobb7d4f12e0cb3a6272d6f082de8c1327cb833e9b8
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_MOVR,
266 INSN_CSEL_SEL,
267 INSN_CSEL_INC,
268 INSN_CSEL_INV,
269 INSN_CSEL_NEG,
270 INSN_STP,
271 INSN_LDP,
272 INSN_MOV_MASK,
273 INSN_MEMCPY,
274 INSN_MEMSET,
275 INSN_FP_CMP,
276 INSN_FP_CMP_DEST_REG,
277 INSN_FP_CMP_DEST_REG_TRAP,
278 INSN_FP_CMP_UNORDERED_DEST_REG,
279 INSN_FP_CMP_COND,
280 INSN_FP_TEST_REG,
281 INSN_FP_TO_INT_FLAGS,
282 INSN_FP_ALU,
283 INSN_FP_ALU1,
284 INSN_FP_TO_INT32,
285 INSN_FP_TO_INT64,
286 INSN_FP_TO_INT64_TRAP,
287 INSN_FP_FROM_INT32,
288 INSN_FP_FROM_INT64,
289 INSN_FP_INT64_TO_INT32_TRAP,
290 INSN_FP_CVT,
291 INSN_X87_FLD,
292 INSN_X87_FILD,
293 INSN_X87_FSTP,
294 INSN_X87_FISTP,
295 INSN_X87_FISTTP,
296 INSN_X87_FCOMP,
297 INSN_X87_FCOMPP,
298 INSN_X87_FCOMIP,
299 INSN_X87_ALU,
300 INSN_X87_ALUP,
301 INSN_X87_FCHS,
302 INSN_X87_FSQRT,
303 INSN_X87_FRNDINT,
304 INSN_X87_FNSTSW,
305 INSN_X87_FLDCW,
306 INSN_JMP,
307 INSN_JMP_COND,
308 INSN_JMP_COND_LOGICAL,
309 INSN_JMP_REG,
310 INSN_JMP_REG_BIT,
311 INSN_JMP_2REGS,
312 INSN_JMP_FP_TEST,
313 INSN_JMP_INDIRECT,
314 INSN_MB,
315 INSN_CALL_MILLICODE,
318 #define ARG_REGS_MAX 0xc0
319 #define ARG_SHIFTED_REGISTER 0xc0
320 #define ARG_SHIFT_AMOUNT 0x3f
321 #define ARG_SHIFT_MODE 0xc0
322 #define ARG_SHIFT_LSL 0x00
323 #define ARG_SHIFT_LSR 0x40
324 #define ARG_SHIFT_ASR 0x80
325 #define ARG_SHIFT_ROR 0xc0
326 #define ARG_EXTENDED_REGISTER 0xc1
327 #define ARG_EXTEND_SHIFT 0x07
328 #define ARG_EXTEND_MODE 0x38
329 #define ARG_EXTEND_UXTB 0x00
330 #define ARG_EXTEND_UXTH 0x08
331 #define ARG_EXTEND_UXTW 0x10
332 #define ARG_EXTEND_UXTX 0x18
333 #define ARG_EXTEND_SXTB 0x20
334 #define ARG_EXTEND_SXTH 0x28
335 #define ARG_EXTEND_SXTW 0x30
336 #define ARG_EXTEND_SXTX 0x38
337 #define ARG_ADDRESS_0 0xd0
338 #define ARG_ADDRESS_1 0xd1
339 #define ARG_ADDRESS_1_2 0xd2
340 #define ARG_ADDRESS_1_4 0xd3
341 #define ARG_ADDRESS_1_8 0xd4
342 #define ARG_ADDRESS_1_PRE_I 0xd5
343 #define ARG_ADDRESS_1_POST_I 0xd6
344 #define ARG_ADDRESS_2 0xd7
345 #define ARG_ADDRESS_2_2 0xd8
346 #define ARG_ADDRESS_2_4 0xd9
347 #define ARG_ADDRESS_2_8 0xda
348 #define ARG_ADDRESS_2_UXTW 0xdb
349 #define ARG_ADDRESS_2_SXTW 0xdc
350 #define ARG_IMM 0xe0
352 #define ARG_IS_ADDRESS(a) ((a) >= ARG_ADDRESS_0 && (a) <= ARG_ADDRESS_2_SXTW)
354 #ifdef POINTER_COMPRESSION
355 #define OP_SIZE_SLOT OP_SIZE_4
356 #else
357 #define OP_SIZE_SLOT OP_SIZE_ADDRESS
358 #endif
360 #define OP_SIZE_BITMAP (bitmap_64bit ? OP_SIZE_8 : OP_SIZE_4)
362 #define OP_SIZE_INT log_2(sizeof(int_default_t))
364 #define check_insn(insn) \
365 do { \
366 /*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));*/\
367 /*if (insn == 0x001a000e) internal(file_line, "invalid insn %08x", insn);*/\
368 } while (0)
370 #ifdef DEBUG_INSNS
371 #define gen_line() gen_four(__LINE__)
372 #else
373 #define gen_line() do { } while (0)
374 #endif
376 #ifdef ARCH_IA64
377 #define ARCH_CONTEXT struct { \
378 uint64_t insns[3]; \
379 uint8_t insn_units[3]; \
380 bool insn_stops[3]; \
381 uint64_t wr_mask[4]; \
383 #endif
385 #define gen_insn(opcode, op_size, aux, writes_flags) \
386 do { \
387 uint32_t dword = \
388 (uint32_t)(opcode) << INSN_OPCODE_SHIFT | \
389 (uint32_t)(op_size) << INSN_OP_SIZE_SHIFT | \
390 (uint32_t)(aux) << INSN_AUX_SHIFT | \
391 (uint32_t)(writes_flags) << INSN_WRITES_FLAGS_SHIFT; \
392 check_insn(dword); \
393 gen_line(); \
394 gen_four(dword); \
395 } while (0)
397 static size_t arg_size(uint8_t arg)
399 if (arg < ARG_REGS_MAX)
400 return 1;
401 if (arg >= ARG_SHIFTED_REGISTER && arg <= ARG_EXTENDED_REGISTER)
402 return 3;
403 if (arg == ARG_ADDRESS_0)
404 return 9;
405 if (arg >= ARG_ADDRESS_1 && arg <= ARG_ADDRESS_1_POST_I)
406 return 10;
407 if (arg >= ARG_ADDRESS_2 && arg <= ARG_ADDRESS_2_SXTW)
408 return 11;
409 if (arg == ARG_IMM)
410 return 9;
411 internal(file_line, "arg_size: invalid argument %02x", arg);
412 return 0;
415 struct relocation {
416 uint32_t label_id;
417 uint8_t length;
418 size_t position;
419 size_t jmp_instr;
422 struct code_arg {
423 frame_t slot;
424 frame_t flags;
425 frame_t type;
428 struct cg_entry {
429 size_t entry_to_pos;
430 frame_t *variables;
431 size_t n_variables;
432 uint32_t entry_label;
433 uint32_t nonflat_label;
436 struct cg_exit {
437 uint32_t undo_label;
438 uint8_t undo_opcode;
439 uint8_t undo_op_size;
440 uint8_t undo_aux;
441 uint8_t undo_writes_flags;
442 uint8_t undo_parameters[35];
443 uint8_t undo_parameters_len;
444 uint32_t escape_label;
447 struct codegen_context {
448 struct data *fn;
449 struct data **local_directory;
451 const code_t *instr_start;
452 const code_t *current_position;
453 uchar_efficient_t arg_mode;
455 uint32_t label_id;
456 struct cg_entry *entries;
457 frame_t n_entries;
459 uint8_t *code;
460 size_t code_size;
462 uint8_t *code_position;
464 uint32_t *code_labels;
465 struct cg_exit **code_exits;
466 uint32_t escape_nospill_label;
467 uint32_t call_label;
468 uint32_t reload_label;
470 uint8_t *mcode;
471 size_t mcode_size;
473 size_t *label_to_pos;
474 struct relocation *reloc;
475 size_t reloc_size;
477 struct trap_record *trap_records;
478 size_t trap_records_size;
480 struct code_arg *args;
481 size_t args_l;
482 const code_t *return_values;
484 int8_t *flag_cache;
485 short *registers;
486 frame_t *need_spill;
487 size_t need_spill_l;
489 unsigned base_reg;
490 bool offset_reg;
491 int64_t offset_imm;
493 bool const_reg;
494 int64_t const_imm;
496 struct data *codegen;
498 int upcall_args;
499 frame_t *var_aux;
501 ajla_error_t err;
503 #ifdef ARCH_CONTEXT
504 ARCH_CONTEXT a;
505 #endif
508 static void init_ctx(struct codegen_context *ctx)
510 ctx->local_directory = NULL;
511 ctx->label_id = 0;
512 ctx->entries = NULL;
513 ctx->n_entries = 0;
514 ctx->code = NULL;
515 ctx->code_labels = NULL;
516 ctx->code_exits = NULL;
517 ctx->escape_nospill_label = 0;
518 ctx->call_label = 0;
519 ctx->reload_label = 0;
520 ctx->mcode = NULL;
521 ctx->label_to_pos = NULL;
522 ctx->reloc = NULL;
523 ctx->trap_records = NULL;
524 ctx->args = NULL;
525 ctx->flag_cache = NULL;
526 ctx->registers = NULL;
527 ctx->need_spill = NULL;
528 ctx->codegen = NULL;
529 ctx->upcall_args = -1;
530 ctx->var_aux = NULL;
533 static void done_ctx(struct codegen_context *ctx)
535 if (ctx->local_directory)
536 mem_free(ctx->local_directory);
537 if (ctx->entries) {
538 size_t i;
539 for (i = 0; i < ctx->n_entries; i++) {
540 struct cg_entry *ce = &ctx->entries[i];
541 if (ce->variables)
542 mem_free(ce->variables);
544 mem_free(ctx->entries);
546 if (ctx->code)
547 mem_free(ctx->code);
548 if (ctx->code_labels)
549 mem_free(ctx->code_labels);
550 if (ctx->code_exits) {
551 ip_t ip;
552 ip_t cs = da(ctx->fn,function)->code_size;
553 for (ip = 0; ip < cs; ip++) {
554 if (ctx->code_exits[ip])
555 mem_free(ctx->code_exits[ip]);
557 mem_free(ctx->code_exits);
559 if (ctx->mcode)
560 mem_free(ctx->mcode);
561 if (ctx->label_to_pos)
562 mem_free(ctx->label_to_pos);
563 if (ctx->reloc)
564 mem_free(ctx->reloc);
565 if (ctx->trap_records)
566 mem_free(ctx->trap_records);
567 if (ctx->args)
568 mem_free(ctx->args);
569 if (ctx->flag_cache)
570 mem_free(ctx->flag_cache);
571 if (ctx->registers)
572 mem_free(ctx->registers);
573 if (ctx->need_spill)
574 mem_free(ctx->need_spill);
575 if (ctx->codegen)
576 data_free(ctx->codegen);
577 if (ctx->var_aux)
578 mem_free(ctx->var_aux);
582 static inline code_t get_code(struct codegen_context *ctx)
584 ajla_assert(ctx->current_position < da(ctx->fn,function)->code + da(ctx->fn,function)->code_size, (file_line, "get_code: ran out of code"));
585 return *ctx->current_position++;
588 static inline uint32_t get_uint32(struct codegen_context *ctx)
590 uint32_t a1 = get_code(ctx);
591 uint32_t a2 = get_code(ctx);
592 #if !CODE_ENDIAN
593 return a1 + (a2 << 16);
594 #else
595 return a2 + (a1 << 16);
596 #endif
599 static int32_t get_jump_offset(struct codegen_context *ctx)
601 if (SIZEOF_IP_T == 2) {
602 return (int32_t)(int16_t)get_code(ctx);
603 } else if (SIZEOF_IP_T == 4) {
604 return (int32_t)get_uint32(ctx);
605 } else {
606 not_reached();
607 return -1;
611 static inline void get_one(struct codegen_context *ctx, frame_t *v)
613 if (!ctx->arg_mode) {
614 code_t c = get_code(ctx);
615 ajla_assert(!(c & ~0xff), (file_line, "get_one: high byte is not cleared: %u", (unsigned)c));
616 *v = c & 0xff;
617 } else if (ctx->arg_mode == 1) {
618 *v = get_code(ctx);
619 #if ARG_MODE_N >= 2
620 } else if (ctx->arg_mode == 2) {
621 *v = get_uint32(ctx);
622 #endif
623 } else {
624 internal(file_line, "get_one: invalid arg mode %u", ctx->arg_mode);
628 static inline void get_two(struct codegen_context *ctx, frame_t *v1, frame_t *v2)
630 if (!ctx->arg_mode) {
631 code_t c = get_code(ctx);
632 *v1 = c & 0xff;
633 *v2 = c >> 8;
634 } else if (ctx->arg_mode == 1) {
635 *v1 = get_code(ctx);
636 *v2 = get_code(ctx);
637 #if ARG_MODE_N >= 2
638 } else if (ctx->arg_mode == 2) {
639 *v1 = get_uint32(ctx);
640 *v2 = get_uint32(ctx);
641 #endif
642 } else {
643 internal(file_line, "get_two: invalid arg mode %u", ctx->arg_mode);
648 static uint32_t alloc_label(struct codegen_context *ctx)
650 return ++ctx->label_id;
653 static struct cg_exit *alloc_cg_exit_for_ip(struct codegen_context *ctx, const code_t *code)
655 ip_t ip = code - da(ctx->fn,function)->code;
656 struct cg_exit *ce = ctx->code_exits[ip];
657 if (!ce) {
658 ce = mem_calloc_mayfail(struct cg_exit *, sizeof(struct cg_exit), &ctx->err);
659 if (unlikely(!ce))
660 return NULL;
661 ctx->code_exits[ip] = ce;
663 return ce;
666 static struct cg_exit *alloc_undo_label(struct codegen_context *ctx)
668 struct cg_exit *ce = alloc_cg_exit_for_ip(ctx, ctx->instr_start);
669 if (unlikely(!ce))
670 return NULL;
671 if (unlikely(ce->undo_label != 0))
672 internal(file_line, "alloc_cg_exit: undo label already allocated");
673 ce->undo_label = alloc_label(ctx);
674 if (unlikely(!ce->undo_label))
675 return NULL;
676 return ce;
679 static uint32_t alloc_escape_label_for_ip(struct codegen_context *ctx, const code_t *code)
681 struct cg_exit *ce = alloc_cg_exit_for_ip(ctx, code);
682 if (!ce)
683 return 0;
684 if (!ce->escape_label)
685 ce->escape_label = alloc_label(ctx);
686 return ce->escape_label;
689 static uint32_t alloc_escape_label(struct codegen_context *ctx)
691 return alloc_escape_label_for_ip(ctx, ctx->instr_start);
694 static uint32_t attr_unused alloc_call_label(struct codegen_context *ctx)
696 if (!ctx->call_label) {
697 ctx->call_label = alloc_label(ctx);
699 return ctx->call_label;
702 static uint32_t alloc_reload_label(struct codegen_context *ctx)
704 if (!ctx->reload_label) {
705 ctx->reload_label = alloc_label(ctx);
707 return ctx->reload_label;
710 static size_t attr_unused mark_params(struct codegen_context *ctx)
712 return ctx->code_size;
715 static void attr_unused copy_params(struct codegen_context *ctx, struct cg_exit *ce, size_t mark)
717 if (ctx->code_size - mark > n_array_elements(ce->undo_parameters))
718 internal(file_line, "undo_parameters is too small: %"PRIuMAX" > %"PRIuMAX"", (uintmax_t)(ctx->code_size - mark), (uintmax_t)n_array_elements(ce->undo_parameters));
719 memcpy(ce->undo_parameters, ctx->code + mark, ctx->code_size - mark);
720 ce->undo_parameters_len = ctx->code_size - mark;
721 ctx->code_size = mark;
724 #define g(call) \
725 do { \
726 if (unlikely(!call)) \
727 return false; \
728 } while (0)
730 #define gen_one(byte) \
731 do { \
732 /*debug("gen %d: %02x", __LINE__, (uint8_t)(byte))*/; \
733 if (unlikely(!array_add_mayfail(uint8_t, &ctx->code, &ctx->code_size, byte, NULL, &ctx->err)))\
734 return false; \
735 } while (0)
737 #if defined(C_LITTLE_ENDIAN)
738 #define gen_two(word) \
739 do { \
740 uint16_t word_ = (word); \
741 /*debug("gen %d: %04x", __LINE__, (uint16_t)(word_));*/ \
742 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
743 return false; \
744 } while (0)
745 #define gen_four(dword) \
746 do { \
747 uint32_t dword_ = (dword); \
748 /*debug("gen %d: %08x", __LINE__, (uint32_t)(dword_));*/ \
749 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
750 return false; \
751 } while (0)
752 #define gen_eight(qword) \
753 do { \
754 uint64_t qword_ = (qword); \
755 /*debug("gen %d: %016lx", __LINE__, (uint64_t)(qword_));*/ \
756 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
757 return false; \
758 } while (0)
759 #else
760 #define gen_two(word) \
761 do { \
762 uint16_t word_ = (word); \
763 gen_one(word_ & 0xffU); \
764 gen_one(word_ >> 8); \
765 } while (0)
766 #define gen_four(dword) \
767 do { \
768 uint32_t dword_ = (dword); \
769 gen_two(dword_ & 0xffffU); \
770 gen_two(dword_ >> 15 >> 1); \
771 } while (0)
772 #define gen_eight(qword) \
773 do { \
774 uint64_t qword_ = (qword); \
775 gen_four(qword_ & 0xffffffffUL); \
776 gen_four(qword_ >> 15 >> 15 >> 2); \
777 } while (0)
778 #endif
780 #define gen_label(label_id) \
781 do { \
782 gen_insn(INSN_LABEL, 0, 0, 0); \
783 gen_four(label_id); \
784 } while (0)
787 static uint8_t attr_unused cget_one(struct codegen_context *ctx)
789 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_one: ran out of code"));
790 return *ctx->code_position++;
793 static uint16_t attr_unused cget_two(struct codegen_context *ctx)
795 #if defined(C_LITTLE_ENDIAN)
796 uint16_t r;
797 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_two: ran out of code"));
798 memcpy(&r, ctx->code_position, 2);
799 ctx->code_position += 2;
800 return r;
801 #else
802 uint16_t r = cget_one(ctx);
803 r |= cget_one(ctx) << 8;
804 return r;
805 #endif
808 static uint32_t cget_four(struct codegen_context *ctx)
810 #if defined(C_LITTLE_ENDIAN)
811 uint32_t r;
812 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_four: ran out of code"));
813 memcpy(&r, ctx->code_position, 4);
814 ctx->code_position += 4;
815 return r;
816 #else
817 uint32_t r = cget_two(ctx);
818 r |= (uint32_t)cget_two(ctx) << 16;
819 return r;
820 #endif
823 static uint64_t attr_unused cget_eight(struct codegen_context *ctx)
825 #if defined(C_LITTLE_ENDIAN)
826 uint64_t r;
827 ajla_assert(ctx->code_position < ctx->code + ctx->code_size, (file_line, "cget_eight: ran out of code"));
828 memcpy(&r, ctx->code_position, 8);
829 ctx->code_position += 8;
830 return r;
831 #else
832 uint64_t r = cget_four(ctx);
833 r |= (uint64_t)cget_four(ctx) << 32;
834 return r;
835 #endif
838 static int64_t get_imm(uint8_t *ptr)
840 #if defined(C_LITTLE_ENDIAN)
841 int64_t r;
842 memcpy(&r, ptr, 8);
843 return r;
844 #else
845 int64_t r;
846 r = (uint64_t)ptr[0] |
847 ((uint64_t)ptr[1] << 8) |
848 ((uint64_t)ptr[2] << 16) |
849 ((uint64_t)ptr[3] << 24) |
850 ((uint64_t)ptr[4] << 32) |
851 ((uint64_t)ptr[5] << 40) |
852 ((uint64_t)ptr[6] << 48) |
853 ((uint64_t)ptr[7] << 56);
854 return r;
855 #endif
858 #define cgen_one(byte) \
859 do { \
860 if (unlikely(!array_add_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, byte, NULL, &ctx->err)))\
861 return false; \
862 } while (0)
864 #if defined(C_LITTLE_ENDIAN) || 1
865 #define cgen_two(word) \
866 do { \
867 uint16_t word_ = (word); \
868 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
869 return false; \
870 } while (0)
871 #define cgen_four(dword) \
872 do { \
873 uint32_t dword_ = (dword); \
874 /*if (dword_ == 0x1ee02000) internal(file_line, "invalid instruction");*/\
875 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
876 return false; \
877 } while (0)
878 #define cgen_eight(qword) \
879 do { \
880 uint64_t qword_ = (qword); \
881 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
882 return false; \
883 } while (0)
884 #else
885 #define cgen_two(word) \
886 do { \
887 cgen_one((word) & 0xff); \
888 cgen_one((word) >> 8); \
889 } while (0)
890 #define cgen_four(dword) \
891 do { \
892 cgen_two((dword) & 0xffff); \
893 cgen_two((dword) >> 15 >> 1); \
894 } while (0)
895 #define cgen_eight(qword) \
896 do { \
897 cgen_four((qword) & 0xffffffff); \
898 cgen_four((qword) >> 15 >> 15 >> 2); \
899 } while (0)
900 #endif
903 #define IMM_PURPOSE_LDR_OFFSET 1
904 #define IMM_PURPOSE_LDR_SX_OFFSET 2
905 #define IMM_PURPOSE_STR_OFFSET 3
906 #define IMM_PURPOSE_LDP_STP_OFFSET 4
907 #define IMM_PURPOSE_VLDR_VSTR_OFFSET 5
908 #define IMM_PURPOSE_MVI_CLI_OFFSET 6
909 #define IMM_PURPOSE_STORE_VALUE 7
910 #define IMM_PURPOSE_ADD 8
911 #define IMM_PURPOSE_SUB 9
912 #define IMM_PURPOSE_CMP 10
913 #define IMM_PURPOSE_CMP_LOGICAL 11
914 #define IMM_PURPOSE_AND 12
915 #define IMM_PURPOSE_OR 13
916 #define IMM_PURPOSE_XOR 14
917 #define IMM_PURPOSE_ANDN 15
918 #define IMM_PURPOSE_TEST 16
919 #define IMM_PURPOSE_JMP_2REGS 17
920 #define IMM_PURPOSE_MUL 18
921 #define IMM_PURPOSE_CMOV 19
922 #define IMM_PURPOSE_MOVR 20
923 #define IMM_PURPOSE_BITWISE 21
926 static bool attr_w gen_upcall_end(struct codegen_context *ctx, unsigned args);
928 #define gen_address_offset() \
929 do { \
930 if (likely(!ctx->offset_reg)) { \
931 gen_one(ARG_ADDRESS_1); \
932 gen_one(ctx->base_reg); \
933 gen_eight(ctx->offset_imm); \
934 } else { \
935 gen_one(ARG_ADDRESS_2); \
936 gen_one(ctx->base_reg); \
937 gen_one(R_OFFSET_IMM); \
938 gen_eight(0); \
940 } while (0)
942 #define gen_imm_offset() \
943 do { \
944 if (likely(!ctx->const_reg)) { \
945 gen_one(ARG_IMM); \
946 gen_eight(ctx->const_imm); \
947 } else { \
948 gen_one(R_CONST_IMM); \
950 } while (0)
952 #define is_imm() (!ctx->const_reg)
955 #if defined(ARCH_ALPHA)
956 #include "c1-alpha.inc"
957 #elif defined(ARCH_ARM32)
958 #include "c1-arm.inc"
959 #elif defined(ARCH_ARM64)
960 #include "c1-arm64.inc"
961 #elif defined(ARCH_IA64)
962 #include "c1-ia64.inc"
963 #elif defined(ARCH_LOONGARCH64)
964 #include "c1-loong.inc"
965 #elif defined(ARCH_MIPS)
966 #include "c1-mips.inc"
967 #elif defined(ARCH_PARISC)
968 #include "c1-hppa.inc"
969 #elif defined(ARCH_POWER)
970 #include "c1-power.inc"
971 #elif defined(ARCH_S390)
972 #include "c1-s390.inc"
973 #elif defined(ARCH_SPARC)
974 #include "c1-sparc.inc"
975 #elif defined(ARCH_RISCV64)
976 #include "c1-riscv.inc"
977 #elif defined(ARCH_X86)
978 #include "c1-x86.inc"
979 #endif
982 #ifndef ARCH_SUPPORTS_TRAPS
983 #define ARCH_SUPPORTS_TRAPS 0
984 #define ARCH_TRAP_BEFORE 0
985 #endif
988 #include "cg-util.inc"
990 #include "cg-frame.inc"
992 #include "cg-flags.inc"
994 #include "cg-flcch.inc"
996 #include "cg-ptr.inc"
998 #include "cg-alu.inc"
1000 #include "cg-ops.inc"
1003 #ifndef n_regs_saved
1004 #define n_regs_saved n_array_elements(regs_saved)
1005 #endif
1007 #ifndef n_regs_volatile
1008 #define n_regs_volatile n_array_elements(regs_volatile)
1009 #endif
1011 #ifndef n_fp_saved
1012 #define n_fp_saved n_array_elements(fp_saved)
1013 #endif
1015 #ifndef n_fp_volatile
1016 #define n_fp_volatile n_array_elements(fp_volatile)
1017 #endif
1019 #ifndef n_vector_volatile
1020 #define n_vector_volatile n_array_elements(vector_volatile)
1021 #endif
1023 static bool attr_w gen_registers(struct codegen_context *ctx)
1025 frame_t v;
1026 size_t index_saved = 0;
1027 size_t index_volatile = 0;
1028 size_t index_fp_saved = 0;
1029 size_t index_fp_volatile = 0;
1030 size_t attr_unused index_vector_volatile = 0;
1031 #ifdef ARCH_S390
1032 bool uses_x = false;
1033 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
1034 const struct type *t = get_type_of_local(ctx, v);
1035 if (t && TYPE_TAG_IS_REAL(t->tag) && TYPE_TAG_IDX_REAL(t->tag) == 4) {
1036 uses_x = true;
1037 break;
1040 #endif
1041 /*for (v = function_n_variables(ctx->fn) - 1; v >= MIN_USEABLE_SLOT; v--)*/
1042 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
1043 const struct type *t;
1044 ctx->registers[v] = -1;
1045 if (ra_chicken)
1046 continue;
1047 t = get_type_of_local(ctx, v);
1048 if (unlikely(!t))
1049 continue;
1050 if (!da(ctx->fn,function)->local_variables_flags[v].must_be_flat)
1051 continue;
1052 if (!ARCH_HAS_BWX && t->size < 1U << OP_SIZE_4)
1053 continue;
1054 if (TYPE_TAG_IS_FIXED(t->tag) || TYPE_TAG_IS_INT(t->tag) || t->tag == TYPE_TAG_flat_option) {
1055 if (!is_power_of_2(t->size) || t->size > 1U << OP_SIZE_NATIVE)
1056 continue;
1057 if (index_saved < n_regs_saved + zero
1058 #if defined(ARCH_PARISC) || defined(ARCH_SPARC)
1059 && t->size <= 1U << OP_SIZE_ADDRESS
1060 #endif
1062 ctx->registers[v] = regs_saved[index_saved++];
1063 } else if (index_volatile < n_regs_volatile + zero) {
1064 ctx->registers[v] = regs_volatile[index_volatile++];
1065 } else {
1066 continue;
1068 } else if (TYPE_TAG_IS_REAL(t->tag)) {
1069 unsigned real_type = TYPE_TAG_IDX_REAL(t->tag);
1070 if ((SUPPORTED_FP >> real_type) & 1) {
1071 #ifdef ARCH_POWER
1072 if (real_type == 4) {
1073 if (index_vector_volatile < n_vector_volatile + zero) {
1074 ctx->registers[v] = vector_volatile[index_vector_volatile++];
1075 goto success;
1077 continue;
1079 #endif
1080 #ifdef ARCH_S390
1081 if (real_type == 4) {
1082 if (!(index_fp_saved & 1) && index_fp_saved + 1 < n_fp_saved + zero) {
1083 ctx->registers[v] = fp_saved[index_fp_saved++];
1084 index_fp_saved++;
1085 goto success;
1087 if (index_fp_saved & 1 && index_fp_saved + 2 < n_fp_saved + zero) {
1088 index_fp_saved++;
1089 ctx->registers[v] = fp_saved[index_fp_saved++];
1090 index_fp_saved++;
1091 goto success;
1093 if (!(index_fp_volatile & 1) && index_fp_volatile + 1 < n_fp_volatile + zero) {
1094 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1095 index_fp_volatile++;
1096 goto success;
1098 if (index_fp_volatile & 1 && index_fp_volatile + 2 < n_fp_volatile + zero) {
1099 index_fp_volatile++;
1100 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1101 index_fp_volatile++;
1102 goto success;
1104 continue;
1106 #endif
1107 if (index_fp_saved < n_fp_saved + zero) {
1108 ctx->registers[v] = fp_saved[index_fp_saved++];
1109 } else if (index_fp_volatile < n_fp_volatile + zero) {
1110 ctx->registers[v] = fp_volatile[index_fp_volatile++];
1111 } else {
1112 continue;
1114 } else {
1115 continue;
1117 } else {
1118 continue;
1120 goto success;
1121 success:
1122 if (!reg_is_saved(ctx->registers[v])) {
1123 if (unlikely(!array_add_mayfail(frame_t, &ctx->need_spill, &ctx->need_spill_l, v, NULL, &ctx->err)))
1124 return false;
1128 return true;
1131 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)
1133 const code_t *backup = ctx->current_position;
1134 code_t code;
1135 frame_t slot_dr, slot_test;
1136 int32_t offs_false;
1138 *failed = false;
1140 next_code:
1141 code = get_code(ctx);
1142 ctx->arg_mode = code / OPCODE_MODE_MULT;
1143 code %= OPCODE_MODE_MULT;
1144 ajla_assert_lo(ctx->arg_mode < ARG_MODE_N, (file_line, "gen_fused_binary: invalid opcode %04x", (unsigned)*ctx->instr_start));
1146 if (code == OPCODE_DEREFERENCE) {
1147 get_one(ctx, &slot_dr);
1148 const struct type *t = get_type_of_local(ctx, slot_dr);
1149 if (!TYPE_TAG_IS_BUILTIN(t->tag)) {
1150 *failed = true;
1151 goto fail;
1153 if (unlikely(!flag_is_clear(ctx, slot_dr))) {
1154 *failed = true;
1155 goto fail;
1157 goto next_code;
1159 if (code == OPCODE_DEREFERENCE_CLEAR) {
1160 *failed = true;
1161 goto fail;
1163 if (unlikely(code != OPCODE_JMP_FALSE))
1164 internal(file_line, "gen_fused_binary: binary operation is not followed by jmp false: %x, %s", code, decode_opcode(code, true));
1165 get_one(ctx, &slot_test);
1166 if (unlikely(slot_test != slot_r))
1167 internal(file_line, "gen_fused_binary: the result of the binary operation and the tested variable do not match");
1168 offs_false = get_jump_offset(ctx);
1169 get_jump_offset(ctx);
1171 if (mode == MODE_ARRAY_LEN_GT) {
1172 g(gen_array_len(ctx, slot_1, slot_2, slot_r, true, offs_false));
1173 } else if (mode == MODE_REAL) {
1174 g(gen_fp_alu_jmp(ctx, op_size, op, escape_label, slot_1, slot_2, offs_false, failed));
1175 } else {
1176 g(gen_alu_jmp(ctx, mode, op_size, op, slot_1, slot_2, offs_false, failed));
1179 fail:
1180 if (*failed)
1181 ctx->current_position = backup;
1183 return true;
1186 static bool attr_w gen_function(struct codegen_context *ctx)
1188 ctx->current_position = da(ctx->fn,function)->code;
1190 ctx->escape_nospill_label = alloc_label(ctx);
1191 if (unlikely(!ctx->escape_nospill_label))
1192 return false;
1194 while (ctx->current_position != da(ctx->fn,function)->code + da(ctx->fn,function)->code_size) {
1195 ip_t ip;
1196 code_t code;
1197 unsigned op, type;
1198 frame_t slot_1, slot_2, slot_3, slot_r, flags, fn_idx, opt;
1199 arg_t n_args, n_ret, i_arg;
1200 uint32_t label_id;
1201 uint32_t escape_label;
1202 bool failed;
1204 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));
1206 ctx->instr_start = ctx->current_position;
1208 /*debug("%s: %04x, %s", da(ctx->fn,function)->function_name, *ctx->instr_start, decode_opcode(*ctx->instr_start, true));*/
1210 ip = ctx->instr_start - da(ctx->fn,function)->code;
1211 if (likely(!ctx->code_labels[ip])) {
1212 ctx->code_labels[ip] = alloc_label(ctx);
1213 if (unlikely(!ctx->code_labels[ip]))
1214 return false;
1216 gen_label(ctx->code_labels[ip]);
1218 code = get_code(ctx);
1219 ctx->arg_mode = code / OPCODE_MODE_MULT;
1220 code %= OPCODE_MODE_MULT;
1221 ajla_assert_lo(ctx->arg_mode < ARG_MODE_N, (file_line, "gen_function: invalid opcode %04x", (unsigned)*ctx->instr_start));
1223 if (code >= OPCODE_FIXED_OP + uzero && code < OPCODE_INT_OP) {
1224 code -= OPCODE_FIXED_OP;
1225 op = (code / OPCODE_FIXED_OP_MULT) % OPCODE_FIXED_TYPE_MULT;
1226 type = code / OPCODE_FIXED_TYPE_MULT;
1227 if (op < OPCODE_FIXED_OP_UNARY) {
1228 get_two(ctx, &slot_1, &slot_2);
1229 get_two(ctx, &slot_r, &flags);
1230 escape_label = alloc_escape_label(ctx);
1231 if (unlikely(!escape_label))
1232 return false;
1233 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1234 flag_set(ctx, slot_1, false);
1235 flag_set(ctx, slot_2, false);
1236 flag_set(ctx, slot_r, false);
1237 if (flags & OPCODE_FLAG_FUSED) {
1238 g(gen_fused_binary(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1239 if (unlikely(!failed))
1240 continue;
1242 g(gen_alu(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_2, slot_r));
1243 continue;
1244 } else if (op < OPCODE_FIXED_OP_N) {
1245 get_two(ctx, &slot_1, &slot_r);
1246 get_one(ctx, &flags);
1247 escape_label = alloc_escape_label(ctx);
1248 if (unlikely(!escape_label))
1249 return false;
1250 g(gen_test_1_cached(ctx, slot_1, escape_label));
1251 flag_set(ctx, slot_1, false);
1252 flag_set(ctx, slot_r, false);
1253 g(gen_alu1(ctx, MODE_FIXED, type, op, escape_label, slot_1, slot_r));
1254 continue;
1255 } else if (op == OPCODE_FIXED_OP_ldc) {
1256 unsigned i;
1257 get_one(ctx, &slot_r);
1258 g(gen_constant(ctx, false, type, false, slot_r));
1259 for (i = 0; i < 1U << type; i += 2)
1260 get_code(ctx);
1261 flag_set(ctx, slot_r, false);
1262 continue;
1263 } else if (op == OPCODE_FIXED_OP_ldc16) {
1264 get_one(ctx, &slot_r);
1265 g(gen_constant(ctx, false, type, true, slot_r));
1266 get_code(ctx);
1267 flag_set(ctx, slot_r, false);
1268 continue;
1269 } else if (op == OPCODE_FIXED_OP_move || op == OPCODE_FIXED_OP_copy) {
1270 get_two(ctx, &slot_1, &slot_r);
1271 escape_label = alloc_escape_label(ctx);
1272 if (unlikely(!escape_label))
1273 return false;
1274 g(gen_test_1_cached(ctx, slot_1, escape_label));
1275 flag_set(ctx, slot_1, false);
1276 flag_set(ctx, slot_r, false);
1277 g(gen_copy(ctx, type, slot_1, slot_r));
1278 continue;
1279 } else {
1280 internal(file_line, "gen_function: bad fixed code %04x", *ctx->instr_start);
1282 } else if (code >= OPCODE_INT_OP && code < OPCODE_REAL_OP) {
1283 code -= OPCODE_INT_OP;
1284 op = (code / OPCODE_INT_OP_MULT) % OPCODE_INT_TYPE_MULT;
1285 type = code / OPCODE_INT_TYPE_MULT;
1286 if (op < OPCODE_INT_OP_UNARY) {
1287 get_two(ctx, &slot_1, &slot_2);
1288 get_two(ctx, &slot_r, &flags);
1289 escape_label = alloc_escape_label(ctx);
1290 if (unlikely(!escape_label))
1291 return false;
1292 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1293 flag_set(ctx, slot_1, false);
1294 flag_set(ctx, slot_2, false);
1295 flag_set(ctx, slot_r, false);
1296 if (flags & OPCODE_FLAG_FUSED) {
1297 g(gen_fused_binary(ctx, MODE_INT, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1298 if (unlikely(!failed))
1299 continue;
1301 g(gen_alu(ctx, MODE_INT, type, op, escape_label, slot_1, slot_2, slot_r));
1302 continue;
1303 } else if (op < OPCODE_INT_OP_N) {
1304 get_two(ctx, &slot_1, &slot_r);
1305 get_one(ctx, &flags);
1306 if ((op == OPCODE_INT_OP_to_int || op == OPCODE_INT_OP_from_int) && slot_1 == slot_r)
1307 continue;
1308 escape_label = alloc_escape_label(ctx);
1309 if (unlikely(!escape_label))
1310 return false;
1311 g(gen_test_1_cached(ctx, slot_1, escape_label));
1312 flag_set(ctx, slot_1, false);
1313 flag_set(ctx, slot_r, false);
1314 g(gen_alu1(ctx, MODE_INT, type, op, escape_label, slot_1, slot_r));
1315 continue;
1316 } else if (op == OPCODE_INT_OP_ldc) {
1317 unsigned i;
1318 get_one(ctx, &slot_r);
1319 g(gen_constant(ctx, false, type, false, slot_r));
1320 for (i = 0; i < 1U << type; i += 2)
1321 get_code(ctx);
1322 flag_set(ctx, slot_r, false);
1323 continue;
1324 } else if (op == OPCODE_INT_OP_ldc16) {
1325 get_one(ctx, &slot_r);
1326 g(gen_constant(ctx, false, type, true, slot_r));
1327 get_code(ctx);
1328 flag_set(ctx, slot_r, false);
1329 continue;
1330 } else if (op == OPCODE_INT_OP_move || op == OPCODE_INT_OP_copy) {
1331 get_two(ctx, &slot_1, &slot_r);
1332 escape_label = alloc_escape_label(ctx);
1333 if (unlikely(!escape_label))
1334 return false;
1335 g(gen_test_1_cached(ctx, slot_1, escape_label));
1336 flag_set(ctx, slot_1, false);
1337 flag_set(ctx, slot_r, false);
1338 g(gen_copy(ctx, type, slot_1, slot_r));
1339 continue;
1340 } else {
1341 internal(file_line, "gen_function: bad integer code %04x", *ctx->instr_start);
1343 } else if (code >= OPCODE_REAL_OP && code < OPCODE_BOOL_OP) {
1344 code -= OPCODE_REAL_OP;
1345 op = (code / OPCODE_REAL_OP_MULT) % OPCODE_REAL_TYPE_MULT;
1346 type = code / OPCODE_REAL_TYPE_MULT;
1347 if (op < OPCODE_REAL_OP_UNARY) {
1348 get_two(ctx, &slot_1, &slot_2);
1349 get_two(ctx, &slot_r, &flags);
1350 escape_label = alloc_escape_label(ctx);
1351 if (unlikely(!escape_label))
1352 return false;
1353 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1354 flag_set(ctx, slot_1, false);
1355 flag_set(ctx, slot_2, false);
1356 flag_set(ctx, slot_r, false);
1357 if (flags & OPCODE_FLAG_FUSED) {
1358 g(gen_fused_binary(ctx, MODE_REAL, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1359 if (unlikely(!failed))
1360 continue;
1362 g(gen_fp_alu(ctx, type, op, escape_label, slot_1, slot_2, slot_r));
1363 continue;
1364 } else if (op < OPCODE_REAL_OP_N) {
1365 get_two(ctx, &slot_1, &slot_r);
1366 get_one(ctx, &flags);
1367 escape_label = alloc_escape_label(ctx);
1368 if (unlikely(!escape_label))
1369 return false;
1370 g(gen_test_1_cached(ctx, slot_1, escape_label));
1371 flag_set(ctx, slot_1, false);
1372 flag_set(ctx, slot_r, false);
1373 g(gen_fp_alu1(ctx, type, op, escape_label, slot_1, slot_r));
1374 continue;
1375 } else if (op == OPCODE_REAL_OP_ldc) {
1376 const struct type *t;
1377 unsigned i;
1378 get_one(ctx, &slot_r);
1379 t = type_get_real(type);
1380 g(gen_real_constant(ctx, t, slot_r));
1381 for (i = 0; i < t->size; i += 2)
1382 get_code(ctx);
1383 flag_set(ctx, slot_r, false);
1384 continue;
1385 } else if (op == OPCODE_REAL_OP_move || op == OPCODE_REAL_OP_copy) {
1386 get_two(ctx, &slot_1, &slot_r);
1387 escape_label = alloc_escape_label(ctx);
1388 if (unlikely(!escape_label))
1389 return false;
1390 g(gen_test_1_cached(ctx, slot_1, escape_label));
1391 flag_set(ctx, slot_1, false);
1392 flag_set(ctx, slot_r, false);
1393 g(gen_memcpy_slots(ctx, slot_r, slot_1));
1394 continue;
1395 } else {
1396 internal(file_line, "gen_function: bad real code %04x", *ctx->instr_start);
1398 } else if (code >= OPCODE_BOOL_OP && code < OPCODE_EXTRA) {
1399 code -= OPCODE_BOOL_OP;
1400 op = (code / OPCODE_BOOL_OP_MULT) % OPCODE_BOOL_TYPE_MULT;
1401 type = log_2(sizeof(ajla_flat_option_t));
1402 if (op < OPCODE_BOOL_OP_UNARY) {
1403 get_two(ctx, &slot_1, &slot_2);
1404 get_two(ctx, &slot_r, &flags);
1405 escape_label = alloc_escape_label(ctx);
1406 if (unlikely(!escape_label))
1407 return false;
1408 g(gen_test_2_cached(ctx, slot_1, slot_2, escape_label));
1409 flag_set(ctx, slot_1, false);
1410 flag_set(ctx, slot_2, false);
1411 flag_set(ctx, slot_r, false);
1412 if (flags & OPCODE_FLAG_FUSED) {
1413 g(gen_fused_binary(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_2, slot_r, &failed));
1414 if (unlikely(!failed))
1415 continue;
1417 g(gen_alu(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_2, slot_r));
1418 continue;
1419 } else if (op < OPCODE_BOOL_OP_N) {
1420 get_two(ctx, &slot_1, &slot_r);
1421 get_one(ctx, &flags);
1422 escape_label = alloc_escape_label(ctx);
1423 if (unlikely(!escape_label))
1424 return false;
1425 g(gen_test_1_cached(ctx, slot_1, escape_label));
1426 flag_set(ctx, slot_1, false);
1427 flag_set(ctx, slot_r, false);
1428 g(gen_alu1(ctx, MODE_BOOL, type, op, escape_label, slot_1, slot_r));
1429 continue;
1430 } else if (op == OPCODE_BOOL_OP_move || op == OPCODE_BOOL_OP_copy) {
1431 get_two(ctx, &slot_1, &slot_r);
1432 escape_label = alloc_escape_label(ctx);
1433 if (unlikely(!escape_label))
1434 return false;
1435 g(gen_test_1_cached(ctx, slot_1, escape_label));
1436 flag_set(ctx, slot_1, false);
1437 flag_set(ctx, slot_r, false);
1438 g(gen_copy(ctx, type, slot_1, slot_r));
1439 continue;
1440 } else {
1441 internal(file_line, "gen_function: bad boolean code %04x", *ctx->instr_start);
1443 } else switch (code) {
1444 case OPCODE_INT_LDC_LONG: {
1445 uint32_t words, w;
1446 get_one(ctx, &slot_r);
1447 words = get_uint32(ctx);
1448 for (w = 0; w < words; w++)
1449 get_code(ctx);
1450 unconditional_escape:
1451 escape_label = alloc_escape_label(ctx);
1452 if (unlikely(!escape_label))
1453 return false;
1454 gen_insn(INSN_JMP, 0, 0, 0);
1455 gen_four(escape_label);
1456 continue;
1458 case OPCODE_IS_EXCEPTION: {
1459 get_two(ctx, &slot_1, &slot_r);
1460 get_one(ctx, &flags);
1461 g(gen_is_exception(ctx, slot_1, slot_r));
1462 continue;
1464 case OPCODE_EXCEPTION_CLASS:
1465 case OPCODE_EXCEPTION_TYPE:
1466 case OPCODE_EXCEPTION_AUX: {
1467 get_two(ctx, &slot_1, &slot_r);
1468 get_one(ctx, &flags);
1469 goto unconditional_escape;
1471 case OPCODE_SYSTEM_PROPERTY: {
1472 get_two(ctx, &slot_1, &slot_r);
1473 get_one(ctx, &flags);
1474 g(gen_system_property(ctx, slot_1, slot_r));
1475 continue;
1477 case OPCODE_FLAT_MOVE:
1478 case OPCODE_FLAT_COPY: {
1479 get_two(ctx, &slot_1, &slot_r);
1480 g(gen_flat_move_copy(ctx, slot_1, slot_r));
1481 continue;
1483 case OPCODE_REF_MOVE:
1484 case OPCODE_REF_MOVE_CLEAR:
1485 case OPCODE_REF_COPY: {
1486 get_two(ctx, &slot_1, &slot_r);
1487 g(gen_ref_move_copy(ctx, code, slot_1, slot_r));
1488 continue;
1490 case OPCODE_BOX_MOVE_CLEAR:
1491 case OPCODE_BOX_COPY: {
1492 get_two(ctx, &slot_1, &slot_r);
1493 g(gen_box_move_copy(ctx, code, slot_1, slot_r));
1494 continue;
1496 case OPCODE_TAKE_BORROWED:
1497 get_one(ctx, &slot_1);
1498 if (!da(ctx->fn,function)->local_variables_flags[slot_1].may_be_borrowed)
1499 continue;
1500 if (unlikely(!(label_id = alloc_label(ctx))))
1501 return false;
1502 if (flag_is_set(ctx, slot_1))
1503 goto take_borrowed_done;
1504 if (flag_is_clear(ctx, slot_1)) {
1505 g(gen_set_1(ctx, R_FRAME, slot_1, 0, true));
1506 goto do_take_borrowed;
1508 g(gen_test_1(ctx, R_FRAME, slot_1, 0, label_id, false, TEST_SET));
1509 do_take_borrowed:
1510 g(gen_upcall_start(ctx, 1));
1511 g(gen_frame_load(ctx, OP_SIZE_SLOT, garbage, slot_1, 0, R_ARG0));
1512 g(gen_upcall_argument(ctx, 0));
1513 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_pointer_reference_owned), 1));
1514 flag_set(ctx, slot_1, true);
1515 take_borrowed_done:
1516 gen_label(label_id);
1517 continue;
1518 case OPCODE_DEREFERENCE:
1519 case OPCODE_DEREFERENCE_CLEAR: {
1520 bool need_bit_test;
1521 /*const struct type *type;*/
1522 get_one(ctx, &slot_1);
1523 if (flag_is_clear(ctx, slot_1))
1524 goto skip_dereference;
1525 /*type = get_type_of_local(ctx, slot_1);*/
1526 /*need_bit_test = 1 || TYPE_IS_FLAT(type) || da(ctx->fn,function)->local_variables[slot_1].may_be_borrowed;*/
1527 need_bit_test = !flag_is_set(ctx, slot_1);
1528 if (need_bit_test) {
1529 if (unlikely(!(label_id = alloc_label(ctx))))
1530 return false;
1531 g(gen_test_1(ctx, R_FRAME, slot_1, 0, label_id, true, TEST_CLEAR));
1532 } else {
1533 g(gen_set_1(ctx, R_FRAME, slot_1, 0, false));
1534 label_id = 0; /* avoid warning */
1536 g(gen_upcall_start(ctx, 1));
1537 g(gen_frame_load(ctx, OP_SIZE_SLOT, garbage, slot_1, 0, R_ARG0));
1538 g(gen_upcall_argument(ctx, 0));
1539 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_pointer_dereference), 1));
1540 if (need_bit_test)
1541 gen_label(label_id);
1542 skip_dereference:
1543 if (code == OPCODE_DEREFERENCE_CLEAR)
1544 g(gen_frame_clear(ctx, OP_SIZE_SLOT, slot_1));
1545 flag_set(ctx, slot_1, false);
1546 continue;
1548 case OPCODE_EVAL: {
1549 get_one(ctx, &slot_1);
1550 g(gen_eval(ctx, slot_1));
1551 continue;
1553 case OPCODE_ESCAPE_NONFLAT: {
1554 frame_t n, i;
1555 frame_t *vars;
1557 get_one(ctx, &n);
1558 vars = mem_alloc_array_mayfail(mem_alloc_mayfail, frame_t *, 0, 0, n, sizeof(frame_t), &ctx->err);
1559 if (unlikely(!vars))
1560 return false;
1561 for (i = 0; i < n; i++) {
1562 get_one(ctx, &vars[i]);
1565 escape_label = alloc_escape_label(ctx);
1566 if (unlikely(!escape_label)) {
1567 mem_free(vars);
1568 return false;
1571 if (unlikely(!gen_test_multiple(ctx, vars, n, escape_label))) {
1572 mem_free(vars);
1573 return false;
1575 mem_free(vars);
1577 continue;
1579 case OPCODE_CHECKPOINT: {
1580 frame_t n_vars;
1582 g(clear_flag_cache(ctx));
1584 if (SIZEOF_IP_T == 2) {
1585 slot_1 = get_code(ctx);
1586 } else if (SIZEOF_IP_T == 4) {
1587 slot_1 = get_uint32(ctx);
1588 } else {
1589 not_reached();
1590 continue;
1593 if (unlikely(!(slot_1 + 1)))
1594 return false;
1595 while (slot_1 >= ctx->n_entries) {
1596 void *err_entries;
1597 struct cg_entry e;
1598 if (unlikely(!ctx->entries)) {
1599 if (unlikely(!array_init_mayfail(struct cg_entry, &ctx->entries, &ctx->n_entries, &ctx->err)))
1600 return false;
1602 memset(&e, 0, sizeof(struct cg_entry));
1603 if (unlikely(!array_add_mayfail(struct cg_entry, &ctx->entries, &ctx->n_entries, e, &err_entries, &ctx->err))) {
1604 ctx->entries = err_entries;
1605 return false;
1609 get_one(ctx, &n_vars);
1611 escape_label = 0; /* avoid warning */
1612 if (likely(slot_1 != 0)) {
1613 escape_label = alloc_escape_label(ctx);
1614 if (unlikely(!escape_label))
1615 return false;
1618 if (n_vars || !slot_1) {
1619 frame_t i;
1620 uint32_t entry_label, nonflat_label;
1621 struct cg_entry *ce = &ctx->entries[slot_1];
1623 if (unlikely(!array_init_mayfail(frame_t, &ce->variables, &ce->n_variables, &ctx->err)))
1624 return false;
1625 for (i = 0; i < n_vars; i++) {
1626 frame_t v;
1627 get_one(ctx, &v);
1628 if (unlikely(!array_add_mayfail(frame_t, &ce->variables, &ce->n_variables, v, NULL, &ctx->err)))
1629 return false;
1631 if (!slot_1) {
1632 g(gen_test_multiple(ctx, ce->variables, ce->n_variables, ctx->escape_nospill_label));
1634 entry_label = alloc_label(ctx);
1635 if (unlikely(!entry_label))
1636 return false;
1637 gen_label(entry_label);
1638 ce->entry_label = entry_label;
1640 nonflat_label = alloc_escape_label_for_ip(ctx, ctx->current_position);
1641 if (unlikely(!nonflat_label))
1642 return false;
1643 ce->nonflat_label = nonflat_label;
1645 if (unlikely(!slot_1))
1646 g(gen_timestamp_test(ctx, ctx->escape_nospill_label));
1647 else
1648 g(gen_timestamp_test(ctx, escape_label));
1649 } else {
1650 g(gen_timestamp_test(ctx, escape_label));
1652 gen_insn(INSN_ENTRY, 0, 0, 0);
1653 gen_four(slot_1);
1655 continue;
1657 case OPCODE_JMP: {
1658 int32_t x = get_jump_offset(ctx);
1659 g(gen_jump(ctx, x, OP_SIZE_NATIVE, COND_ALWAYS, -1U, -1U));
1660 continue;
1662 case OPCODE_JMP_BACK_16: {
1663 int32_t x = get_code(ctx);
1664 g(gen_jump(ctx, -x - (int)(2 * sizeof(code_t)), OP_SIZE_NATIVE, COND_ALWAYS, -1U, -1U));
1665 continue;
1667 case OPCODE_JMP_FALSE: {
1668 int32_t offs_false;
1669 get_one(ctx, &slot_1);
1670 offs_false = get_jump_offset(ctx);
1671 get_jump_offset(ctx);
1672 escape_label = alloc_escape_label(ctx);
1673 if (unlikely(!escape_label))
1674 return false;
1675 g(gen_test_1_cached(ctx, slot_1, escape_label));
1676 flag_set(ctx, slot_1, false);
1677 g(gen_cond_jump(ctx, slot_1, offs_false));
1678 continue;
1680 case OPCODE_LABEL: {
1681 g(clear_flag_cache(ctx));
1682 continue;
1684 #define init_args \
1685 do { \
1686 if (ctx->args != NULL) \
1687 mem_free(ctx->args); \
1688 g(array_init_mayfail(struct code_arg, &ctx->args, &ctx->args_l, &ctx->err));\
1689 } while (0)
1690 #define load_args \
1691 do { \
1692 init_args; \
1693 for (i_arg = 0; i_arg < n_args; i_arg++) { \
1694 struct code_arg a; \
1695 get_two(ctx, &a.slot, &a.flags); \
1696 a.type = 0; \
1697 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));\
1699 } while (0)
1700 case OPCODE_LOAD_FN:
1701 get_two(ctx, &n_args, &slot_r);
1702 get_one(ctx, &fn_idx);
1703 load_args;
1704 g(gen_load_fn_or_curry(ctx, fn_idx, NO_FRAME_T, slot_r, 0));
1705 continue;
1706 case OPCODE_CURRY:
1707 get_two(ctx, &n_args, &slot_r);
1708 get_two(ctx, &slot_1, &flags);
1709 load_args;
1710 g(gen_load_fn_or_curry(ctx, NO_FRAME_T, slot_1, slot_r, flags));
1711 continue;
1712 case OPCODE_CALL:
1713 case OPCODE_CALL_STRICT:
1714 case OPCODE_CALL_SPARK:
1715 case OPCODE_CALL_LAZY:
1716 case OPCODE_CALL_CACHE:
1717 case OPCODE_CALL_SAVE: {
1718 get_two(ctx, &n_args, &n_ret);
1719 get_one(ctx, &fn_idx);
1720 jump_over_arguments_and_return:
1721 load_args;
1722 ctx->return_values = ctx->current_position;
1723 for (i_arg = 0; i_arg < n_ret; i_arg++) {
1724 #if ARG_MODE_N >= 3
1725 get_uint32(ctx);
1726 #else
1727 get_code(ctx);
1728 #endif
1729 get_code(ctx);
1731 if (unlikely(profiling))
1732 goto unconditional_escape;
1733 if (code == OPCODE_CALL || code == OPCODE_CALL_STRICT) {
1734 g(gen_call(ctx, code, fn_idx));
1735 continue;
1737 /*if (code == OPCODE_CALL_INDIRECT || code == OPCODE_CALL_INDIRECT_STRICT) {
1738 if (unlikely(!gen_call_indirect(ctx, code, slot_1, flags)))
1739 return false;
1740 continue;
1742 goto unconditional_escape;
1744 case OPCODE_CALL_INDIRECT:
1745 case OPCODE_CALL_INDIRECT_STRICT:
1746 case OPCODE_CALL_INDIRECT_SPARK:
1747 case OPCODE_CALL_INDIRECT_LAZY:
1748 case OPCODE_CALL_INDIRECT_CACHE:
1749 case OPCODE_CALL_INDIRECT_SAVE: {
1750 fn_idx = 0; /* avoid warning */
1751 get_two(ctx, &n_args, &n_ret);
1752 get_two(ctx, &slot_1, &flags);
1753 goto jump_over_arguments_and_return;
1755 case OPCODE_RETURN: {
1756 n_args = da(ctx->fn,function)->n_return_values;
1757 load_args;
1758 if (unlikely(profiling))
1759 goto unconditional_escape;
1760 g(gen_return(ctx));
1761 continue;
1763 case OPCODE_STRUCTURED: {
1764 init_args;
1765 get_two(ctx, &slot_1, &slot_2);
1766 do {
1767 struct code_arg a;
1768 get_two(ctx, &flags, &slot_r);
1769 get_one(ctx, &opt);
1770 a.slot = slot_r;
1771 a.flags = flags;
1772 a.type = opt;
1773 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1774 } while (!(flags & OPCODE_STRUCTURED_FLAG_END));
1775 g(gen_structured(ctx, slot_1, slot_2));
1776 continue;
1778 case OPCODE_RECORD_CREATE: {
1779 init_args;
1780 get_two(ctx, &slot_r, &n_args);
1781 for (i_arg = 0; i_arg < n_args; i_arg++) {
1782 struct code_arg a;
1783 get_two(ctx, &slot_1, &flags);
1784 a.slot = slot_1;
1785 a.flags = flags;
1786 a.type = 0;
1787 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1789 g(gen_record_create(ctx, slot_r));
1790 continue;
1792 case OPCODE_RECORD_LOAD: {
1793 get_two(ctx, &slot_1, &opt);
1794 get_two(ctx, &slot_r, &flags);
1795 g(gen_record_load(ctx, slot_1, slot_r, opt, flags));
1796 continue;
1798 case OPCODE_OPTION_CREATE_EMPTY_FLAT: {
1799 get_two(ctx, &slot_r, &opt);
1800 g(gen_option_create_empty_flat(ctx, opt, slot_r));
1801 continue;
1803 case OPCODE_OPTION_CREATE_EMPTY: {
1804 get_two(ctx, &slot_r, &opt);
1805 g(gen_option_create_empty(ctx, opt, slot_r));
1806 continue;
1808 case OPCODE_OPTION_CREATE: {
1809 get_two(ctx, &slot_r, &opt);
1810 get_two(ctx, &slot_1, &flags);
1811 g(gen_option_create(ctx, opt, slot_1, slot_r, flags));
1812 continue;
1814 case OPCODE_OPTION_LOAD: {
1815 get_two(ctx, &slot_1, &opt);
1816 get_two(ctx, &slot_r, &flags);
1817 g(gen_option_load(ctx, slot_1, slot_r, opt, flags));
1818 continue;
1820 case OPCODE_OPTION_TEST_FLAT: {
1821 get_two(ctx, &slot_1, &opt);
1822 get_one(ctx, &slot_r);
1823 g(gen_option_test_flat(ctx, slot_1, opt, slot_r));
1824 continue;
1826 case OPCODE_OPTION_TEST: {
1827 get_two(ctx, &slot_1, &opt);
1828 get_one(ctx, &slot_r);
1829 g(gen_option_test(ctx, slot_1, opt, slot_r));
1830 continue;
1832 case OPCODE_OPTION_ORD_FLAT: {
1833 get_two(ctx, &slot_1, &slot_r);
1834 g(gen_option_ord(ctx, slot_1, slot_r, true));
1835 continue;
1837 case OPCODE_OPTION_ORD: {
1838 get_two(ctx, &slot_1, &slot_r);
1839 g(gen_option_ord(ctx, slot_1, slot_r, false));
1840 continue;
1842 case OPCODE_ARRAY_CREATE: {
1843 init_args;
1844 get_two(ctx, &slot_r, &n_args);
1845 for (i_arg = 0; i_arg < n_args; i_arg++) {
1846 struct code_arg a;
1847 get_two(ctx, &slot_1, &flags);
1848 a.slot = slot_1;
1849 a.flags = flags;
1850 a.type = 0;
1851 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));
1853 g(gen_array_create(ctx, slot_r));
1854 continue;
1856 case OPCODE_ARRAY_CREATE_EMPTY_FLAT: {
1857 get_two(ctx, &slot_r, &flags);
1858 g(gen_array_create_empty_flat(ctx, slot_r, flags));
1859 continue;
1861 case OPCODE_ARRAY_CREATE_EMPTY: {
1862 get_one(ctx, &slot_r);
1863 g(gen_array_create_empty(ctx, slot_r));
1864 continue;
1866 case OPCODE_ARRAY_FILL: {
1867 get_two(ctx, &slot_1, &flags);
1868 get_two(ctx, &slot_2, &slot_r);
1869 g(gen_array_fill(ctx, slot_1, flags, slot_2, slot_r));
1870 continue;
1872 case OPCODE_ARRAY_STRING: {
1873 frame_t i;
1874 get_two(ctx, &slot_r, &i);
1875 g(gen_array_string(ctx, type_get_fixed(0, true)->tag, cast_ptr(uint8_t *, ctx->current_position), i, slot_r));
1876 ctx->current_position += (i + 1) >> 1;
1877 continue;
1879 case OPCODE_ARRAY_UNICODE: {
1880 frame_t i;
1881 get_two(ctx, &slot_r, &i);
1882 g(gen_array_string(ctx, type_get_int(2)->tag, cast_ptr(uint8_t *, ctx->current_position), i, slot_r));
1883 ctx->current_position += i * 2;
1884 continue;
1886 case OPCODE_ARRAY_LOAD: {
1887 get_two(ctx, &slot_1, &slot_2);
1888 get_two(ctx, &slot_r, &flags);
1889 g(gen_array_load(ctx, slot_1, slot_2, slot_r, flags));
1890 continue;
1892 case OPCODE_ARRAY_LEN: {
1893 get_two(ctx, &slot_1, &slot_r);
1894 get_one(ctx, &flags);
1895 g(gen_array_len(ctx, slot_1, NO_FRAME_T, slot_r, false, 0));
1896 continue;
1898 case OPCODE_ARRAY_LEN_GREATER_THAN: {
1899 get_two(ctx, &slot_1, &slot_2);
1900 get_two(ctx, &slot_r, &flags);
1901 escape_label = alloc_escape_label(ctx);
1902 if (unlikely(!escape_label))
1903 return false;
1904 if (flags & OPCODE_FLAG_FUSED) {
1905 g(gen_fused_binary(ctx, MODE_ARRAY_LEN_GT, 0, 0, escape_label, slot_1, slot_2, slot_r, &failed));
1906 if (unlikely(!failed))
1907 continue;
1909 g(gen_array_len(ctx, slot_1, slot_2, slot_r, false, 0));
1910 continue;
1912 case OPCODE_ARRAY_SUB: {
1913 get_two(ctx, &slot_1, &slot_2);
1914 get_two(ctx, &slot_3, &slot_r);
1915 get_one(ctx, &flags);
1916 g(gen_array_sub(ctx, slot_1, slot_2, slot_3, slot_r, flags));
1917 continue;
1919 case OPCODE_ARRAY_SKIP: {
1920 get_two(ctx, &slot_1, &slot_2);
1921 get_two(ctx, &slot_r, &flags);
1922 g(gen_array_skip(ctx, slot_1, slot_2, slot_r, flags));
1923 continue;
1925 case OPCODE_ARRAY_APPEND: {
1926 get_two(ctx, &slot_r, &flags);
1927 get_two(ctx, &slot_1, &slot_2);
1928 g(gen_array_append(ctx, slot_1, slot_2, slot_r, flags));
1929 continue;
1931 case OPCODE_ARRAY_APPEND_ONE_FLAT: {
1932 get_two(ctx, &slot_r, &flags);
1933 get_two(ctx, &slot_1, &slot_2);
1934 g(gen_array_append_one_flat(ctx, slot_1, slot_2, slot_r, flags));
1935 continue;
1937 case OPCODE_ARRAY_APPEND_ONE: {
1938 get_two(ctx, &slot_r, &flags);
1939 get_two(ctx, &slot_1, &slot_2);
1940 g(gen_array_append_one(ctx, slot_1, slot_2, slot_r, flags));
1941 continue;
1943 case OPCODE_ARRAY_FLATTEN: {
1944 get_two(ctx, &slot_r, &flags);
1945 get_one(ctx, &slot_1);
1946 goto unconditional_escape;
1948 case OPCODE_IO: {
1949 get_two(ctx, &flags, &slot_1);
1950 get_two(ctx, &slot_2, &slot_3);
1951 g(gen_io(ctx, flags, slot_1, slot_2, slot_3));
1952 continue;
1954 case OPCODE_INTERNAL_FUNCTION:
1955 case OPCODE_EXIT_THREAD:
1956 case OPCODE_UNREACHABLE: {
1957 goto unconditional_escape;
1959 default: {
1960 #if 1
1961 /*if (getenv("DUMP") && !strcmp(da(ctx->fn,function)->function_name, getenv("DUMP")))*/
1962 warning("gen_function: %s: unknown opcode %04x, %s", da(ctx->fn,function)->function_name, *ctx->instr_start, decode_opcode(*ctx->instr_start, false));
1963 #endif
1964 return false;
1969 return true;
1972 static bool attr_w gen_entries(struct codegen_context *ctx)
1974 size_t i;
1975 for (i = 0; i < ctx->n_entries; i++) {
1976 struct cg_entry *ce = &ctx->entries[i];
1977 if (ce->entry_label) {
1978 gen_insn(INSN_ENTRY, 0, 0, 0);
1979 gen_four(i);
1981 g(gen_test_multiple(ctx, ce->variables, ce->n_variables, ce->nonflat_label));
1983 gen_insn(INSN_JMP, 0, 0, 0);
1984 gen_four(ce->entry_label);
1987 return true;
1990 static bool attr_w gen_epilogues(struct codegen_context *ctx)
1992 frame_t v;
1993 ip_t ip;
1994 uint32_t escape_label, nospill_label;
1995 escape_label = alloc_label(ctx);
1996 if (unlikely(!escape_label))
1997 return false;
1998 nospill_label = alloc_label(ctx);
1999 if (unlikely(!nospill_label))
2000 return false;
2001 #if defined(ARCH_PARISC)
2002 if (ctx->call_label) {
2003 gen_label(ctx->call_label);
2004 g(gen_call_millicode(ctx));
2006 #endif
2007 if (ctx->reload_label) {
2008 gen_label(ctx->reload_label);
2009 g(gen_mov(ctx, i_size(OP_SIZE_ADDRESS), R_FRAME, R_RET0));
2010 g(gen_escape_arg(ctx, (ip_t)-1, escape_label));
2012 gen_label(ctx->escape_nospill_label);
2013 g(gen_escape_arg(ctx, 0, nospill_label));
2014 for (ip = 0; ip < da(ctx->fn,function)->code_size; ip++) {
2015 struct cg_exit *ce = ctx->code_exits[ip];
2016 if (ce && (ce->undo_label || ce->escape_label)) {
2017 if (ce->undo_label) {
2018 size_t i;
2019 gen_label(ce->undo_label);
2020 gen_insn(ce->undo_opcode, ce->undo_op_size, ce->undo_aux, ce->undo_writes_flags);
2021 for (i = 0; i < ce->undo_parameters_len; i++)
2022 gen_one(ce->undo_parameters[i]);
2024 if (ce->escape_label) {
2025 gen_label(ce->escape_label);
2027 g(gen_escape_arg(ctx, ip, escape_label));
2030 gen_label(escape_label);
2031 for (v = MIN_USEABLE_SLOT; v < function_n_variables(ctx->fn); v++) {
2032 if (ctx->registers[v] >= 0) {
2033 g(spill(ctx, v));
2036 gen_label(nospill_label);
2037 g(gen_escape(ctx));
2038 return true;
2041 static bool attr_w cgen_entry(struct codegen_context *ctx)
2043 uint32_t entry_id = cget_four(ctx);
2044 ajla_assert_lo(entry_id < ctx->n_entries, (file_line, "cgen_entry: invalid entry %lx", (unsigned long)entry_id));
2045 ctx->entries[entry_id].entry_to_pos = ctx->mcode_size;
2046 return true;
2049 static bool attr_w cgen_label(struct codegen_context *ctx)
2051 uint32_t label_id = cget_four(ctx);
2052 ctx->label_to_pos[label_id] = ctx->mcode_size;
2053 return true;
2056 static bool attr_w attr_unused cgen_trap(struct codegen_context *ctx, uint32_t label)
2058 struct trap_record tr;
2059 tr.source_ip = ctx->mcode_size;
2060 tr.destination_ip = label;
2061 if (unlikely(!array_add_mayfail(struct trap_record, &ctx->trap_records, &ctx->trap_records_size, tr, NULL, &ctx->err)))
2062 return false;
2063 return true;
2066 static bool attr_w add_relocation(struct codegen_context *ctx, unsigned length, int offset, bool *known)
2068 struct relocation rel;
2069 rel.label_id = cget_four(ctx);
2070 rel.length = length;
2071 rel.position = ctx->mcode_size;
2072 rel.jmp_instr = ctx->code_position - 8 - offset - ctx->code;
2073 if (unlikely(!array_add_mayfail(struct relocation, &ctx->reloc, &ctx->reloc_size, rel, NULL, &ctx->err)))
2074 return false;
2075 if (known)
2076 *known = ctx->label_to_pos[rel.label_id] != (size_t)-1;
2077 return true;
2081 #if defined(ARCH_ALPHA)
2082 #include "c2-alpha.inc"
2083 #elif defined(ARCH_ARM32)
2084 #include "c2-arm.inc"
2085 #elif defined(ARCH_ARM64)
2086 #include "c2-arm64.inc"
2087 #elif defined(ARCH_IA64)
2088 #include "c2-ia64.inc"
2089 #elif defined(ARCH_LOONGARCH64)
2090 #include "c2-loong.inc"
2091 #elif defined(ARCH_MIPS)
2092 #include "c2-mips.inc"
2093 #elif defined(ARCH_PARISC)
2094 #include "c2-hppa.inc"
2095 #elif defined(ARCH_POWER)
2096 #include "c2-power.inc"
2097 #elif defined(ARCH_S390)
2098 #include "c2-s390.inc"
2099 #elif defined(ARCH_SPARC)
2100 #include "c2-sparc.inc"
2101 #elif defined(ARCH_RISCV64)
2102 #include "c2-riscv.inc"
2103 #elif defined(ARCH_X86)
2104 #include "c2-x86.inc"
2105 #endif
2108 static bool attr_w gen_mcode(struct codegen_context *ctx)
2110 ctx->code_position = ctx->code;
2112 while (ctx->code_position != ctx->code + ctx->code_size) {
2113 uint32_t insn;
2114 ajla_assert_lo(ctx->code_position < ctx->code + ctx->code_size, (file_line, "gen_mcode: ran out of code"));
2115 #ifdef DEBUG_INSNS
2116 insn = cget_four(ctx);
2117 debug("line: %u", insn);
2118 #endif
2119 insn = cget_four(ctx);
2120 g(cgen_insn(ctx, insn));
2123 return true;
2126 #define RELOCS_RETRY -1
2127 #define RELOCS_FAIL 0
2128 #define RELOCS_OK 1
2130 static int8_t resolve_relocs(struct codegen_context *ctx)
2132 size_t i;
2133 int8_t status = RELOCS_OK;
2134 for (i = 0; i < ctx->reloc_size; i++) {
2135 struct relocation *reloc = &ctx->reloc[i];
2136 if (!resolve_relocation(ctx, reloc)) {
2137 uint8_t *jmp_instr;
2138 uint32_t insn;
2139 uint32_t new_length;
2140 status = RELOCS_RETRY;
2141 if (unlikely(reloc->length + zero >= JMP_LIMIT))
2142 return RELOCS_FAIL;
2143 new_length = reloc->length + 1;
2144 jmp_instr = ctx->code + reloc->jmp_instr;
2145 insn = (uint32_t)jmp_instr[0] +
2146 ((uint32_t)jmp_instr[1] << 8) +
2147 ((uint32_t)jmp_instr[2] << 16) +
2148 ((uint32_t)jmp_instr[3] << 24);
2149 insn &= ~INSN_JUMP_SIZE;
2150 insn |= (uint32_t)new_length << INSN_JUMP_SIZE_SHIFT;
2151 jmp_instr[0] = insn;
2152 jmp_instr[1] = insn >> 8;
2153 jmp_instr[2] = insn >> 16;
2154 jmp_instr[3] = insn >> 24;
2157 return status;
2160 static void resolve_traps(struct codegen_context *ctx)
2162 size_t i;
2163 for (i = 0; i < ctx->trap_records_size; i++) {
2164 struct trap_record *tr = &ctx->trap_records[i];
2165 tr->destination_ip = ctx->label_to_pos[tr->destination_ip];
2170 static bool attr_w codegen_map(struct codegen_context *ctx)
2172 void *ptr;
2173 frame_t i;
2174 array_finish(uint8_t, &ctx->mcode, &ctx->mcode_size);
2175 ptr = os_code_map(ctx->mcode, ctx->mcode_size, &ctx->err);
2176 ctx->mcode = NULL;
2177 if (unlikely(!ptr)) {
2178 return false;
2180 for (i = 0; i < ctx->n_entries; i++) {
2181 char *entry = cast_ptr(char *, ptr) + ctx->entries[i].entry_to_pos;
2182 da(ctx->codegen,codegen)->unoptimized_code[i] = entry;
2183 da(ctx->codegen,codegen)->n_entries++;
2185 da(ctx->codegen,codegen)->unoptimized_code_base = ptr;
2186 da(ctx->codegen,codegen)->unoptimized_code_size = ctx->mcode_size;
2188 return true;
2192 void *codegen_fn(frame_s *fp, const code_t *ip, union internal_arg ia[])
2194 struct codegen_context ctx_;
2195 struct codegen_context *ctx = &ctx_;
2196 frame_t i;
2197 int8_t rr;
2198 struct data *codegen;
2199 uint32_t l;
2201 init_ctx(ctx);
2202 ctx->fn = ia[0].ptr;
2204 #ifdef DEBUG_ENV
2205 if (getenv("CG") && strcmp(da(ctx->fn,function)->function_name, getenv("CG")))
2206 goto fail;
2207 #endif
2209 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);
2210 if (unlikely(!ctx->local_directory))
2211 goto fail;
2213 if (0) for (i = 0; i < da(ctx->fn,function)->local_directory_size; i++) {
2214 struct data *callee;
2215 pointer_t *ptr;
2216 ptr = da(ctx->fn,function)->local_directory[i];
2217 pointer_follow(ptr, false, callee, PF_SPARK, NULL, 0,
2218 SUBMIT_EX(ex_);
2219 goto next_one,
2220 goto next_one;
2222 ctx->local_directory[i] = callee;
2223 next_one:;
2225 for (i = 0; i < da(ctx->fn,function)->local_directory_size; i++) {
2226 struct data *callee;
2227 pointer_t *ptr;
2228 if (ctx->local_directory[i])
2229 continue;
2230 ptr = da(ctx->fn,function)->local_directory[i];
2231 pointer_follow(ptr, false, callee, PF_WAIT, fp, ip,
2232 done_ctx(ctx);
2233 return ex_,
2234 goto fail
2236 ctx->local_directory[i] = callee;
2237 /*debug("processing call: %s -> %s", da(ctx->fn,function)->function_name, da(callee,function)->function_name);*/
2240 if (da(ctx->fn,function)->module_designator) {
2241 struct function_descriptor *sfd = save_find_function_descriptor(da(ctx->fn,function)->module_designator, da(ctx->fn,function)->function_designator);
2242 if (sfd && sfd->unoptimized_code_size) {
2243 codegen = data_alloc_flexible(codegen, unoptimized_code, sfd->n_entries, &ctx->err);
2244 if (unlikely(!codegen))
2245 goto fail;
2246 da(codegen,codegen)->unoptimized_code_base = sfd->unoptimized_code_base;
2247 da(codegen,codegen)->unoptimized_code_size = sfd->unoptimized_code_size;
2248 da(codegen,codegen)->function = ctx->fn;
2249 da(codegen,codegen)->is_saved = true;
2250 da(codegen,codegen)->n_entries = sfd->n_entries;
2251 da(codegen,codegen)->offsets = NULL;
2252 for (i = 0; i < sfd->n_entries; i++) {
2253 da(codegen,codegen)->unoptimized_code[i] = cast_ptr(char *, da(codegen,codegen)->unoptimized_code_base) + sfd->entries[i];
2254 /*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]);*/
2256 #ifdef HAVE_CODEGEN_TRAPS
2257 da(codegen,codegen)->trap_records = sfd->trap_records;
2258 da(codegen,codegen)->trap_records_size = sfd->trap_records_size;
2259 data_trap_insert(codegen);
2260 #endif
2261 goto have_codegen;
2265 /*debug("trying: %s", da(ctx->fn,function)->function_name);*/
2266 if (unlikely(!array_init_mayfail(uint8_t, &ctx->code, &ctx->code_size, &ctx->err)))
2267 goto fail;
2269 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);
2270 if (unlikely(!ctx->code_labels))
2271 goto fail;
2273 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);
2274 if (unlikely(!ctx->code_exits))
2275 goto fail;
2277 ctx->flag_cache = mem_alloc_array_mayfail(mem_calloc_mayfail, int8_t *, 0, 0, function_n_variables(ctx->fn), sizeof(int8_t), &ctx->err);
2278 if (unlikely(!ctx->flag_cache))
2279 goto fail;
2281 ctx->registers = mem_alloc_array_mayfail(mem_alloc_mayfail, short *, 0, 0, function_n_variables(ctx->fn), sizeof(short), &ctx->err);
2282 if (unlikely(!ctx->registers))
2283 goto fail;
2285 if (unlikely(!array_init_mayfail(frame_t, &ctx->need_spill, &ctx->need_spill_l, &ctx->err)))
2286 goto fail;
2288 if (unlikely(!gen_registers(ctx)))
2289 goto fail;
2291 if (unlikely(!gen_function(ctx)))
2292 goto fail;
2294 if (unlikely(!gen_entries(ctx)))
2295 goto fail;
2297 if (unlikely(!gen_epilogues(ctx)))
2298 goto fail;
2300 if (unlikely(!(ctx->label_id + 1)))
2301 goto fail;
2302 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))))
2303 goto fail;
2305 again:
2306 for (l = 0; l < ctx->label_id + 1; l++)
2307 ctx->label_to_pos[l] = (size_t)-1;
2309 if (unlikely(!array_init_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, &ctx->err)))
2310 goto fail;
2312 if (unlikely(!array_init_mayfail(struct relocation, &ctx->reloc, &ctx->reloc_size, &ctx->err)))
2313 goto fail;
2315 if (unlikely(!array_init_mayfail(struct trap_record, &ctx->trap_records, &ctx->trap_records_size, &ctx->err)))
2316 goto fail;
2318 #ifdef ARCH_CONTEXT
2319 init_arch_context(ctx);
2320 #endif
2322 if (unlikely(!gen_mcode(ctx)))
2323 goto fail;
2325 rr = resolve_relocs(ctx);
2326 if (unlikely(rr == RELOCS_FAIL)) {
2327 /*debug("relocation fail: %s", da(ctx->fn,function)->function_name);*/
2328 goto fail;
2330 if (rr == RELOCS_RETRY) {
2331 mem_free(ctx->mcode);
2332 ctx->mcode = NULL;
2333 mem_free(ctx->reloc);
2334 ctx->reloc = NULL;
2335 mem_free(ctx->trap_records);
2336 ctx->trap_records = NULL;
2337 goto again;
2340 resolve_traps(ctx);
2342 #ifdef DEBUG_ENV
2343 if ((getenv("DUMP") && !strcmp(getenv("DUMP"), da(ctx->fn,function)->function_name)) || getenv("DUMP_ALL")) {
2344 char *hex;
2345 size_t hexl;
2346 size_t i;
2347 handle_t h;
2349 mutex_lock(&dump_mutex);
2350 str_init(&hex, &hexl);
2351 str_add_string(&hex, &hexl, "_");
2352 str_add_unsigned(&hex, &hexl, dump_seq++, 10);
2353 str_add_string(&hex, &hexl, "_");
2354 str_add_string(&hex, &hexl, da(ctx->fn,function)->function_name);
2355 str_add_string(&hex, &hexl, ":");
2356 for (i = 0; i < hexl; i++)
2357 if (hex[i] == '/')
2358 hex[i] = '_';
2359 for (i = 0; i < ctx->mcode_size; i++) {
2360 uint8_t a = ctx->mcode[i];
2361 if (!(i & 0xff))
2362 str_add_string(&hex, &hexl, "\n .byte 0x");
2363 else
2364 str_add_string(&hex, &hexl, ",0x");
2365 if (a < 16)
2366 str_add_char(&hex, &hexl, '0');
2367 str_add_unsigned(&hex, &hexl, a, 16);
2369 str_add_string(&hex, &hexl, "\n");
2370 h = os_open(os_cwd, "dump.s", O_WRONLY | O_APPEND, 0600, NULL);
2371 os_write_all(h, hex, hexl, NULL);
2372 os_close(h);
2373 mem_free(hex);
2374 mutex_unlock(&dump_mutex);
2376 #endif
2378 ctx->codegen = data_alloc_flexible(codegen, unoptimized_code, ctx->n_entries, &ctx->err);
2379 if (unlikely(!ctx->codegen))
2380 goto fail;
2381 da(ctx->codegen,codegen)->function = ctx->fn;
2382 da(ctx->codegen,codegen)->is_saved = false;
2383 da(ctx->codegen,codegen)->n_entries = 0;
2384 da(ctx->codegen,codegen)->offsets = NULL;
2386 if (unlikely(!codegen_map(ctx)))
2387 goto fail;
2389 codegen = ctx->codegen;
2390 ctx->codegen = NULL;
2392 #ifdef HAVE_CODEGEN_TRAPS
2393 da(codegen,codegen)->trap_records = ctx->trap_records;
2394 da(codegen,codegen)->trap_records_size = ctx->trap_records_size;
2395 ctx->trap_records = NULL;
2396 data_trap_insert(codegen);
2397 #endif
2399 have_codegen:
2400 done_ctx(ctx);
2401 return function_return(fp, pointer_data(codegen));
2403 fail:
2404 /*debug("FAILED: %s", da(ctx->fn,function)->function_name);*/
2405 done_ctx(ctx);
2406 return function_return(fp, pointer_thunk(thunk_alloc_exception_error(error_ajla(EC_SYNC, AJLA_ERROR_NOT_SUPPORTED), NULL, NULL, NULL pass_file_line)));
2409 void codegen_free(struct data *codegen)
2411 if (unlikely(da(codegen,codegen)->offsets != NULL))
2412 mem_free(da(codegen,codegen)->offsets);
2413 if (likely(da(codegen,codegen)->is_saved))
2414 return;
2415 #ifdef HAVE_CODEGEN_TRAPS
2416 mem_free(da(codegen,codegen)->trap_records);
2417 #endif
2418 os_code_unmap(da(codegen,codegen)->unoptimized_code_base, da(codegen,codegen)->unoptimized_code_size);
2421 #if defined(ARCH_IA64)
2422 static uintptr_t ia64_stub[2];
2423 #endif
2424 #if defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2425 static uintptr_t parisc_stub[2];
2426 #endif
2427 #if defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2428 static uintptr_t parisc_stub[4];
2429 #endif
2430 #if defined(ARCH_POWER) && defined(AIX_CALL)
2431 static uintptr_t ppc_stub[3];
2432 #endif
2434 void name(codegen_init)(void)
2436 struct codegen_context ctx_;
2437 struct codegen_context *ctx = &ctx_;
2438 void *ptr;
2440 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
2441 #if defined(HAVE_SYSCALL) && defined(HAVE_ASM_PRCTL_H) && defined(HAVE_SYS_SYSCALL_H)
2442 if (!dll) {
2443 int r;
2444 EINTR_LOOP(r, syscall(SYS_arch_prctl, ARCH_SET_GS, &cg_upcall_vector));
2445 if (!r)
2446 upcall_register = R_GS;
2448 #elif defined(HAVE_AMD64_SET_GSBASE) && defined(HAVE_X86_SYSARCH_H)
2449 if (!dll) {
2450 int r;
2451 EINTR_LOOP(r, amd64_set_gsbase(&cg_upcall_vector));
2452 if (!r)
2453 upcall_register = R_GS;
2455 #elif defined(HAVE_SYSARCH) && defined(HAVE_X86_SYSARCH_H) && defined(X86_64_SET_GSBASE)
2456 if (!dll) {
2457 int r;
2458 void *ptr = &cg_upcall_vector;
2459 EINTR_LOOP(r, sysarch(X86_64_SET_GSBASE, &ptr));
2460 if (!r)
2461 upcall_register = R_GS;
2463 #endif
2464 #endif
2466 init_ctx(ctx);
2467 ctx->fn = NULL;
2469 array_init(uint8_t, &ctx->code, &ctx->code_size);
2471 if (unlikely(!gen_entry(ctx)))
2472 goto fail;
2474 array_init(uint8_t, &ctx->mcode, &ctx->mcode_size);
2476 #ifdef ARCH_CONTEXT
2477 init_arch_context(ctx);
2478 #endif
2480 if (unlikely(!gen_mcode(ctx)))
2481 goto fail;
2483 array_finish(uint8_t, &ctx->mcode, &ctx->mcode_size);
2484 ptr = os_code_map(ctx->mcode, ctx->mcode_size, NULL);
2485 codegen_ptr = ptr;
2486 codegen_size = ctx->mcode_size;
2487 ctx->mcode = NULL;
2488 #if defined(ARCH_IA64)
2489 ia64_stub[0] = ptr_to_num(ptr);
2490 ia64_stub[1] = 0;
2491 codegen_entry = cast_ptr(codegen_type, ia64_stub);
2492 #elif defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2493 parisc_stub[0] = ptr_to_num(ptr);
2494 parisc_stub[1] = 0;
2495 codegen_entry = cast_ptr(codegen_type, cast_ptr(char *, parisc_stub) + 2);
2496 #elif defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2497 parisc_stub[0] = 0;
2498 parisc_stub[1] = 0;
2499 parisc_stub[2] = ptr_to_num(ptr);
2500 parisc_stub[3] = 0;
2501 codegen_entry = cast_ptr(codegen_type, parisc_stub);
2502 #elif defined(ARCH_POWER) && defined(AIX_CALL)
2503 ppc_stub[0] = ptr_to_num(ptr);
2504 ppc_stub[1] = 0;
2505 ppc_stub[2] = 0;
2506 codegen_entry = cast_ptr(codegen_type, ppc_stub);
2507 #else
2508 codegen_entry = ptr;
2509 #endif
2510 done_ctx(ctx);
2512 #ifdef DEBUG_ENV
2513 mutex_init(&dump_mutex);
2514 if (getenv("DUMP") || getenv("DUMP_ALL")) {
2515 size_t i;
2516 char *hex;
2517 size_t hexl;
2518 str_init(&hex, &hexl);
2519 #if defined(ARCH_RISCV64)
2520 str_add_string(&hex, &hexl, " .attribute arch, \"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zba1p0_zbb1p0_zbc1p0_zbs1p0\"\n");
2521 #endif
2522 for (i = 0; i < codegen_size; i++) {
2523 uint8_t a = cast_ptr(uint8_t *, codegen_ptr)[i];
2524 str_add_string(&hex, &hexl, " .byte 0x");
2525 if (a < 16)
2526 str_add_char(&hex, &hexl, '0');
2527 str_add_unsigned(&hex, &hexl, a, 16);
2528 str_add_char(&hex, &hexl, '\n');
2530 os_write_atomic(".", "dump.s", hex, hexl, NULL);
2531 mem_free(hex);
2533 #endif
2535 return;
2537 fail:
2538 fatal("couldn't compile global entry");
2541 void name(codegen_done)(void)
2543 os_code_unmap(codegen_ptr, codegen_size);
2544 #ifdef DEBUG_ENV
2545 mutex_done(&dump_mutex);
2546 #endif
2549 #else
2551 void name(codegen_init)(void)
2555 void name(codegen_done)(void)
2559 #endif
2561 #endif