10#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
12#elif defined(IR_TARGET_AARCH64)
15# error "Unknown IR target"
22# define WIN32_LEAN_AND_MEAN
27#if defined(__linux__) || defined(__sun)
31#define DASM_M_GROW(ctx, t, p, sz, need) \
33 size_t _sz = (sz), _need = (need); \
35 if (_sz < 16) _sz = 16; \
36 while (_sz < _need) _sz += _sz; \
37 (p) = (t *)ir_mem_realloc((p), _sz); \
42#define DASM_M_FREE(ctx, p, sz) ir_mem_free(p)
63static const int8_t *_ir_int_reg_params;
68static const int8_t *_ir_fp_reg_params;
76 if (
func->op == IR_FUNC ||
func->op == IR_FUNC_ADDR) {
81 }
else if (ctx->
ir_base[insn->op2].op == IR_PROTO) {
87#ifdef IR_HAVE_FASTCALL
88static const int8_t _ir_int_fc_reg_params[IR_REG_INT_FCARGS];
89static const int8_t *_ir_fp_fc_reg_params;
93 if (
sizeof(
void*) == 4) {
97 if (
func->op == IR_FUNC ||
func->op == IR_FUNC_ADDR) {
104 }
else if (ctx->
ir_base[insn->op2].op == IR_PROTO) {
122 const ir_proto_t *proto = ir_call_proto(ctx, insn);
133 return ctx->
rules[ref];
142static ir_reg ir_get_param_reg(
const ir_ctx *ctx,
ir_ref ref)
152 const int8_t *int_reg_params = _ir_int_reg_params;
153 const int8_t *fp_reg_params = _ir_fp_reg_params;
155#ifdef IR_HAVE_FASTCALL
157 int_reg_params_count = IR_REG_INT_FCARGS;
158 fp_reg_params_count = IR_REG_FP_FCARGS;
159 int_reg_params = _ir_int_fc_reg_params;
160 fp_reg_params = _ir_fp_fc_reg_params;
167 if (insn->op == IR_PARAM) {
170 if (int_param < int_reg_params_count) {
171 return int_reg_params[int_param];
184 if (fp_param < fp_reg_params_count) {
185 return fp_reg_params[fp_param];
201static int ir_get_args_regs(
const ir_ctx *ctx,
const ir_insn *insn, int8_t *regs)
210 const int8_t *int_reg_params = _ir_int_reg_params;
211 const int8_t *fp_reg_params = _ir_fp_reg_params;
213#ifdef IR_HAVE_FASTCALL
215 int_reg_params_count = IR_REG_INT_FCARGS;
216 fp_reg_params_count = IR_REG_FP_FCARGS;
217 int_reg_params = _ir_int_fc_reg_params;
218 fp_reg_params = _ir_fp_fc_reg_params;
222 n = insn->inputs_count;
224 for (
j = 3;
j <=
n;
j++) {
227 if (int_param < int_reg_params_count) {
228 regs[
j] = int_reg_params[int_param];
240 if (fp_param < fp_reg_params_count) {
241 regs[
j] = fp_reg_params[fp_param];
290 EnumProcessModules(GetCurrentProcess(), mods,
sizeof(mods), &cbNeeded);
292 while(i < (cbNeeded /
sizeof(HMODULE))) {
293 addr = GetProcAddress(mods[i],
name);
303#ifdef IR_SNAPSHOT_HANDLER_DCL
307#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
308static void* ir_sym_addr(
ir_ctx *ctx,
const ir_insn *addr_insn)
319static void* ir_sym_val(
ir_ctx *ctx,
const ir_insn *addr_insn)
335 if (addr_insn->op == IR_FUNC) {
336 addr = ir_sym_val(ctx, addr_insn);
338 IR_ASSERT(addr_insn->op == IR_ADDR || addr_insn->op == IR_FUNC_ADDR);
339 addr = (
void*)addr_insn->
val.addr;
346 void *
addr = ir_call_addr(ctx, insn, addr_insn);
348#ifdef IR_SNAPSHOT_HANDLER
349 if (ctx->
ir_base[insn->op1].op == IR_SNAPSHOT) {
370 return ((int8_t*)ctx->
regs)[ref_and_op];
374# pragma GCC diagnostic push
375# pragma GCC diagnostic ignored "-Warray-bounds"
376# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
379#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
382#elif defined(IR_TARGET_AARCH64)
385# define DASM_ADD_VENEER ir_add_veneer
388# error "Unknown IR target"
392# pragma GCC diagnostic pop
396static void ir_emit_osr_entry_loads(
ir_ctx *ctx,
int b,
ir_block *bb);
397static int ir_parallel_copy(
ir_ctx *ctx,
ir_copy *copies,
int count, ir_reg tmp_reg, ir_reg tmp_fp_reg);
417#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
418# include "ir_emit_x86.h"
419#elif defined(IR_TARGET_AARCH64)
420# include "ir_emit_aarch64.h"
422# error "Unknown IR target"
447 for (i = 0; i <
count; i++,
pos++) {
473static int ir_parallel_copy(
ir_ctx *ctx,
ir_copy *copies,
int count, ir_reg tmp_reg, ir_reg tmp_fp_reg)
476 int8_t *pred, *loc, *
types;
479 ir_regset todo, ready, srcs;
483 from = copies[0].
from;
487 ir_emit_mov(ctx,
type, to, from);
489 ir_emit_fp_mov(ctx,
type, to, from);
497 todo = IR_REGSET_EMPTY;
498 srcs = IR_REGSET_EMPTY;
500 for (i = 0; i <
count; i++) {
501 from = copies[i].
from;
504 IR_REGSET_INCL(srcs, from);
509 IR_REGSET_INCL(todo, to);
512 ready = IR_REGSET_DIFFERENCE(todo, srcs);
515 for (i = 0; i <
count; i++) {
516 from = copies[i].
from;
521 ir_emit_mov(ctx,
type, to, from);
523 ir_emit_fp_mov(ctx,
type, to, from);
534 while (ready != IR_REGSET_EMPTY) {
537 to = ir_regset_pop_first(&ready);
542 ir_emit_mov_ext(ctx,
type, to, r);
544 ir_emit_fp_mov(ctx,
type, to, r);
546 IR_REGSET_EXCL(todo, to);
548 if (from == r && IR_REGSET_IN(todo, from)) {
549 IR_REGSET_INCL(ready, from);
552 if (todo == IR_REGSET_EMPTY) {
557 IR_ASSERT(tmp_reg ==
IR_REG_NONE || !IR_REGSET_IN(srcs, tmp_reg) || pred[loc[tmp_reg]] == tmp_reg);
558 IR_ASSERT(tmp_fp_reg ==
IR_REG_NONE || !IR_REGSET_IN(srcs, tmp_fp_reg) || pred[loc[tmp_fp_reg]] == tmp_fp_reg);
561 while (todo != IR_REGSET_EMPTY) {
562 to = ir_regset_pop_first(&todo);
567#ifdef IR_HAVE_SWAP_INT
568 if (pred[from] == to) {
572 ir_emit_swap(ctx,
type, to, from);
573 IR_REGSET_EXCL(todo, from);
581 ir_emit_mov(ctx,
type, tmp_reg, to);
584#ifdef IR_HAVE_SWAP_FP
585 if (pred[from] == to &&
types[to] ==
type) {
586 ir_emit_swap_fp(ctx,
type, to, from);
587 IR_REGSET_EXCL(todo, from);
595 ir_emit_fp_mov(ctx,
type, tmp_fp_reg, to);
596 loc[to] = tmp_fp_reg;
605 ir_emit_mov_ext(ctx,
type, to, r);
607 ir_emit_fp_mov(ctx,
type, to, r);
609 IR_REGSET_EXCL(todo, to);
611 if (from == r && IR_REGSET_IN(todo, from)) {
624 ir_mem mem_from, mem_to;
629 if (-from < ctx->consts_count) {
631 ir_emit_load(ctx,
type, to, from);
638 ir_emit_mov(ctx,
type, to, from);
640 ir_emit_fp_mov(ctx,
type, to, from);
643 mem_from = ir_vreg_spill_slot(ctx, from -
IR_REG_NUM);
644 ir_emit_load_mem(ctx,
type, to, mem_from);
647 mem_to = ir_vreg_spill_slot(ctx, to -
IR_REG_NUM);
649 if (-from < ctx->consts_count) {
651#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
655 ir_emit_store_mem_imm(ctx,
type, mem_to, ctx->
ir_base[from].
val.i32);
661 ir_emit_load(ctx,
type, tmp, from);
662 ir_emit_store_mem(ctx,
type, mem_to, tmp);
667 ir_load_local_addr(ctx, tmp_reg, -from - ctx->
consts_count);
668 ir_emit_store_mem(ctx,
type, mem_to, tmp_reg);
671 ir_emit_store_mem(ctx,
type, mem_to, from);
673 mem_from = ir_vreg_spill_slot(ctx, from -
IR_REG_NUM);
674 IR_ASSERT(IR_MEM_VAL(mem_to) != IR_MEM_VAL(mem_from));
677 ir_emit_load_mem(ctx,
type, tmp, mem_from);
678 ir_emit_store_mem(ctx,
type, mem_to, tmp);
686 ir_mem tmp_spill_slot;
689 IR_MEM_VAL(tmp_spill_slot) = 0;
698#ifdef IR_HAVE_SWAP_INT
704 ir_emit_swap(ctx,
type, to, from);
716 ir_emit_mov(ctx,
type, tmp_reg, to);
718 ir_emit_load_mem_int(ctx,
type, tmp_reg, ir_vreg_spill_slot(ctx, to -
IR_REG_NUM));
721#ifdef IR_HAVE_SWAP_FP
724 ir_emit_swap_fp(ctx,
type, to, from);
725 IR_REGSET_EXCL(todo, from);
726 IR_REGSET_EXCL(todo, to);
734 loc[to] = tmp_fp_reg;
736 ir_emit_fp_mov(ctx,
type, tmp_fp_reg, to);
738 ir_emit_load_mem_fp(ctx,
type, tmp_fp_reg, ir_vreg_spill_slot(ctx, to -
IR_REG_NUM));
754 if (!IR_MEM_VAL(tmp_spill_slot)) {
757 ir_emit_store_mem(ctx,
type, tmp_spill_slot, tmp);
759 ir_emit_dessa_move(ctx,
type, to, r, tmp_reg, tmp_fp_reg);
772 if (IR_MEM_VAL(tmp_spill_slot)) {
783 int32_t *pred, *loc, to, from;
791 from = copies[0].
from;
794 ir_emit_dessa_move(ctx,
type, to, from, tmp_reg, tmp_fp_reg);
805 for (i = 0; i <
count; i++) {
806 from = copies[i].
from;
838 ir_emit_dessa_move(ctx,
type, to, from, tmp_reg, tmp_fp_reg);
840 int32_t r = loc[from];
841 ir_emit_dessa_move(ctx,
type, to, r, tmp_reg, tmp_fp_reg);
843 if (from == r &&
ir_bitset_in(todo, from) && from != tmp_reg && from != tmp_fp_reg) {
880 ir_emit_dessa_move(ctx,
type, to, from, tmp_reg, tmp_fp_reg);
882 int32_t r = loc[from];
883 ir_emit_dessa_move(ctx,
type, to, r, tmp_reg, tmp_fp_reg);
903 uint32_t succ, k,
n = 0;
908 ir_reg tmp_reg = ctx->
regs[bb->
end][0];
909 ir_reg tmp_fp_reg = ctx->
regs[bb->
end][1];
924 if (insn->op == IR_PHI) {
927 ir_reg dst = ctx->
regs[ref][0];
933 }
else if (
ir_rule(ctx, input) == IR_STATIC_ALLOCA) {
945 && IR_MEM_VAL(ir_vreg_spill_slot(ctx, from -
IR_REG_NUM)) ==
946 IR_MEM_VAL(ir_vreg_spill_slot(ctx, to -
IR_REG_NUM))) {
951 copies[
n].
type = insn->type;
952 copies[
n].
from = from;
960 ir_dessa_parallel_copy(ctx, copies,
n, tmp_reg, tmp_fp_reg);
970 uint32_t entries_count = 0;
988 IR_ASSERT(entries_count < ctx->entries_count);
991 insn->op3 = entries_count;
992 ctx->
entries[entries_count] = b;
999 if (insn->op == IR_END || insn->op == IR_LOOP_END) {
1000 ctx->
rules[ref] = insn->op;
1001 ref = prev_ref[ref];
1018 while (ref !=
start) {
1019 uint32_t rule = ctx->
rules[ref];
1022 ctx->
rules[ref] = rule = ir_match_insn(ctx, ref);
1024 ir_match_insn2(ctx, ref, rule);
1025 ref = prev_ref[ref];
1031 if (!entries_count) {
1047 return IR_SPILL_POS_TO_OFFSET(
offset);
count(Countable|array $value, int $mode=COUNT_NORMAL)
ir_ref ir_binding_find(const ir_ctx *ctx, ir_ref ref)
const char * ir_get_str(const ir_ctx *ctx, ir_ref idx)
const uint8_t ir_type_size[IR_LAST_TYPE]
#define IR_REG_SPILLED(r)
ir_ref ir_strtab_find(const ir_strtab *strtab, const char *str, uint32_t len)
#define IR_IS_TYPE_INT(t)
struct _ir_live_interval ir_live_interval
IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
struct _ir_proto_t ir_proto_t
#define IR_IS_CONST_REF(ref)
struct _ir_use_list ir_use_list
#define IR_MERGE_EMPTY_ENTRIES
struct _ir_block ir_block
#define IR_REG_STACK_POINTER
IR_ALWAYS_INLINE uint32_t ir_rule(const ir_ctx *ctx, ir_ref ref)
int ir_match(ir_ctx *ctx)
struct _ir_common_backend_data ir_common_backend_data
bool ir_is_fastcall(const ir_ctx *ctx, const ir_insn *insn)
bool ir_is_vararg(const ir_ctx *ctx, ir_insn *insn)
int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref)
IR_ALWAYS_INLINE bool ir_in_same_block(ir_ctx *ctx, ir_ref ref)
void * ir_resolve_sym_name(const char *name)
struct _ir_dessa_copy ir_dessa_copy
IR_ALWAYS_INLINE void ir_dessa_resolve_cycle(ir_ctx *ctx, int32_t *pred, int32_t *loc, int8_t *types, ir_bitset todo, int32_t to, ir_reg tmp_reg, ir_reg tmp_fp_reg)
void ir_build_prev_refs(ir_ctx *ctx)
#define IR_SNAPSHOT_HANDLER(ctx, ref, insn, addr)
#define IR_SNAPSHOT_HANDLER_DCL()
ir_bitset_base_t * ir_bitset
IR_ALWAYS_INLINE bool ir_bitset_in(const ir_bitset set, uint32_t n)
IR_ALWAYS_INLINE void ir_bitset_copy(ir_bitset set1, const ir_bitset set2, uint32_t len)
IR_ALWAYS_INLINE uint32_t ir_phi_input_number(const ir_ctx *ctx, const ir_block *bb, uint32_t from)
IR_ALWAYS_INLINE void ir_bitset_intersection(ir_bitset set1, const ir_bitset set2, uint32_t len)
IR_ALWAYS_INLINE ir_bitset ir_bitset_malloc(uint32_t n)
IR_ALWAYS_INLINE bool ir_bitset_empty(const ir_bitset set, uint32_t len)
IR_ALWAYS_INLINE void ir_bitset_incl(ir_bitset set, uint32_t n)
#define IR_IS_SYM_CONST(op)
IR_ALWAYS_INLINE int8_t ir_get_alocated_reg(const ir_ctx *ctx, ir_ref ref, int op_num)
IR_ALWAYS_INLINE uint32_t ir_bitset_len(uint32_t n)
IR_ALWAYS_INLINE int ir_bitset_first(const ir_bitset set, uint32_t len)
IR_ALWAYS_INLINE ir_ref ir_list_at(const ir_list *l, uint32_t i)
#define IR_LIVE_INTERVAL_SPILL_SPECIAL
#define IR_BB_PREV_EMPTY_ENTRY
struct _ir_reg_alloc_data ir_reg_alloc_data
IR_ALWAYS_INLINE void ir_bitset_difference(ir_bitset set1, const ir_bitset set2, uint32_t len)
#define IR_BB_UNREACHABLE
IR_ALWAYS_INLINE int ir_bitset_pop_first(ir_bitset set, uint32_t len)
IR_ALWAYS_INLINE void ir_bitset_clear(ir_bitset set, uint32_t len)
#define IR_LIVE_INTERVAL_SPILLED
IR_ALWAYS_INLINE void ir_bitset_excl(ir_bitset set, uint32_t n)
unsigned const char * pos
unsigned char key[REFLECTION_KEY_LEN]
uint32_t successors_count
uint32_t predecessors_count
ir_reg_alloc_data ra_data
uint32_t dessa_from_block
ir_live_interval ** live_intervals
uint32_t cfg_blocks_count
void *(* resolve_sym_name)(ir_loader *loader, const char *name, bool add_thunk)
#define EXPECTED(condition)
#define UNEXPECTED(condition)