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
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/>.
38 #define flag_cache_chicken 0
39 #define must_be_flat_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>
54 #if (defined(HAVE_AMD64_SET_GSBASE) || defined(HAVE_SYSARCH)) && defined(HAVE_X86_SYSARCH_H)
55 #include <x86/sysarch.h>
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
;
64 static mutex_t dump_mutex
;
65 static uint64_t dump_seq
= 0;
73 * writes flags - 2 bit
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))
103 #define ALU_ANDN 0x09
104 #define ALU_XORN 0x0a
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
120 #define ALU_ZAPNOT 0x21
122 #define ALU1_NOT 0x00
123 #define ALU1_NEG 0x01
124 #define ALU1_NGC 0x02
125 #define ALU1_BSWAP 0x03
126 #define ALU1_BSWAP16 0x04
127 #define ALU1_BREV 0x05
128 #define ALU1_BSF 0x06
129 #define ALU1_BSR 0x07
130 #define ALU1_LZCNT 0x08
131 #define ALU1_POPCNT 0x09
137 #define FP_ALU1_NEG 0
138 #define FP_ALU1_SQRT 1
139 #define FP_ALU1_ROUND 2
140 #define FP_ALU1_FLOOR 3
141 #define FP_ALU1_CEIL 4
142 #define FP_ALU1_TRUNC 5
143 #define FP_ALU1_VCNT8 6
144 #define FP_ALU1_VPADDL 7
145 #define FP_ALU1_ADDV 8
163 #define COND_BLBC 0x10
164 #define COND_BLBS 0x11
165 #define COND_ALWAYS 0x12
168 #define FP_COND_P (COND_FP | COND_P)
169 #define FP_COND_NP (COND_FP | COND_NP)
170 #define FP_COND_E (COND_FP | COND_E)
171 #define FP_COND_NE (COND_FP | COND_NE)
172 #define FP_COND_A (COND_FP | COND_A)
173 #define FP_COND_BE (COND_FP | COND_BE)
174 #define FP_COND_B (COND_FP | COND_B)
175 #define FP_COND_AE (COND_FP | COND_AE)
190 #define BTX_BTEXT 0x4
199 #define MOV_MASK_0_16 0x0
200 #define MOV_MASK_16_32 0x1
201 #define MOV_MASK_32_48 0x2
202 #define MOV_MASK_48_64 0x3
203 #define MOV_MASK_0_8 0x4
204 #define MOV_MASK_32_64 0x5
205 #define MOV_MASK_52_64 0x6
207 #define JMP_SHORTEST 0x0000
208 #define JMP_SHORT 0x0001
209 #define JMP_LONG 0x0002
210 #define JMP_EXTRA_LONG 0x0003
241 INSN_ALU_FLAGS_PARTIAL
,
247 INSN_ALU1_FLAGS_PARTIAL
,
262 INSN_SET_COND_PARTIAL
,
277 INSN_FP_CMP_DEST_REG
,
278 INSN_FP_CMP_DEST_REG_TRAP
,
279 INSN_FP_CMP_UNORDERED_DEST_REG
,
282 INSN_FP_TO_INT_FLAGS
,
287 INSN_FP_TO_INT64_TRAP
,
290 INSN_FP_INT64_TO_INT32_TRAP
,
309 INSN_JMP_COND_LOGICAL
,
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
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
358 #define OP_SIZE_SLOT OP_SIZE_ADDRESS
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) \
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);*/\
372 #define gen_line() gen_four(__LINE__ + (insn_file << 24))
374 #define gen_line() do { } while (0)
378 #define ARCH_CONTEXT struct { \
380 uint8_t insn_units[3]; \
381 bool insn_stops[3]; \
382 uint64_t wr_mask[4]; \
386 #define gen_insn(opcode, op_size, aux, writes_flags) \
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; \
398 static size_t arg_size(uint8_t arg
)
400 if (arg
< ARG_REGS_MAX
)
402 if (arg
>= ARG_SHIFTED_REGISTER
&& arg
<= ARG_EXTENDED_REGISTER
)
404 if (arg
== ARG_ADDRESS_0
)
406 if (arg
>= ARG_ADDRESS_1
&& arg
<= ARG_ADDRESS_1_POST_I
)
408 if (arg
>= ARG_ADDRESS_2
&& arg
<= ARG_ADDRESS_2_SXTW
)
412 internal(file_line
, "arg_size: invalid argument %02x", arg
);
433 uint32_t entry_label
;
434 uint32_t nonflat_label
;
440 uint8_t undo_op_size
;
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
{
454 struct data
**local_directory
;
456 const code_t
*instr_start
;
457 const code_t
*current_position
;
458 uchar_efficient_t arg_mode
;
461 struct cg_entry
*entries
;
467 uint8_t *code_position
;
469 uint32_t *code_labels
;
470 struct cg_exit
**code_exits
;
471 uint32_t escape_nospill_label
;
473 uint32_t reload_label
;
478 size_t *label_to_pos
;
479 struct relocation
*reloc
;
482 struct trap_record
*trap_records
;
483 size_t trap_records_size
;
485 struct code_arg
*args
;
487 const code_t
*return_values
;
501 struct data
*codegen
;
506 bool upcall_hacked_abi
;
516 static void init_ctx(struct codegen_context
*ctx
)
518 ctx
->local_directory
= NULL
;
523 ctx
->code_labels
= NULL
;
524 ctx
->code_exits
= NULL
;
525 ctx
->escape_nospill_label
= 0;
527 ctx
->reload_label
= 0;
529 ctx
->label_to_pos
= NULL
;
531 ctx
->trap_records
= NULL
;
533 ctx
->flag_cache
= NULL
;
534 ctx
->registers
= NULL
;
535 ctx
->need_spill
= NULL
;
537 ctx
->upcall_offset
= -1;
538 ctx
->upcall_args
= -1;
539 ctx
->upcall_hacked_abi
= false;
543 static void done_ctx(struct codegen_context
*ctx
)
545 if (ctx
->local_directory
)
546 mem_free(ctx
->local_directory
);
549 for (i
= 0; i
< ctx
->n_entries
; i
++) {
550 struct cg_entry
*ce
= &ctx
->entries
[i
];
552 mem_free(ce
->variables
);
554 mem_free(ctx
->entries
);
558 if (ctx
->code_labels
)
559 mem_free(ctx
->code_labels
);
560 if (ctx
->code_exits
) {
562 ip_t cs
= da(ctx
->fn
,function
)->code_size
;
563 for (ip
= 0; ip
< cs
; ip
++) {
564 if (ctx
->code_exits
[ip
])
565 mem_free(ctx
->code_exits
[ip
]);
567 mem_free(ctx
->code_exits
);
570 mem_free(ctx
->mcode
);
571 if (ctx
->label_to_pos
)
572 mem_free(ctx
->label_to_pos
);
574 mem_free(ctx
->reloc
);
575 if (ctx
->trap_records
)
576 mem_free(ctx
->trap_records
);
580 mem_free(ctx
->flag_cache
);
582 mem_free(ctx
->registers
);
584 mem_free(ctx
->need_spill
);
586 data_free(ctx
->codegen
);
588 mem_free(ctx
->var_aux
);
592 static inline code_t
get_code(struct codegen_context
*ctx
)
594 ajla_assert(ctx
->current_position
< da(ctx
->fn
,function
)->code
+ da(ctx
->fn
,function
)->code_size
, (file_line
, "get_code: ran out of code"));
595 return *ctx
->current_position
++;
598 static inline uint32_t get_uint32(struct codegen_context
*ctx
)
600 uint32_t a1
= get_code(ctx
);
601 uint32_t a2
= get_code(ctx
);
603 return a1
+ (a2
<< 16);
605 return a2
+ (a1
<< 16);
609 static int32_t get_jump_offset(struct codegen_context
*ctx
)
611 if (SIZEOF_IP_T
== 2) {
612 return (int32_t)(int16_t)get_code(ctx
);
613 } else if (SIZEOF_IP_T
== 4) {
614 return (int32_t)get_uint32(ctx
);
621 static inline void get_one(struct codegen_context
*ctx
, frame_t
*v
)
623 if (!ctx
->arg_mode
) {
624 code_t c
= get_code(ctx
);
625 ajla_assert(!(c
& ~0xff), (file_line
, "get_one: high byte is not cleared: %u", (unsigned)c
));
627 } else if (ctx
->arg_mode
== 1) {
630 } else if (ctx
->arg_mode
== 2) {
631 *v
= get_uint32(ctx
);
634 internal(file_line
, "get_one: invalid arg mode %u", ctx
->arg_mode
);
638 static inline void get_two(struct codegen_context
*ctx
, frame_t
*v1
, frame_t
*v2
)
640 if (!ctx
->arg_mode
) {
641 code_t c
= get_code(ctx
);
644 } else if (ctx
->arg_mode
== 1) {
648 } else if (ctx
->arg_mode
== 2) {
649 *v1
= get_uint32(ctx
);
650 *v2
= get_uint32(ctx
);
653 internal(file_line
, "get_two: invalid arg mode %u", ctx
->arg_mode
);
658 static uint32_t alloc_label(struct codegen_context
*ctx
)
660 return ++ctx
->label_id
;
663 static struct cg_exit
*alloc_cg_exit_for_ip(struct codegen_context
*ctx
, const code_t
*code
)
665 ip_t ip
= code
- da(ctx
->fn
,function
)->code
;
666 struct cg_exit
*ce
= ctx
->code_exits
[ip
];
668 ce
= mem_calloc_mayfail(struct cg_exit
*, sizeof(struct cg_exit
), &ctx
->err
);
671 ctx
->code_exits
[ip
] = ce
;
676 static struct cg_exit
*alloc_undo_label(struct codegen_context
*ctx
)
678 struct cg_exit
*ce
= alloc_cg_exit_for_ip(ctx
, ctx
->instr_start
);
681 if (unlikely(ce
->undo_label
!= 0))
682 internal(file_line
, "alloc_cg_exit: undo label already allocated");
683 ce
->undo_label
= alloc_label(ctx
);
684 if (unlikely(!ce
->undo_label
))
689 static uint32_t alloc_escape_label_for_ip(struct codegen_context
*ctx
, const code_t
*code
)
691 struct cg_exit
*ce
= alloc_cg_exit_for_ip(ctx
, code
);
694 if (!ce
->escape_label
)
695 ce
->escape_label
= alloc_label(ctx
);
696 return ce
->escape_label
;
699 static uint32_t alloc_escape_label(struct codegen_context
*ctx
)
701 return alloc_escape_label_for_ip(ctx
, ctx
->instr_start
);
704 static uint32_t attr_unused
alloc_call_label(struct codegen_context
*ctx
)
706 if (!ctx
->call_label
) {
707 ctx
->call_label
= alloc_label(ctx
);
709 return ctx
->call_label
;
712 static uint32_t alloc_reload_label(struct codegen_context
*ctx
)
714 if (!ctx
->reload_label
) {
715 ctx
->reload_label
= alloc_label(ctx
);
717 return ctx
->reload_label
;
720 static size_t attr_unused
mark_params(struct codegen_context
*ctx
)
722 return ctx
->code_size
;
725 static void attr_unused
copy_params(struct codegen_context
*ctx
, struct cg_exit
*ce
, size_t mark
)
727 if (ctx
->code_size
- mark
> n_array_elements(ce
->undo_parameters
))
728 internal(file_line
, "undo_parameters is too small: %"PRIuMAX
" > %"PRIuMAX
"", (uintmax_t)(ctx
->code_size
- mark
), (uintmax_t)n_array_elements(ce
->undo_parameters
));
729 memcpy(ce
->undo_parameters
, ctx
->code
+ mark
, ctx
->code_size
- mark
);
730 ce
->undo_parameters_len
= ctx
->code_size
- mark
;
731 ctx
->code_size
= mark
;
736 if (unlikely(!call)) \
740 #define gen_one(byte) \
742 /*debug("gen %d: %02x", __LINE__, (uint8_t)(byte))*/; \
743 if (unlikely(!array_add_mayfail(uint8_t, &ctx->code, &ctx->code_size, byte, NULL, &ctx->err)))\
747 #if defined(C_LITTLE_ENDIAN)
748 #define gen_two(word) \
750 uint16_t word_ = (word); \
751 /*debug("gen %d: %04x", __LINE__, (uint16_t)(word_));*/ \
752 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
755 #define gen_four(dword) \
757 uint32_t dword_ = (dword); \
758 /*debug("gen %d: %08x", __LINE__, (uint32_t)(dword_));*/ \
759 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
762 #define gen_eight(qword) \
764 uint64_t qword_ = (qword); \
765 /*debug("gen %d: %016lx", __LINE__, (uint64_t)(qword_));*/ \
766 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->code, &ctx->code_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
770 #define gen_two(word) \
772 uint16_t word_ = (word); \
773 gen_one(word_ & 0xffU); \
774 gen_one(word_ >> 8); \
776 #define gen_four(dword) \
778 uint32_t dword_ = (dword); \
779 gen_two(dword_ & 0xffffU); \
780 gen_two(dword_ >> 15 >> 1); \
782 #define gen_eight(qword) \
784 uint64_t qword_ = (qword); \
785 gen_four(qword_ & 0xffffffffUL); \
786 gen_four(qword_ >> 15 >> 15 >> 2); \
790 #define gen_label(label_id) \
792 gen_insn(INSN_LABEL, 0, 0, 0); \
793 gen_four(label_id); \
797 static uint8_t attr_unused
cget_one(struct codegen_context
*ctx
)
799 ajla_assert(ctx
->code_position
< ctx
->code
+ ctx
->code_size
, (file_line
, "cget_one: ran out of code"));
800 return *ctx
->code_position
++;
803 static uint16_t attr_unused
cget_two(struct codegen_context
*ctx
)
805 #if defined(C_LITTLE_ENDIAN)
807 ajla_assert(ctx
->code_position
< ctx
->code
+ ctx
->code_size
, (file_line
, "cget_two: ran out of code"));
808 memcpy(&r
, ctx
->code_position
, 2);
809 ctx
->code_position
+= 2;
812 uint16_t r
= cget_one(ctx
);
813 r
|= cget_one(ctx
) << 8;
818 static uint32_t cget_four(struct codegen_context
*ctx
)
820 #if defined(C_LITTLE_ENDIAN)
822 ajla_assert(ctx
->code_position
< ctx
->code
+ ctx
->code_size
, (file_line
, "cget_four: ran out of code"));
823 memcpy(&r
, ctx
->code_position
, 4);
824 ctx
->code_position
+= 4;
827 uint32_t r
= cget_two(ctx
);
828 r
|= (uint32_t)cget_two(ctx
) << 16;
833 static uint64_t attr_unused
cget_eight(struct codegen_context
*ctx
)
835 #if defined(C_LITTLE_ENDIAN)
837 ajla_assert(ctx
->code_position
< ctx
->code
+ ctx
->code_size
, (file_line
, "cget_eight: ran out of code"));
838 memcpy(&r
, ctx
->code_position
, 8);
839 ctx
->code_position
+= 8;
842 uint64_t r
= cget_four(ctx
);
843 r
|= (uint64_t)cget_four(ctx
) << 32;
848 static int64_t get_imm(uint8_t *ptr
)
850 #if defined(C_LITTLE_ENDIAN)
856 r
= (uint64_t)ptr
[0] |
857 ((uint64_t)ptr
[1] << 8) |
858 ((uint64_t)ptr
[2] << 16) |
859 ((uint64_t)ptr
[3] << 24) |
860 ((uint64_t)ptr
[4] << 32) |
861 ((uint64_t)ptr
[5] << 40) |
862 ((uint64_t)ptr
[6] << 48) |
863 ((uint64_t)ptr
[7] << 56);
868 #define cgen_one(byte) \
870 if (unlikely(!array_add_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, byte, NULL, &ctx->err)))\
874 #if defined(C_LITTLE_ENDIAN) || 1
875 #define cgen_two(word) \
877 uint16_t word_ = (word); \
878 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &word_), 2, NULL, &ctx->err)))\
881 #define cgen_four(dword) \
883 uint32_t dword_ = (dword); \
884 /*if (dword_ == 0x1ee02000) internal(file_line, "invalid instruction");*/\
885 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &dword_), 4, NULL, &ctx->err)))\
888 #define cgen_eight(qword) \
890 uint64_t qword_ = (qword); \
891 if (unlikely(!array_add_multiple_mayfail(uint8_t, &ctx->mcode, &ctx->mcode_size, cast_ptr(uint8_t *, &qword_), 8, NULL, &ctx->err)))\
895 #define cgen_two(word) \
897 cgen_one((word) & 0xff); \
898 cgen_one((word) >> 8); \
900 #define cgen_four(dword) \
902 cgen_two((dword) & 0xffff); \
903 cgen_two((dword) >> 15 >> 1); \
905 #define cgen_eight(qword) \
907 cgen_four((qword) & 0xffffffff); \
908 cgen_four((qword) >> 15 >> 15 >> 2); \
913 #define IMM_PURPOSE_LDR_OFFSET 1
914 #define IMM_PURPOSE_LDR_SX_OFFSET 2
915 #define IMM_PURPOSE_STR_OFFSET 3
916 #define IMM_PURPOSE_LDP_STP_OFFSET 4
917 #define IMM_PURPOSE_VLDR_VSTR_OFFSET 5
918 #define IMM_PURPOSE_MVI_CLI_OFFSET 6
919 #define IMM_PURPOSE_STORE_VALUE 7
920 #define IMM_PURPOSE_ADD 8
921 #define IMM_PURPOSE_SUB 9
922 #define IMM_PURPOSE_CMP 10
923 #define IMM_PURPOSE_CMP_LOGICAL 11
924 #define IMM_PURPOSE_AND 12
925 #define IMM_PURPOSE_OR 13
926 #define IMM_PURPOSE_XOR 14
927 #define IMM_PURPOSE_ANDN 15
928 #define IMM_PURPOSE_TEST 16
929 #define IMM_PURPOSE_JMP_2REGS 17
930 #define IMM_PURPOSE_MUL 18
931 #define IMM_PURPOSE_CMOV 19
932 #define IMM_PURPOSE_MOVR 20
933 #define IMM_PURPOSE_BITWISE 21
934 #define IMM_PURPOSE_ADD_TRAP 22
935 #define IMM_PURPOSE_SUB_TRAP 23
938 static unsigned alu_purpose(unsigned alu
)
941 alu
== ALU_ADD
? IMM_PURPOSE_ADD
:
942 alu
== ALU_ADC
? IMM_PURPOSE_ADD
:
943 alu
== ALU_SUB
? IMM_PURPOSE_SUB
:
944 alu
== ALU_SBB
? IMM_PURPOSE_SUB
:
945 alu
== ALU_MUL
? IMM_PURPOSE_MUL
:
946 alu
== ALU_UMULH
? IMM_PURPOSE_MUL
:
947 alu
== ALU_SMULH
? IMM_PURPOSE_MUL
:
948 alu
== ALU_ANDN
? IMM_PURPOSE_ANDN
:
949 alu
== ALU_AND
? IMM_PURPOSE_AND
:
950 alu
== ALU_OR
? IMM_PURPOSE_OR
:
951 alu
== ALU_XOR
? IMM_PURPOSE_XOR
:
952 alu
== ALU_EXTBL
? IMM_PURPOSE_OR
:
953 alu
== ALU_EXTWL
? IMM_PURPOSE_OR
:
954 alu
== ALU_EXTLL
? IMM_PURPOSE_OR
:
955 alu
== ALU_EXTLH
? IMM_PURPOSE_OR
:
956 alu
== ALU_INSBL
? IMM_PURPOSE_OR
:
957 alu
== ALU_MSKBL
? IMM_PURPOSE_OR
:
958 alu
== ALU_ZAP
? IMM_PURPOSE_ANDN
:
959 alu
== ALU_ZAPNOT
? IMM_PURPOSE_AND
:
961 if (unlikely(purpose
== -1U))
962 internal(file_line
, "alu_purpose: invalid alu %u", alu
);
966 static unsigned alu_trap_purpose(unsigned alu
)
969 alu
== ALU_ADD
? IMM_PURPOSE_ADD_TRAP
:
970 alu
== ALU_SUB
? IMM_PURPOSE_SUB_TRAP
:
972 if (unlikely(purpose
== -1U))
973 internal(file_line
, "alu_trap_purpose: invalid alu %u", alu
);
978 static bool attr_w
gen_imm(struct codegen_context
*ctx
, int64_t imm
, unsigned purpose
, unsigned size
);
979 static bool attr_w
gen_upcall_end(struct codegen_context
*ctx
, unsigned offset
, unsigned args
);
981 #define gen_address_offset() \
983 if (likely(!ctx->offset_reg)) { \
984 gen_one(ARG_ADDRESS_1); \
985 gen_one(ctx->base_reg); \
986 gen_eight(ctx->offset_imm); \
988 gen_one(ARG_ADDRESS_2); \
989 gen_one(ctx->base_reg); \
990 gen_one(R_OFFSET_IMM); \
995 #define gen_imm_offset() \
997 if (likely(!ctx->const_reg)) { \
999 gen_eight(ctx->const_imm); \
1001 gen_one(R_CONST_IMM); \
1005 #define is_imm() (!ctx->const_reg)
1008 static inline bool slot_is_register(struct codegen_context
*ctx
, frame_t slot
)
1010 if (frame_t_is_const(slot
))
1012 if (unlikely(slot
>= function_n_variables(ctx
->fn
)))
1013 internal(file_line
, "slot_is_register: invalid slot %lu", (unsigned long)slot
);
1014 return ctx
->registers
[slot
] >= 0;
1019 #if defined(ARCH_ALPHA)
1020 #include "c1-alpha.inc"
1021 #elif defined(ARCH_ARM32)
1022 #include "c1-arm.inc"
1023 #elif defined(ARCH_ARM64)
1024 #include "c1-arm64.inc"
1025 #elif defined(ARCH_IA64)
1026 #include "c1-ia64.inc"
1027 #elif defined(ARCH_LOONGARCH64)
1028 #include "c1-loong.inc"
1029 #elif defined(ARCH_MIPS)
1030 #include "c1-mips.inc"
1031 #elif defined(ARCH_PARISC)
1032 #include "c1-hppa.inc"
1033 #elif defined(ARCH_POWER)
1034 #include "c1-power.inc"
1035 #elif defined(ARCH_S390)
1036 #include "c1-s390.inc"
1037 #elif defined(ARCH_SPARC)
1038 #include "c1-sparc.inc"
1039 #elif defined(ARCH_RISCV64)
1040 #include "c1-riscv.inc"
1041 #elif defined(ARCH_X86)
1042 #include "c1-x86.inc"
1047 #ifndef ARCH_SUPPORTS_TRAPS
1048 #define ARCH_SUPPORTS_TRAPS(size) 0
1049 #define ARCH_TRAP_BEFORE 0
1053 static bool attr_w
gen_imm(struct codegen_context
*ctx
, int64_t imm
, unsigned purpose
, unsigned size
)
1055 if (!is_direct_const(imm
, purpose
& 0xff, size
))
1057 if (purpose
>> 8 && !is_direct_const(imm
, purpose
>> 8, size
))
1059 ctx
->const_imm
= imm
;
1060 ctx
->const_reg
= false;
1063 g(gen_load_constant(ctx
, R_CONST_IMM
, imm
));
1064 ctx
->const_reg
= true;
1070 #include "cg-util.inc"
1074 #include "cg-frame.inc"
1078 #include "cg-flags.inc"
1082 #include "cg-flcch.inc"
1086 #include "cg-ptr.inc"
1090 #include "cg-alu.inc"
1094 #include "cg-ops.inc"
1100 #ifndef n_regs_saved
1101 #define n_regs_saved n_array_elements(regs_saved)
1104 #ifndef n_regs_volatile
1105 #define n_regs_volatile n_array_elements(regs_volatile)
1109 #define n_fp_saved n_array_elements(fp_saved)
1112 #ifndef n_fp_volatile
1113 #define n_fp_volatile n_array_elements(fp_volatile)
1116 #ifndef n_vector_volatile
1117 #define n_vector_volatile n_array_elements(vector_volatile)
1120 static bool attr_w
gen_registers(struct codegen_context
*ctx
)
1123 size_t index_saved
= 0;
1124 size_t index_volatile
= 0;
1125 size_t index_fp_saved
= 0;
1126 size_t index_fp_volatile
= 0;
1127 size_t attr_unused index_vector_volatile
= 0;
1129 bool uses_x
= false;
1130 for (v
= MIN_USEABLE_SLOT
; v
< function_n_variables(ctx
->fn
); v
++) {
1131 const struct type
*t
= get_type_of_local(ctx
, v
);
1132 if (t
&& TYPE_TAG_IS_REAL(t
->tag
) && TYPE_TAG_IDX_REAL(t
->tag
) == 4) {
1138 /*for (v = function_n_variables(ctx->fn) - 1; v >= MIN_USEABLE_SLOT; v--)*/
1139 for (v
= MIN_USEABLE_SLOT
; v
< function_n_variables(ctx
->fn
); v
++) {
1140 const struct type
*t
;
1141 ctx
->registers
[v
] = -1;
1144 t
= get_type_of_local(ctx
, v
);
1147 if (!da(ctx
->fn
,function
)->local_variables_flags
[v
].must_be_flat
&&
1148 !da(ctx
->fn
,function
)->local_variables_flags
[v
].must_be_data
)
1150 if (!ARCH_HAS_BWX
&& t
->size
< 1U << OP_SIZE_4
)
1152 if (TYPE_TAG_IS_FIXED(t
->tag
) || TYPE_TAG_IS_INT(t
->tag
) || t
->tag
== TYPE_TAG_flat_option
|| t
->tag
== TYPE_TAG_unknown
|| t
->tag
== TYPE_TAG_record
) {
1153 if (TYPE_TAG_IS_BUILTIN(t
->tag
)) {
1154 if (!is_power_of_2(t
->size
) || t
->size
> 1U << OP_SIZE_NATIVE
)
1157 if (index_saved
< n_regs_saved
+ zero
1158 #if defined(ARCH_PARISC) || defined(ARCH_SPARC)
1159 && t
->size
<= 1U << OP_SIZE_ADDRESS
1162 ctx
->registers
[v
] = regs_saved
[index_saved
++];
1163 } else if (index_volatile
< n_regs_volatile
+ zero
) {
1164 ctx
->registers
[v
] = regs_volatile
[index_volatile
++];
1168 } else if (TYPE_TAG_IS_REAL(t
->tag
)) {
1169 unsigned real_type
= TYPE_TAG_IDX_REAL(t
->tag
);
1170 if ((SUPPORTED_FP
>> real_type
) & 1) {
1172 if (real_type
== 4) {
1173 if (index_vector_volatile
< n_vector_volatile
+ zero
) {
1174 ctx
->registers
[v
] = vector_volatile
[index_vector_volatile
++];
1181 if (real_type
== 4) {
1182 if (!(index_fp_saved
& 1) && index_fp_saved
+ 1 < n_fp_saved
+ zero
) {
1183 ctx
->registers
[v
] = fp_saved
[index_fp_saved
++];
1187 if (index_fp_saved
& 1 && index_fp_saved
+ 2 < n_fp_saved
+ zero
) {
1189 ctx
->registers
[v
] = fp_saved
[index_fp_saved
++];
1193 if (!(index_fp_volatile
& 1) && index_fp_volatile
+ 1 < n_fp_volatile
+ zero
) {
1194 ctx
->registers
[v
] = fp_volatile
[index_fp_volatile
++];
1195 index_fp_volatile
++;
1198 if (index_fp_volatile
& 1 && index_fp_volatile
+ 2 < n_fp_volatile
+ zero
) {
1199 index_fp_volatile
++;
1200 ctx
->registers
[v
] = fp_volatile
[index_fp_volatile
++];
1201 index_fp_volatile
++;
1207 if (index_fp_saved
< n_fp_saved
+ zero
) {
1208 ctx
->registers
[v
] = fp_saved
[index_fp_saved
++];
1209 } else if (index_fp_volatile
< n_fp_volatile
+ zero
) {
1210 ctx
->registers
[v
] = fp_volatile
[index_fp_volatile
++];
1222 if (!reg_is_saved(ctx
->registers
[v
])) {
1223 if (unlikely(!array_add_mayfail(frame_t
, &ctx
->need_spill
, &ctx
->need_spill_l
, v
, NULL
, &ctx
->err
)))
1231 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
)
1233 const code_t
*backup
= ctx
->current_position
;
1235 frame_t slot_dr
, slot_test
;
1241 code
= get_code(ctx
);
1242 ctx
->arg_mode
= code
/ OPCODE_MODE_MULT
;
1243 code
%= OPCODE_MODE_MULT
;
1244 ajla_assert_lo(ctx
->arg_mode
< ARG_MODE_N
, (file_line
, "gen_fused_binary: invalid opcode %04x", (unsigned)*ctx
->instr_start
));
1246 if (code
== OPCODE_DEREFERENCE
) {
1247 const struct type
*t
;
1248 get_one(ctx
, &slot_dr
);
1249 t
= get_type_of_local(ctx
, slot_dr
);
1250 if (!TYPE_TAG_IS_BUILTIN(t
->tag
)) {
1254 if (unlikely(!flag_is_clear(ctx
, slot_dr
))) {
1260 if (code
== OPCODE_DEREFERENCE_CLEAR
) {
1264 if (unlikely(code
!= OPCODE_JMP_FALSE
))
1265 internal(file_line
, "gen_fused_binary: binary operation is not followed by jmp false: %x, %s", code
, decode_opcode(code
, true));
1266 get_one(ctx
, &slot_test
);
1267 if (unlikely(slot_test
!= slot_r
))
1268 internal(file_line
, "gen_fused_binary: the result of the binary operation and the tested variable do not match");
1269 offs_false
= get_jump_offset(ctx
);
1270 get_jump_offset(ctx
);
1272 if (mode
== MODE_ARRAY_LEN_GT
) {
1273 g(gen_array_len(ctx
, slot_1
, slot_2
, slot_r
, true, offs_false
));
1274 } else if (mode
== MODE_REAL
) {
1275 g(gen_fp_alu_jmp(ctx
, op_size
, op
, escape_label
, slot_1
, slot_2
, offs_false
, failed
));
1277 g(gen_alu_jmp(ctx
, mode
, op_size
, op
, slot_1
, slot_2
, offs_false
, failed
));
1282 ctx
->current_position
= backup
;
1287 static bool attr_w
gen_function(struct codegen_context
*ctx
)
1289 ctx
->current_position
= da(ctx
->fn
,function
)->code
;
1291 ctx
->escape_nospill_label
= alloc_label(ctx
);
1292 if (unlikely(!ctx
->escape_nospill_label
))
1295 while (ctx
->current_position
!= da(ctx
->fn
,function
)->code
+ da(ctx
->fn
,function
)->code_size
) {
1299 frame_t slot_1
, slot_2
, slot_3
, slot_r
, flags
, fn_idx
, opt
;
1300 arg_t n_args
, n_ret
, i_arg
;
1302 uint32_t escape_label
;
1305 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
));
1307 ctx
->instr_start
= ctx
->current_position
;
1309 /*debug("%s: %04x, %s", da(ctx->fn,function)->function_name, *ctx->instr_start, decode_opcode(*ctx->instr_start, true));*/
1311 ip
= ctx
->instr_start
- da(ctx
->fn
,function
)->code
;
1312 if (likely(!ctx
->code_labels
[ip
])) {
1313 ctx
->code_labels
[ip
] = alloc_label(ctx
);
1314 if (unlikely(!ctx
->code_labels
[ip
]))
1317 gen_label(ctx
->code_labels
[ip
]);
1319 code
= get_code(ctx
);
1320 ctx
->arg_mode
= code
/ OPCODE_MODE_MULT
;
1321 code
%= OPCODE_MODE_MULT
;
1322 ajla_assert_lo(ctx
->arg_mode
< ARG_MODE_N
, (file_line
, "gen_function: invalid opcode %04x", (unsigned)*ctx
->instr_start
));
1324 if (code
>= OPCODE_FIXED_OP
+ uzero
&& code
< OPCODE_INT_OP
) {
1325 code
-= OPCODE_FIXED_OP
;
1326 op
= (code
/ OPCODE_FIXED_OP_MULT
) % OPCODE_FIXED_TYPE_MULT
;
1327 type
= code
/ OPCODE_FIXED_TYPE_MULT
;
1328 if (op
< OPCODE_FIXED_OP_C
) {
1329 get_two(ctx
, &slot_1
, &slot_2
);
1330 get_two(ctx
, &slot_r
, &flags
);
1331 escape_label
= alloc_escape_label(ctx
);
1332 if (unlikely(!escape_label
))
1334 g(gen_test_2_cached(ctx
, slot_1
, slot_2
, escape_label
));
1335 flag_set(ctx
, slot_1
, false);
1336 flag_set(ctx
, slot_2
, false);
1337 flag_set(ctx
, slot_r
, false);
1338 if (flags
& OPCODE_FLAG_FUSED
) {
1339 g(gen_fused_binary(ctx
, MODE_FIXED
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1340 if (unlikely(!failed
))
1343 g(gen_alu(ctx
, MODE_FIXED
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1345 } else if (op
< OPCODE_FIXED_OP_UNARY
) {
1346 op
-= OPCODE_FIXED_OP_C
;
1347 get_two(ctx
, &slot_1
, &slot_2
);
1348 get_two(ctx
, &slot_r
, &flags
);
1349 escape_label
= alloc_escape_label(ctx
);
1350 if (unlikely(!escape_label
))
1352 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1353 flag_set(ctx
, slot_1
, false);
1354 flag_set(ctx
, slot_r
, false);
1355 slot_2
= frame_t_from_const((int32_t)slot_2
);
1356 if (flags
& OPCODE_FLAG_FUSED
) {
1357 g(gen_fused_binary(ctx
, MODE_FIXED
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1358 if (unlikely(!failed
))
1361 g(gen_alu(ctx
, MODE_FIXED
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1363 } else if (op
< OPCODE_FIXED_OP_N
) {
1364 get_two(ctx
, &slot_1
, &slot_r
);
1365 get_one(ctx
, &flags
);
1366 escape_label
= alloc_escape_label(ctx
);
1367 if (unlikely(!escape_label
))
1369 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1370 flag_set(ctx
, slot_1
, false);
1371 flag_set(ctx
, slot_r
, false);
1372 g(gen_alu1(ctx
, MODE_FIXED
, type
, op
, escape_label
, slot_1
, slot_r
));
1374 } else if (op
== OPCODE_FIXED_OP_ldc
) {
1376 get_one(ctx
, &slot_r
);
1377 g(gen_constant(ctx
, false, type
, false, slot_r
));
1378 for (i
= 0; i
< 1U << type
; i
+= 2)
1380 flag_set(ctx
, slot_r
, false);
1382 } else if (op
== OPCODE_FIXED_OP_ldc16
) {
1383 get_one(ctx
, &slot_r
);
1384 g(gen_constant(ctx
, false, type
, true, slot_r
));
1386 flag_set(ctx
, slot_r
, false);
1388 } else if (op
== OPCODE_FIXED_OP_move
|| op
== OPCODE_FIXED_OP_copy
) {
1389 get_two(ctx
, &slot_1
, &slot_r
);
1390 escape_label
= alloc_escape_label(ctx
);
1391 if (unlikely(!escape_label
))
1393 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1394 flag_set(ctx
, slot_1
, false);
1395 flag_set(ctx
, slot_r
, false);
1396 g(gen_copy(ctx
, type
, slot_1
, slot_r
));
1399 internal(file_line
, "gen_function: bad fixed code %04x", *ctx
->instr_start
);
1401 } else if (code
>= OPCODE_INT_OP
&& code
< OPCODE_REAL_OP
) {
1402 code
-= OPCODE_INT_OP
;
1403 op
= (code
/ OPCODE_INT_OP_MULT
) % OPCODE_INT_TYPE_MULT
;
1404 type
= code
/ OPCODE_INT_TYPE_MULT
;
1405 if (op
< OPCODE_INT_OP_C
) {
1406 get_two(ctx
, &slot_1
, &slot_2
);
1407 get_two(ctx
, &slot_r
, &flags
);
1408 escape_label
= alloc_escape_label(ctx
);
1409 if (unlikely(!escape_label
))
1411 g(gen_test_2_cached(ctx
, slot_1
, slot_2
, escape_label
));
1412 flag_set(ctx
, slot_1
, false);
1413 flag_set(ctx
, slot_2
, false);
1414 flag_set(ctx
, slot_r
, false);
1415 if (flags
& OPCODE_FLAG_FUSED
) {
1416 g(gen_fused_binary(ctx
, MODE_INT
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1417 if (unlikely(!failed
))
1420 g(gen_alu(ctx
, MODE_INT
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1422 } else if (op
< OPCODE_INT_OP_UNARY
) {
1423 op
-= OPCODE_INT_OP_C
;
1424 get_two(ctx
, &slot_1
, &slot_2
);
1425 get_two(ctx
, &slot_r
, &flags
);
1426 escape_label
= alloc_escape_label(ctx
);
1427 if (unlikely(!escape_label
))
1429 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1430 flag_set(ctx
, slot_1
, false);
1431 flag_set(ctx
, slot_r
, false);
1432 slot_2
= frame_t_from_const((int32_t)slot_2
);
1433 if (flags
& OPCODE_FLAG_FUSED
) {
1434 g(gen_fused_binary(ctx
, MODE_INT
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1435 if (unlikely(!failed
))
1438 g(gen_alu(ctx
, MODE_INT
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1440 } else if (op
< OPCODE_INT_OP_N
) {
1441 get_two(ctx
, &slot_1
, &slot_r
);
1442 get_one(ctx
, &flags
);
1443 if ((op
== OPCODE_INT_OP_to_int
|| op
== OPCODE_INT_OP_from_int
) && slot_1
== slot_r
)
1445 escape_label
= alloc_escape_label(ctx
);
1446 if (unlikely(!escape_label
))
1448 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1449 flag_set(ctx
, slot_1
, false);
1450 flag_set(ctx
, slot_r
, false);
1451 g(gen_alu1(ctx
, MODE_INT
, type
, op
, escape_label
, slot_1
, slot_r
));
1453 } else if (op
== OPCODE_INT_OP_ldc
) {
1455 get_one(ctx
, &slot_r
);
1456 g(gen_constant(ctx
, false, type
, false, slot_r
));
1457 for (i
= 0; i
< 1U << type
; i
+= 2)
1459 flag_set(ctx
, slot_r
, false);
1461 } else if (op
== OPCODE_INT_OP_ldc16
) {
1462 get_one(ctx
, &slot_r
);
1463 g(gen_constant(ctx
, false, type
, true, slot_r
));
1465 flag_set(ctx
, slot_r
, false);
1467 } else if (op
== OPCODE_INT_OP_move
|| op
== OPCODE_INT_OP_copy
) {
1468 get_two(ctx
, &slot_1
, &slot_r
);
1469 escape_label
= alloc_escape_label(ctx
);
1470 if (unlikely(!escape_label
))
1472 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1473 flag_set(ctx
, slot_1
, false);
1474 flag_set(ctx
, slot_r
, false);
1475 g(gen_copy(ctx
, type
, slot_1
, slot_r
));
1478 internal(file_line
, "gen_function: bad integer code %04x", *ctx
->instr_start
);
1480 } else if (code
>= OPCODE_REAL_OP
&& code
< OPCODE_BOOL_OP
) {
1481 code
-= OPCODE_REAL_OP
;
1482 op
= (code
/ OPCODE_REAL_OP_MULT
) % OPCODE_REAL_TYPE_MULT
;
1483 type
= code
/ OPCODE_REAL_TYPE_MULT
;
1484 if (op
< OPCODE_REAL_OP_UNARY
) {
1485 get_two(ctx
, &slot_1
, &slot_2
);
1486 get_two(ctx
, &slot_r
, &flags
);
1487 escape_label
= alloc_escape_label(ctx
);
1488 if (unlikely(!escape_label
))
1490 g(gen_test_2_cached(ctx
, slot_1
, slot_2
, escape_label
));
1491 flag_set(ctx
, slot_1
, false);
1492 flag_set(ctx
, slot_2
, false);
1493 flag_set(ctx
, slot_r
, false);
1494 if (flags
& OPCODE_FLAG_FUSED
) {
1495 g(gen_fused_binary(ctx
, MODE_REAL
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1496 if (unlikely(!failed
))
1499 g(gen_fp_alu(ctx
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1501 } else if (op
< OPCODE_REAL_OP_N
) {
1502 get_two(ctx
, &slot_1
, &slot_r
);
1503 get_one(ctx
, &flags
);
1504 escape_label
= alloc_escape_label(ctx
);
1505 if (unlikely(!escape_label
))
1507 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1508 flag_set(ctx
, slot_1
, false);
1509 flag_set(ctx
, slot_r
, false);
1510 g(gen_fp_alu1(ctx
, type
, op
, escape_label
, slot_1
, slot_r
));
1512 } else if (op
== OPCODE_REAL_OP_ldc
) {
1513 const struct type
*t
;
1515 get_one(ctx
, &slot_r
);
1516 t
= type_get_real(type
);
1517 g(gen_real_constant(ctx
, t
, slot_r
));
1518 for (i
= 0; i
< t
->size
; i
+= 2)
1520 flag_set(ctx
, slot_r
, false);
1522 } else if (op
== OPCODE_REAL_OP_move
|| op
== OPCODE_REAL_OP_copy
) {
1523 get_two(ctx
, &slot_1
, &slot_r
);
1524 escape_label
= alloc_escape_label(ctx
);
1525 if (unlikely(!escape_label
))
1527 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1528 flag_set(ctx
, slot_1
, false);
1529 flag_set(ctx
, slot_r
, false);
1530 g(gen_memcpy_slots(ctx
, slot_r
, slot_1
));
1533 internal(file_line
, "gen_function: bad real code %04x", *ctx
->instr_start
);
1535 } else if (code
>= OPCODE_BOOL_OP
&& code
< OPCODE_EXTRA
) {
1536 code
-= OPCODE_BOOL_OP
;
1537 op
= (code
/ OPCODE_BOOL_OP_MULT
) % OPCODE_BOOL_TYPE_MULT
;
1538 type
= log_2(sizeof(ajla_flat_option_t
));
1539 if (op
< OPCODE_BOOL_OP_UNARY
) {
1540 get_two(ctx
, &slot_1
, &slot_2
);
1541 get_two(ctx
, &slot_r
, &flags
);
1542 escape_label
= alloc_escape_label(ctx
);
1543 if (unlikely(!escape_label
))
1545 g(gen_test_2_cached(ctx
, slot_1
, slot_2
, escape_label
));
1546 flag_set(ctx
, slot_1
, false);
1547 flag_set(ctx
, slot_2
, false);
1548 flag_set(ctx
, slot_r
, false);
1549 if (flags
& OPCODE_FLAG_FUSED
) {
1550 g(gen_fused_binary(ctx
, MODE_BOOL
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
1551 if (unlikely(!failed
))
1554 g(gen_alu(ctx
, MODE_BOOL
, type
, op
, escape_label
, slot_1
, slot_2
, slot_r
));
1556 } else if (op
< OPCODE_BOOL_OP_N
) {
1557 get_two(ctx
, &slot_1
, &slot_r
);
1558 get_one(ctx
, &flags
);
1559 escape_label
= alloc_escape_label(ctx
);
1560 if (unlikely(!escape_label
))
1562 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1563 flag_set(ctx
, slot_1
, false);
1564 flag_set(ctx
, slot_r
, false);
1565 g(gen_alu1(ctx
, MODE_BOOL
, type
, op
, escape_label
, slot_1
, slot_r
));
1567 } else if (op
== OPCODE_BOOL_OP_move
|| op
== OPCODE_BOOL_OP_copy
) {
1568 get_two(ctx
, &slot_1
, &slot_r
);
1569 escape_label
= alloc_escape_label(ctx
);
1570 if (unlikely(!escape_label
))
1572 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1573 flag_set(ctx
, slot_1
, false);
1574 flag_set(ctx
, slot_r
, false);
1575 g(gen_copy(ctx
, type
, slot_1
, slot_r
));
1578 internal(file_line
, "gen_function: bad boolean code %04x", *ctx
->instr_start
);
1580 } else switch (code
) {
1581 case OPCODE_INT_LDC_LONG
: {
1583 get_one(ctx
, &slot_r
);
1584 words
= get_uint32(ctx
);
1585 for (w
= 0; w
< words
; w
++)
1587 unconditional_escape
:
1588 escape_label
= alloc_escape_label(ctx
);
1589 if (unlikely(!escape_label
))
1591 gen_insn(INSN_JMP
, 0, 0, 0);
1592 gen_four(escape_label
);
1595 case OPCODE_IS_EXCEPTION
: {
1596 get_two(ctx
, &slot_1
, &slot_r
);
1597 get_one(ctx
, &flags
);
1598 g(gen_is_exception(ctx
, slot_1
, slot_r
));
1601 case OPCODE_EXCEPTION_CLASS
:
1602 case OPCODE_EXCEPTION_TYPE
:
1603 case OPCODE_EXCEPTION_AUX
: {
1604 get_two(ctx
, &slot_1
, &slot_r
);
1605 get_one(ctx
, &flags
);
1606 goto unconditional_escape
;
1608 case OPCODE_SYSTEM_PROPERTY
: {
1609 get_two(ctx
, &slot_1
, &slot_r
);
1610 get_one(ctx
, &flags
);
1611 g(gen_system_property(ctx
, slot_1
, slot_r
));
1614 case OPCODE_FLAT_MOVE
:
1615 case OPCODE_FLAT_COPY
: {
1616 get_two(ctx
, &slot_1
, &slot_r
);
1617 g(gen_flat_move_copy(ctx
, slot_1
, slot_r
));
1620 case OPCODE_REF_MOVE
:
1621 case OPCODE_REF_MOVE_CLEAR
:
1622 case OPCODE_REF_COPY
: {
1623 get_two(ctx
, &slot_1
, &slot_r
);
1624 g(gen_ref_move_copy(ctx
, code
, slot_1
, slot_r
));
1627 case OPCODE_BOX_MOVE_CLEAR
:
1628 case OPCODE_BOX_COPY
: {
1629 get_two(ctx
, &slot_1
, &slot_r
);
1630 g(gen_box_move_copy(ctx
, code
, slot_1
, slot_r
));
1633 case OPCODE_TAKE_BORROWED
:
1634 get_one(ctx
, &slot_1
);
1635 if (!da(ctx
->fn
,function
)->local_variables_flags
[slot_1
].may_be_borrowed
)
1637 if (unlikely(!(label_id
= alloc_label(ctx
))))
1639 if (flag_is_set(ctx
, slot_1
))
1640 goto take_borrowed_done
;
1641 if (flag_is_clear(ctx
, slot_1
)) {
1642 g(gen_set_1(ctx
, R_FRAME
, slot_1
, 0, true));
1643 goto do_take_borrowed
;
1645 g(gen_test_1(ctx
, R_FRAME
, slot_1
, 0, label_id
, false, TEST_SET
));
1647 g(gen_upcall_start(ctx
, offsetof(struct cg_upcall_vector_s
, cg_upcall_pointer_reference_owned
), 1));
1648 g(gen_frame_load(ctx
, OP_SIZE_SLOT
, garbage
, slot_1
, 0, false, R_ARG0
));
1649 g(gen_upcall_argument(ctx
, 0));
1650 g(gen_upcall(ctx
, offsetof(struct cg_upcall_vector_s
, cg_upcall_pointer_reference_owned
), 1));
1651 flag_set(ctx
, slot_1
, true);
1653 gen_label(label_id
);
1655 case OPCODE_DEREFERENCE
:
1656 case OPCODE_DEREFERENCE_CLEAR
: {
1658 /*const struct type *type;*/
1659 get_one(ctx
, &slot_1
);
1660 if (flag_is_clear(ctx
, slot_1
))
1661 goto skip_dereference
;
1662 /*type = get_type_of_local(ctx, slot_1);*/
1663 /*need_bit_test = 1 || TYPE_IS_FLAT(type) || da(ctx->fn,function)->local_variables[slot_1].may_be_borrowed;*/
1664 need_bit_test
= !flag_is_set(ctx
, slot_1
);
1665 if (need_bit_test
) {
1666 if (unlikely(!(label_id
= alloc_label(ctx
))))
1668 g(gen_test_1(ctx
, R_FRAME
, slot_1
, 0, label_id
, true, TEST_CLEAR
));
1670 g(gen_set_1(ctx
, R_FRAME
, slot_1
, 0, false));
1671 label_id
= 0; /* avoid warning */
1673 g(gen_upcall_start(ctx
, offsetof(struct cg_upcall_vector_s
, cg_upcall_pointer_dereference
), 1));
1674 g(gen_frame_load(ctx
, OP_SIZE_SLOT
, garbage
, slot_1
, 0, false, R_ARG0
));
1675 g(gen_upcall_argument(ctx
, 0));
1676 g(gen_upcall(ctx
, offsetof(struct cg_upcall_vector_s
, cg_upcall_pointer_dereference
), 1));
1678 gen_label(label_id
);
1680 if (code
== OPCODE_DEREFERENCE_CLEAR
)
1681 g(gen_frame_clear(ctx
, OP_SIZE_SLOT
, slot_1
));
1682 flag_set_unknown(ctx
, slot_1
);
1683 flag_set(ctx
, slot_1
, false);
1687 get_one(ctx
, &slot_1
);
1688 g(gen_eval(ctx
, slot_1
));
1691 case OPCODE_ESCAPE_NONFLAT
: {
1696 vars
= mem_alloc_array_mayfail(mem_alloc_mayfail
, frame_t
*, 0, 0, n
, sizeof(frame_t
), &ctx
->err
);
1697 if (unlikely(!vars
))
1699 for (i
= 0; i
< n
; i
++) {
1700 get_one(ctx
, &vars
[i
]);
1703 escape_label
= alloc_escape_label(ctx
);
1704 if (unlikely(!escape_label
)) {
1709 if (unlikely(!gen_test_variables(ctx
, vars
, n
, escape_label
))) {
1717 case OPCODE_CHECKPOINT
: {
1720 g(clear_flag_cache(ctx
));
1722 if (SIZEOF_IP_T
== 2) {
1723 slot_1
= get_code(ctx
);
1724 } else if (SIZEOF_IP_T
== 4) {
1725 slot_1
= get_uint32(ctx
);
1731 if (unlikely(!(slot_1
+ 1)))
1733 while (slot_1
>= ctx
->n_entries
) {
1736 if (unlikely(!ctx
->entries
)) {
1737 if (unlikely(!array_init_mayfail(struct cg_entry
, &ctx
->entries
, &ctx
->n_entries
, &ctx
->err
)))
1740 memset(&e
, 0, sizeof(struct cg_entry
));
1741 if (unlikely(!array_add_mayfail(struct cg_entry
, &ctx
->entries
, &ctx
->n_entries
, e
, &err_entries
, &ctx
->err
))) {
1742 ctx
->entries
= err_entries
;
1747 get_one(ctx
, &n_vars
);
1749 escape_label
= 0; /* avoid warning */
1750 if (likely(slot_1
!= 0)) {
1751 escape_label
= alloc_escape_label(ctx
);
1752 if (unlikely(!escape_label
))
1756 if (n_vars
|| !slot_1
) {
1758 uint32_t entry_label
, nonflat_label
;
1759 struct cg_entry
*ce
= &ctx
->entries
[slot_1
];
1761 if (unlikely(!array_init_mayfail(frame_t
, &ce
->variables
, &ce
->n_variables
, &ctx
->err
)))
1763 for (i
= 0; i
< n_vars
; i
++) {
1766 if (unlikely(!array_add_mayfail(frame_t
, &ce
->variables
, &ce
->n_variables
, v
, NULL
, &ctx
->err
)))
1770 g(gen_test_variables(ctx
, ce
->variables
, ce
->n_variables
, ctx
->escape_nospill_label
));
1772 entry_label
= alloc_label(ctx
);
1773 if (unlikely(!entry_label
))
1775 gen_label(entry_label
);
1776 ce
->entry_label
= entry_label
;
1778 nonflat_label
= alloc_escape_label_for_ip(ctx
, ctx
->current_position
);
1779 if (unlikely(!nonflat_label
))
1781 ce
->nonflat_label
= nonflat_label
;
1783 if (unlikely(!slot_1
))
1784 g(gen_timestamp_test(ctx
, ctx
->escape_nospill_label
));
1786 g(gen_timestamp_test(ctx
, escape_label
));
1788 g(gen_timestamp_test(ctx
, escape_label
));
1790 gen_insn(INSN_ENTRY
, 0, 0, 0);
1796 int32_t x
= get_jump_offset(ctx
);
1797 g(gen_jump(ctx
, x
, OP_SIZE_NATIVE
, COND_ALWAYS
, -1U, -1U));
1800 case OPCODE_JMP_BACK_16
: {
1801 int32_t x
= get_code(ctx
);
1802 g(gen_jump(ctx
, -x
- (int)(2 * sizeof(code_t
)), OP_SIZE_NATIVE
, COND_ALWAYS
, -1U, -1U));
1805 case OPCODE_JMP_FALSE
: {
1807 get_one(ctx
, &slot_1
);
1808 offs_false
= get_jump_offset(ctx
);
1809 get_jump_offset(ctx
);
1810 escape_label
= alloc_escape_label(ctx
);
1811 if (unlikely(!escape_label
))
1813 g(gen_test_1_cached(ctx
, slot_1
, escape_label
));
1814 flag_set(ctx
, slot_1
, false);
1815 g(gen_cond_jump(ctx
, slot_1
, offs_false
));
1818 case OPCODE_LABEL
: {
1819 g(clear_flag_cache(ctx
));
1824 if (ctx->args != NULL) \
1825 mem_free(ctx->args); \
1826 g(array_init_mayfail(struct code_arg, &ctx->args, &ctx->args_l, &ctx->err));\
1831 for (i_arg = 0; i_arg < n_args; i_arg++) { \
1832 struct code_arg a; \
1833 get_two(ctx, &a.slot, &a.flags); \
1835 g(array_add_mayfail(struct code_arg, &ctx->args, &ctx->args_l, a, NULL, &ctx->err));\
1838 case OPCODE_LOAD_FN
:
1839 get_two(ctx
, &n_args
, &slot_r
);
1840 get_one(ctx
, &fn_idx
);
1842 g(gen_load_fn_or_curry(ctx
, fn_idx
, NO_FRAME_T
, slot_r
, 0));
1845 get_two(ctx
, &n_args
, &slot_r
);
1846 get_two(ctx
, &slot_1
, &flags
);
1848 g(gen_load_fn_or_curry(ctx
, NO_FRAME_T
, slot_1
, slot_r
, flags
));
1851 case OPCODE_CALL_STRICT
:
1852 case OPCODE_CALL_SPARK
:
1853 case OPCODE_CALL_LAZY
:
1854 case OPCODE_CALL_CACHE
:
1855 case OPCODE_CALL_SAVE
: {
1856 get_two(ctx
, &n_args
, &n_ret
);
1857 get_one(ctx
, &fn_idx
);
1858 jump_over_arguments_and_return
:
1860 ctx
->return_values
= ctx
->current_position
;
1861 for (i_arg
= 0; i_arg
< n_ret
; i_arg
++) {
1869 if (unlikely(profiling
))
1870 goto unconditional_escape
;
1871 if (code
== OPCODE_CALL
|| code
== OPCODE_CALL_STRICT
) {
1872 g(gen_call(ctx
, code
, fn_idx
));
1875 /*if (code == OPCODE_CALL_INDIRECT || code == OPCODE_CALL_INDIRECT_STRICT) {
1876 if (unlikely(!gen_call_indirect(ctx, code, slot_1, flags)))
1880 goto unconditional_escape
;
1882 case OPCODE_CALL_INDIRECT
:
1883 case OPCODE_CALL_INDIRECT_STRICT
:
1884 case OPCODE_CALL_INDIRECT_SPARK
:
1885 case OPCODE_CALL_INDIRECT_LAZY
:
1886 case OPCODE_CALL_INDIRECT_CACHE
:
1887 case OPCODE_CALL_INDIRECT_SAVE
: {
1888 fn_idx
= 0; /* avoid warning */
1889 get_two(ctx
, &n_args
, &n_ret
);
1890 get_two(ctx
, &slot_1
, &flags
);
1891 goto jump_over_arguments_and_return
;
1893 case OPCODE_RETURN
: {
1894 n_args
= da(ctx
->fn
,function
)->n_return_values
;
1896 if (unlikely(profiling
))
1897 goto unconditional_escape
;
1901 case OPCODE_STRUCTURED
: {
1903 get_two(ctx
, &slot_1
, &slot_2
);
1906 get_two(ctx
, &flags
, &slot_r
);
1911 g(array_add_mayfail(struct code_arg
, &ctx
->args
, &ctx
->args_l
, a
, NULL
, &ctx
->err
));
1912 } while (!(flags
& OPCODE_STRUCTURED_FLAG_END
));
1913 g(gen_structured(ctx
, slot_1
, slot_2
));
1916 case OPCODE_RECORD_CREATE
: {
1918 get_two(ctx
, &slot_r
, &n_args
);
1919 for (i_arg
= 0; i_arg
< n_args
; i_arg
++) {
1921 get_two(ctx
, &slot_1
, &flags
);
1925 g(array_add_mayfail(struct code_arg
, &ctx
->args
, &ctx
->args_l
, a
, NULL
, &ctx
->err
));
1927 g(gen_record_create(ctx
, slot_r
));
1930 case OPCODE_RECORD_LOAD
: {
1931 get_two(ctx
, &slot_1
, &opt
);
1932 get_two(ctx
, &slot_r
, &flags
);
1933 g(gen_record_load(ctx
, slot_1
, slot_r
, opt
, flags
));
1936 case OPCODE_OPTION_CREATE_EMPTY_FLAT
: {
1937 get_two(ctx
, &slot_r
, &opt
);
1938 g(gen_option_create_empty_flat(ctx
, opt
, slot_r
));
1941 case OPCODE_OPTION_CREATE_EMPTY
: {
1942 get_two(ctx
, &slot_r
, &opt
);
1943 g(gen_option_create_empty(ctx
, opt
, slot_r
));
1946 case OPCODE_OPTION_CREATE
: {
1947 get_two(ctx
, &slot_r
, &opt
);
1948 get_two(ctx
, &slot_1
, &flags
);
1949 g(gen_option_create(ctx
, opt
, slot_1
, slot_r
, flags
));
1952 case OPCODE_OPTION_LOAD
: {
1953 get_two(ctx
, &slot_1
, &opt
);
1954 get_two(ctx
, &slot_r
, &flags
);
1955 g(gen_option_load(ctx
, slot_1
, slot_r
, opt
, flags
));
1958 case OPCODE_OPTION_TEST_FLAT
: {
1959 get_two(ctx
, &slot_1
, &opt
);
1960 get_one(ctx
, &slot_r
);
1961 g(gen_option_test_flat(ctx
, slot_1
, opt
, slot_r
));
1964 case OPCODE_OPTION_TEST
: {
1965 get_two(ctx
, &slot_1
, &opt
);
1966 get_one(ctx
, &slot_r
);
1967 g(gen_option_test(ctx
, slot_1
, opt
, slot_r
));
1970 case OPCODE_OPTION_ORD_FLAT
: {
1971 get_two(ctx
, &slot_1
, &slot_r
);
1972 g(gen_option_ord(ctx
, slot_1
, slot_r
, true));
1975 case OPCODE_OPTION_ORD
: {
1976 get_two(ctx
, &slot_1
, &slot_r
);
1977 g(gen_option_ord(ctx
, slot_1
, slot_r
, false));
1980 case OPCODE_ARRAY_CREATE
: {
1982 get_two(ctx
, &slot_r
, &n_args
);
1983 for (i_arg
= 0; i_arg
< n_args
; i_arg
++) {
1985 get_two(ctx
, &slot_1
, &flags
);
1989 g(array_add_mayfail(struct code_arg
, &ctx
->args
, &ctx
->args_l
, a
, NULL
, &ctx
->err
));
1991 g(gen_array_create(ctx
, slot_r
));
1994 case OPCODE_ARRAY_CREATE_EMPTY_FLAT
: {
1995 get_two(ctx
, &slot_r
, &flags
);
1996 g(gen_array_create_empty_flat(ctx
, slot_r
, flags
));
1999 case OPCODE_ARRAY_CREATE_EMPTY
: {
2000 get_one(ctx
, &slot_r
);
2001 g(gen_array_create_empty(ctx
, slot_r
));
2004 case OPCODE_ARRAY_FILL
: {
2005 get_two(ctx
, &slot_1
, &flags
);
2006 get_two(ctx
, &slot_2
, &slot_r
);
2007 g(gen_array_fill(ctx
, slot_1
, flags
, slot_2
, slot_r
));
2010 case OPCODE_ARRAY_STRING
: {
2012 get_two(ctx
, &slot_r
, &i
);
2013 g(gen_array_string(ctx
, type_get_fixed(0, true)->tag
, cast_ptr(uint8_t *, ctx
->current_position
), i
, slot_r
));
2014 ctx
->current_position
+= (i
+ 1) >> 1;
2017 case OPCODE_ARRAY_UNICODE
: {
2019 get_two(ctx
, &slot_r
, &i
);
2020 g(gen_array_string(ctx
, type_get_int(2)->tag
, cast_ptr(uint8_t *, ctx
->current_position
), i
, slot_r
));
2021 ctx
->current_position
+= i
* 2;
2024 case OPCODE_ARRAY_LOAD
: {
2025 get_two(ctx
, &slot_1
, &slot_2
);
2026 get_two(ctx
, &slot_r
, &flags
);
2027 g(gen_array_load(ctx
, slot_1
, slot_2
, slot_r
, flags
));
2030 case OPCODE_ARRAY_LEN
: {
2031 get_two(ctx
, &slot_1
, &slot_r
);
2032 get_one(ctx
, &flags
);
2033 g(gen_array_len(ctx
, slot_1
, NO_FRAME_T
, slot_r
, false, 0));
2036 case OPCODE_ARRAY_LEN_GREATER_THAN
: {
2037 get_two(ctx
, &slot_1
, &slot_2
);
2038 get_two(ctx
, &slot_r
, &flags
);
2039 escape_label
= alloc_escape_label(ctx
);
2040 if (unlikely(!escape_label
))
2042 if (flags
& OPCODE_FLAG_FUSED
) {
2043 g(gen_fused_binary(ctx
, MODE_ARRAY_LEN_GT
, 0, 0, escape_label
, slot_1
, slot_2
, slot_r
, &failed
));
2044 if (unlikely(!failed
))
2047 g(gen_array_len(ctx
, slot_1
, slot_2
, slot_r
, false, 0));
2050 case OPCODE_ARRAY_SUB
: {
2051 get_two(ctx
, &slot_1
, &slot_2
);
2052 get_two(ctx
, &slot_3
, &slot_r
);
2053 get_one(ctx
, &flags
);
2054 g(gen_array_sub(ctx
, slot_1
, slot_2
, slot_3
, slot_r
, flags
));
2057 case OPCODE_ARRAY_SKIP
: {
2058 get_two(ctx
, &slot_1
, &slot_2
);
2059 get_two(ctx
, &slot_r
, &flags
);
2060 g(gen_array_skip(ctx
, slot_1
, slot_2
, slot_r
, flags
));
2063 case OPCODE_ARRAY_APPEND
: {
2064 get_two(ctx
, &slot_r
, &flags
);
2065 get_two(ctx
, &slot_1
, &slot_2
);
2066 g(gen_array_append(ctx
, slot_1
, slot_2
, slot_r
, flags
));
2069 case OPCODE_ARRAY_APPEND_ONE_FLAT
: {
2070 get_two(ctx
, &slot_r
, &flags
);
2071 get_two(ctx
, &slot_1
, &slot_2
);
2072 g(gen_array_append_one_flat(ctx
, slot_1
, slot_2
, slot_r
, flags
));
2075 case OPCODE_ARRAY_APPEND_ONE
: {
2076 get_two(ctx
, &slot_r
, &flags
);
2077 get_two(ctx
, &slot_1
, &slot_2
);
2078 g(gen_array_append_one(ctx
, slot_1
, slot_2
, slot_r
, flags
));
2081 case OPCODE_ARRAY_FLATTEN
: {
2082 get_two(ctx
, &slot_r
, &flags
);
2083 get_one(ctx
, &slot_1
);
2084 goto unconditional_escape
;
2087 get_two(ctx
, &flags
, &slot_1
);
2088 get_two(ctx
, &slot_2
, &slot_3
);
2089 g(gen_io(ctx
, flags
, slot_1
, slot_2
, slot_3
));
2092 case OPCODE_INTERNAL_FUNCTION
:
2093 case OPCODE_EXIT_THREAD
:
2094 case OPCODE_UNREACHABLE
: {
2095 goto unconditional_escape
;
2099 /*if (getenv("DUMP") && !strcmp(da(ctx->fn,function)->function_name, getenv("DUMP")))*/
2100 warning("gen_function: %s: unknown opcode %04x, %s", da(ctx
->fn
,function
)->function_name
, *ctx
->instr_start
, decode_opcode(*ctx
->instr_start
, false));
2110 static bool attr_w
gen_entries(struct codegen_context
*ctx
)
2113 for (i
= 0; i
< ctx
->n_entries
; i
++) {
2114 struct cg_entry
*ce
= &ctx
->entries
[i
];
2115 if (ce
->entry_label
) {
2116 gen_insn(INSN_ENTRY
, 0, 0, 0);
2119 g(gen_test_variables(ctx
, ce
->variables
, ce
->n_variables
, ce
->nonflat_label
));
2121 gen_insn(INSN_JMP
, 0, 0, 0);
2122 gen_four(ce
->entry_label
);
2128 static bool attr_w
gen_epilogues(struct codegen_context
*ctx
)
2132 uint32_t escape_label
, nospill_label
;
2133 escape_label
= alloc_label(ctx
);
2134 if (unlikely(!escape_label
))
2136 nospill_label
= alloc_label(ctx
);
2137 if (unlikely(!nospill_label
))
2139 #if defined(ARCH_PARISC)
2140 if (ctx
->call_label
) {
2141 gen_label(ctx
->call_label
);
2142 g(gen_call_millicode(ctx
));
2145 if (ctx
->reload_label
) {
2146 gen_label(ctx
->reload_label
);
2147 g(gen_mov(ctx
, i_size(OP_SIZE_ADDRESS
), R_FRAME
, R_RET0
));
2148 g(gen_escape_arg(ctx
, (ip_t
)-1, nospill_label
));
2150 gen_label(ctx
->escape_nospill_label
);
2151 g(gen_escape_arg(ctx
, 0, nospill_label
));
2152 for (ip
= 0; ip
< da(ctx
->fn
,function
)->code_size
; ip
++) {
2153 struct cg_exit
*ce
= ctx
->code_exits
[ip
];
2154 if (ce
&& (ce
->undo_label
|| ce
->escape_label
)) {
2155 if (ce
->undo_label
) {
2157 gen_label(ce
->undo_label
);
2158 gen_insn(ce
->undo_opcode
, ce
->undo_op_size
, ce
->undo_aux
, ce
->undo_writes_flags
);
2159 for (i
= 0; i
< ce
->undo_parameters_len
; i
++)
2160 gen_one(ce
->undo_parameters
[i
]);
2162 if (ce
->escape_label
) {
2163 gen_label(ce
->escape_label
);
2165 g(gen_escape_arg(ctx
, ip
, escape_label
));
2168 gen_label(escape_label
);
2169 for (v
= MIN_USEABLE_SLOT
; v
< function_n_variables(ctx
->fn
); v
++) {
2170 if (slot_is_register(ctx
, v
)) {
2174 gen_label(nospill_label
);
2179 static bool attr_w
cgen_entry(struct codegen_context
*ctx
)
2181 uint32_t entry_id
= cget_four(ctx
);
2182 ajla_assert_lo(entry_id
< ctx
->n_entries
, (file_line
, "cgen_entry: invalid entry %lx", (unsigned long)entry_id
));
2183 ctx
->entries
[entry_id
].entry_to_pos
= ctx
->mcode_size
;
2187 static bool attr_w
cgen_label(struct codegen_context
*ctx
)
2189 uint32_t label_id
= cget_four(ctx
);
2190 ctx
->label_to_pos
[label_id
] = ctx
->mcode_size
;
2194 static bool attr_w attr_unused
cgen_trap(struct codegen_context
*ctx
, uint32_t label
)
2196 struct trap_record tr
;
2197 tr
.source_ip
= ctx
->mcode_size
;
2198 tr
.destination_ip
= label
;
2199 if (unlikely(!array_add_mayfail(struct trap_record
, &ctx
->trap_records
, &ctx
->trap_records_size
, tr
, NULL
, &ctx
->err
)))
2204 static bool attr_w
add_relocation(struct codegen_context
*ctx
, unsigned length
, int offset
, bool *known
)
2206 struct relocation rel
;
2207 rel
.label_id
= cget_four(ctx
);
2208 rel
.length
= length
;
2209 rel
.position
= ctx
->mcode_size
;
2210 rel
.jmp_instr
= ctx
->code_position
- 8 - offset
- ctx
->code
;
2211 if (unlikely(!array_add_mayfail(struct relocation
, &ctx
->reloc
, &ctx
->reloc_size
, rel
, NULL
, &ctx
->err
)))
2214 *known
= ctx
->label_to_pos
[rel
.label_id
] != (size_t)-1;
2219 #if defined(ARCH_ALPHA)
2220 #include "c2-alpha.inc"
2221 #elif defined(ARCH_ARM32)
2222 #include "c2-arm.inc"
2223 #elif defined(ARCH_ARM64)
2224 #include "c2-arm64.inc"
2225 #elif defined(ARCH_IA64)
2226 #include "c2-ia64.inc"
2227 #elif defined(ARCH_LOONGARCH64)
2228 #include "c2-loong.inc"
2229 #elif defined(ARCH_MIPS)
2230 #include "c2-mips.inc"
2231 #elif defined(ARCH_PARISC)
2232 #include "c2-hppa.inc"
2233 #elif defined(ARCH_POWER)
2234 #include "c2-power.inc"
2235 #elif defined(ARCH_S390)
2236 #include "c2-s390.inc"
2237 #elif defined(ARCH_SPARC)
2238 #include "c2-sparc.inc"
2239 #elif defined(ARCH_RISCV64)
2240 #include "c2-riscv.inc"
2241 #elif defined(ARCH_X86)
2242 #include "c2-x86.inc"
2246 static bool attr_w
gen_mcode(struct codegen_context
*ctx
)
2248 ctx
->code_position
= ctx
->code
;
2250 while (ctx
->code_position
!= ctx
->code
+ ctx
->code_size
) {
2252 ajla_assert_lo(ctx
->code_position
< ctx
->code
+ ctx
->code_size
, (file_line
, "gen_mcode: ran out of code"));
2254 insn
= cget_four(ctx
);
2255 debug("line: %u/%u", insn
>> 24, insn
& 0x00FFFFFFU
);
2257 insn
= cget_four(ctx
);
2258 g(cgen_insn(ctx
, insn
));
2264 #define RELOCS_RETRY -1
2265 #define RELOCS_FAIL 0
2268 static int8_t resolve_relocs(struct codegen_context
*ctx
)
2271 int8_t status
= RELOCS_OK
;
2272 for (i
= 0; i
< ctx
->reloc_size
; i
++) {
2273 struct relocation
*reloc
= &ctx
->reloc
[i
];
2274 if (!resolve_relocation(ctx
, reloc
)) {
2277 uint32_t new_length
;
2278 status
= RELOCS_RETRY
;
2279 if (unlikely(reloc
->length
+ zero
>= JMP_LIMIT
))
2281 new_length
= reloc
->length
+ 1;
2282 jmp_instr
= ctx
->code
+ reloc
->jmp_instr
;
2283 insn
= (uint32_t)jmp_instr
[0] +
2284 ((uint32_t)jmp_instr
[1] << 8) +
2285 ((uint32_t)jmp_instr
[2] << 16) +
2286 ((uint32_t)jmp_instr
[3] << 24);
2287 insn
&= ~INSN_JUMP_SIZE
;
2288 insn
|= (uint32_t)new_length
<< INSN_JUMP_SIZE_SHIFT
;
2289 jmp_instr
[0] = insn
;
2290 jmp_instr
[1] = insn
>> 8;
2291 jmp_instr
[2] = insn
>> 16;
2292 jmp_instr
[3] = insn
>> 24;
2298 static void resolve_traps(struct codegen_context
*ctx
)
2301 for (i
= 0; i
< ctx
->trap_records_size
; i
++) {
2302 struct trap_record
*tr
= &ctx
->trap_records
[i
];
2303 tr
->destination_ip
= ctx
->label_to_pos
[tr
->destination_ip
];
2308 static bool attr_w
codegen_map(struct codegen_context
*ctx
)
2312 array_finish(uint8_t, &ctx
->mcode
, &ctx
->mcode_size
);
2313 ptr
= os_code_map(ctx
->mcode
, ctx
->mcode_size
, &ctx
->err
);
2315 if (unlikely(!ptr
)) {
2318 for (i
= 0; i
< ctx
->n_entries
; i
++) {
2319 char *entry
= cast_ptr(char *, ptr
) + ctx
->entries
[i
].entry_to_pos
;
2320 da(ctx
->codegen
,codegen
)->unoptimized_code
[i
] = entry
;
2321 da(ctx
->codegen
,codegen
)->n_entries
++;
2323 da(ctx
->codegen
,codegen
)->unoptimized_code_base
= ptr
;
2324 da(ctx
->codegen
,codegen
)->unoptimized_code_size
= ctx
->mcode_size
;
2330 void *codegen_fn(frame_s
*fp
, const code_t
*ip
, union internal_arg ia
[])
2332 struct codegen_context ctx_
;
2333 struct codegen_context
*ctx
= &ctx_
;
2336 struct data
*codegen
;
2340 ctx
->fn
= ia
[0].ptr
;
2343 if (getenv("CG") && strcmp(da(ctx
->fn
,function
)->function_name
, getenv("CG")))
2347 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
);
2348 if (unlikely(!ctx
->local_directory
))
2351 if (0) for (i
= 0; i
< da(ctx
->fn
,function
)->local_directory_size
; i
++) {
2352 struct data
*callee
;
2354 ptr
= da(ctx
->fn
,function
)->local_directory
[i
];
2355 pointer_follow(ptr
, false, callee
, PF_SPARK
, NULL
, 0,
2360 ctx
->local_directory
[i
] = callee
;
2363 for (i
= 0; i
< da(ctx
->fn
,function
)->local_directory_size
; i
++) {
2364 struct data
*callee
;
2366 if (ctx
->local_directory
[i
])
2368 ptr
= da(ctx
->fn
,function
)->local_directory
[i
];
2369 pointer_follow(ptr
, false, callee
, PF_WAIT
, fp
, ip
,
2374 ctx
->local_directory
[i
] = callee
;
2375 /*debug("processing call: %s -> %s", da(ctx->fn,function)->function_name, da(callee,function)->function_name);*/
2378 if (da(ctx
->fn
,function
)->module_designator
) {
2379 struct function_descriptor
*sfd
= save_find_function_descriptor(da(ctx
->fn
,function
)->module_designator
, da(ctx
->fn
,function
)->function_designator
);
2380 if (sfd
&& sfd
->unoptimized_code_size
) {
2381 codegen
= data_alloc_flexible(codegen
, unoptimized_code
, sfd
->n_entries
, &ctx
->err
);
2382 if (unlikely(!codegen
))
2384 da(codegen
,codegen
)->unoptimized_code_base
= sfd
->unoptimized_code_base
;
2385 da(codegen
,codegen
)->unoptimized_code_size
= sfd
->unoptimized_code_size
;
2386 da(codegen
,codegen
)->function
= ctx
->fn
;
2387 da(codegen
,codegen
)->is_saved
= true;
2388 da(codegen
,codegen
)->n_entries
= sfd
->n_entries
;
2389 da(codegen
,codegen
)->offsets
= NULL
;
2390 for (i
= 0; i
< sfd
->n_entries
; i
++) {
2391 da(codegen
,codegen
)->unoptimized_code
[i
] = cast_ptr(char *, da(codegen
,codegen
)->unoptimized_code_base
) + sfd
->entries
[i
];
2392 /*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]);*/
2394 #ifdef HAVE_CODEGEN_TRAPS
2395 da(codegen
,codegen
)->trap_records
= sfd
->trap_records
;
2396 da(codegen
,codegen
)->trap_records_size
= sfd
->trap_records_size
;
2397 data_trap_insert(codegen
);
2403 /*debug("trying: %s", da(ctx->fn,function)->function_name);*/
2404 if (unlikely(!array_init_mayfail(uint8_t, &ctx
->code
, &ctx
->code_size
, &ctx
->err
)))
2407 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
);
2408 if (unlikely(!ctx
->code_labels
))
2411 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
);
2412 if (unlikely(!ctx
->code_exits
))
2415 ctx
->flag_cache
= mem_alloc_array_mayfail(mem_calloc_mayfail
, uint8_t *, 0, 0, function_n_variables(ctx
->fn
), sizeof(int8_t), &ctx
->err
);
2416 if (unlikely(!ctx
->flag_cache
))
2419 ctx
->registers
= mem_alloc_array_mayfail(mem_alloc_mayfail
, short *, 0, 0, function_n_variables(ctx
->fn
), sizeof(short), &ctx
->err
);
2420 if (unlikely(!ctx
->registers
))
2423 if (unlikely(!array_init_mayfail(frame_t
, &ctx
->need_spill
, &ctx
->need_spill_l
, &ctx
->err
)))
2426 if (unlikely(!gen_registers(ctx
)))
2429 if (unlikely(!gen_function(ctx
)))
2432 if (unlikely(!gen_entries(ctx
)))
2435 if (unlikely(!gen_epilogues(ctx
)))
2438 if (unlikely(!(ctx
->label_id
+ 1)))
2440 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
))))
2444 for (l
= 0; l
< ctx
->label_id
+ 1; l
++)
2445 ctx
->label_to_pos
[l
] = (size_t)-1;
2447 if (unlikely(!array_init_mayfail(uint8_t, &ctx
->mcode
, &ctx
->mcode_size
, &ctx
->err
)))
2450 if (unlikely(!array_init_mayfail(struct relocation
, &ctx
->reloc
, &ctx
->reloc_size
, &ctx
->err
)))
2453 if (unlikely(!array_init_mayfail(struct trap_record
, &ctx
->trap_records
, &ctx
->trap_records_size
, &ctx
->err
)))
2457 init_arch_context(ctx
);
2460 if (unlikely(!gen_mcode(ctx
)))
2463 rr
= resolve_relocs(ctx
);
2464 if (unlikely(rr
== RELOCS_FAIL
)) {
2465 /*debug("relocation fail: %s", da(ctx->fn,function)->function_name);*/
2468 if (rr
== RELOCS_RETRY
) {
2469 mem_free(ctx
->mcode
);
2471 mem_free(ctx
->reloc
);
2473 mem_free(ctx
->trap_records
);
2474 ctx
->trap_records
= NULL
;
2481 if ((getenv("DUMP") && !strcmp(getenv("DUMP"), da(ctx
->fn
,function
)->function_name
)) || getenv("DUMP_ALL")) {
2487 mutex_lock(&dump_mutex
);
2488 str_init(&hex
, &hexl
);
2489 str_add_string(&hex
, &hexl
, "_");
2490 str_add_unsigned(&hex
, &hexl
, dump_seq
++, 10);
2491 str_add_string(&hex
, &hexl
, "_");
2492 str_add_string(&hex
, &hexl
, da(ctx
->fn
,function
)->function_name
);
2493 str_add_string(&hex
, &hexl
, ":");
2494 for (i
= 0; i
< hexl
; i
++)
2497 for (i
= 0; i
< ctx
->mcode_size
; i
++) {
2498 uint8_t a
= ctx
->mcode
[i
];
2500 str_add_string(&hex
, &hexl
, "\n .byte 0x");
2502 str_add_string(&hex
, &hexl
, ",0x");
2504 str_add_char(&hex
, &hexl
, '0');
2505 str_add_unsigned(&hex
, &hexl
, a
, 16);
2507 str_add_string(&hex
, &hexl
, "\n");
2508 h
= os_open(os_cwd
, "dump.s", O_WRONLY
| O_APPEND
, 0600, NULL
);
2509 os_write_all(h
, hex
, hexl
, NULL
);
2512 mutex_unlock(&dump_mutex
);
2516 ctx
->codegen
= data_alloc_flexible(codegen
, unoptimized_code
, ctx
->n_entries
, &ctx
->err
);
2517 if (unlikely(!ctx
->codegen
))
2519 da(ctx
->codegen
,codegen
)->function
= ctx
->fn
;
2520 da(ctx
->codegen
,codegen
)->is_saved
= false;
2521 da(ctx
->codegen
,codegen
)->n_entries
= 0;
2522 da(ctx
->codegen
,codegen
)->offsets
= NULL
;
2524 if (unlikely(!codegen_map(ctx
)))
2527 codegen
= ctx
->codegen
;
2528 ctx
->codegen
= NULL
;
2530 #ifdef HAVE_CODEGEN_TRAPS
2531 da(codegen
,codegen
)->trap_records
= ctx
->trap_records
;
2532 da(codegen
,codegen
)->trap_records_size
= ctx
->trap_records_size
;
2533 ctx
->trap_records
= NULL
;
2534 data_trap_insert(codegen
);
2539 return function_return(fp
, pointer_data(codegen
));
2542 /*debug("FAILED: %s", da(ctx->fn,function)->function_name);*/
2544 return function_return(fp
, pointer_thunk(thunk_alloc_exception_error(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), NULL
, NULL
, NULL pass_file_line
)));
2547 void codegen_free(struct data
*codegen
)
2549 if (unlikely(da(codegen
,codegen
)->offsets
!= NULL
))
2550 mem_free(da(codegen
,codegen
)->offsets
);
2551 if (likely(da(codegen
,codegen
)->is_saved
))
2553 #ifdef HAVE_CODEGEN_TRAPS
2554 mem_free(da(codegen
,codegen
)->trap_records
);
2556 os_code_unmap(da(codegen
,codegen
)->unoptimized_code_base
, da(codegen
,codegen
)->unoptimized_code_size
);
2559 #if defined(ARCH_IA64)
2560 static uintptr_t ia64_stub
[2];
2562 #if defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2563 static uintptr_t parisc_stub
[2];
2565 #if defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2566 static uintptr_t parisc_stub
[4];
2568 #if defined(ARCH_POWER) && defined(AIX_CALL)
2569 static uintptr_t ppc_stub
[3];
2572 void name(codegen_init
)(void)
2574 struct codegen_context ctx_
;
2575 struct codegen_context
*ctx
= &ctx_
;
2578 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
2579 #if defined(HAVE_SYSCALL) && defined(HAVE_ASM_PRCTL_H) && defined(HAVE_SYS_SYSCALL_H)
2582 EINTR_LOOP(r
, syscall(SYS_arch_prctl
, ARCH_SET_GS
, &cg_upcall_vector
));
2584 upcall_register
= R_GS
;
2586 #elif defined(HAVE_AMD64_SET_GSBASE) && defined(HAVE_X86_SYSARCH_H)
2589 EINTR_LOOP(r
, amd64_set_gsbase(&cg_upcall_vector
));
2591 upcall_register
= R_GS
;
2593 #elif defined(HAVE_SYSARCH) && defined(HAVE_X86_SYSARCH_H) && defined(X86_64_SET_GSBASE)
2596 void *ptr
= &cg_upcall_vector
;
2597 EINTR_LOOP(r
, sysarch(X86_64_SET_GSBASE
, &ptr
));
2599 upcall_register
= R_GS
;
2607 array_init(uint8_t, &ctx
->code
, &ctx
->code_size
);
2609 if (unlikely(!gen_entry(ctx
)))
2612 array_init(uint8_t, &ctx
->mcode
, &ctx
->mcode_size
);
2615 init_arch_context(ctx
);
2618 if (unlikely(!gen_mcode(ctx
)))
2621 array_finish(uint8_t, &ctx
->mcode
, &ctx
->mcode_size
);
2622 ptr
= os_code_map(ctx
->mcode
, ctx
->mcode_size
, NULL
);
2624 codegen_size
= ctx
->mcode_size
;
2626 #if defined(ARCH_IA64)
2627 ia64_stub
[0] = ptr_to_num(ptr
);
2629 codegen_entry
= cast_ptr(codegen_type
, ia64_stub
);
2630 #elif defined(ARCH_PARISC32) && defined(ARCH_PARISC_USE_STUBS)
2631 parisc_stub
[0] = ptr_to_num(ptr
);
2633 codegen_entry
= cast_ptr(codegen_type
, cast_ptr(char *, parisc_stub
) + 2);
2634 #elif defined(ARCH_PARISC64) && defined(ARCH_PARISC_USE_STUBS)
2637 parisc_stub
[2] = ptr_to_num(ptr
);
2639 codegen_entry
= cast_ptr(codegen_type
, parisc_stub
);
2640 #elif defined(ARCH_POWER) && defined(AIX_CALL)
2641 ppc_stub
[0] = ptr_to_num(ptr
);
2644 codegen_entry
= cast_ptr(codegen_type
, ppc_stub
);
2646 codegen_entry
= ptr
;
2651 mutex_init(&dump_mutex
);
2652 if (getenv("DUMP") || getenv("DUMP_ALL")) {
2656 str_init(&hex
, &hexl
);
2657 #if defined(ARCH_RISCV64)
2658 str_add_string(&hex
, &hexl
, " .attribute arch, \"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zba1p0_zbb1p0_zbc1p0_zbs1p0\"\n");
2660 for (i
= 0; i
< codegen_size
; i
++) {
2661 uint8_t a
= cast_ptr(uint8_t *, codegen_ptr
)[i
];
2662 str_add_string(&hex
, &hexl
, " .byte 0x");
2664 str_add_char(&hex
, &hexl
, '0');
2665 str_add_unsigned(&hex
, &hexl
, a
, 16);
2666 str_add_char(&hex
, &hexl
, '\n');
2668 os_write_atomic(".", "dump.s", hex
, hexl
, NULL
);
2676 fatal("couldn't compile global entry");
2679 void name(codegen_done
)(void)
2681 os_code_unmap(codegen_ptr
, codegen_size
);
2683 mutex_done(&dump_mutex
);
2689 void name(codegen_init
)(void)
2693 void name(codegen_done
)(void)