issue #169 MIR update

pull/200/head
Dibyendu Majumdar 4 years ago
parent a3bf9dc10e
commit a82d42b847

@ -36,6 +36,7 @@ static void target_add_res_proto (c2m_ctx_t c2m_ctx, struct type *ret_type,
static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
target_arg_info_t *arg_info, size_t call_arg_area_offset) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
int size;
@ -52,6 +53,7 @@ static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res,
MIR_insn_t call, size_t call_ops_start) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
int size;
if ((size = reg_aggregate_size (c2m_ctx, ret_type)) < 0)
@ -63,6 +65,7 @@ static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_t
}
static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
int i, size;
if ((size = reg_aggregate_size (c2m_ctx, ret_type)) < 0) {

File diff suppressed because it is too large Load Diff

@ -10,7 +10,8 @@ struct c2mir_macro_command {
struct c2mir_options {
FILE *message_file;
int debug_p, verbose_p, no_prepro_p, prepro_only_p, syntax_only_p, pedantic_p, asm_p, object_p;
int debug_p, verbose_p, ignore_warnings_p, no_prepro_p, prepro_only_p;
int syntax_only_p, pedantic_p, asm_p, object_p;
size_t module_num;
FILE *prepro_output_file; /* non-null for prepro_only_p */
const char *output_file_name;

@ -14,6 +14,7 @@ static MIR_type_t fp_homogeneous_type (c2m_ctx_t c2m_ctx, struct type *param_typ
#else
static MIR_type_t fp_homogeneous_type_1 (c2m_ctx_t c2m_ctx, MIR_type_t curr_type, struct type *type,
int *num) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
int n;
MIR_type_t t;
@ -33,7 +34,7 @@ static MIR_type_t fp_homogeneous_type_1 (c2m_ctx_t c2m_ctx, MIR_type_t curr_type
case TM_UNION:
t = curr_type;
*num = 0;
for (node_t el = NL_HEAD (NL_EL (type->u.tag_type->ops, 1)->ops); el != NULL;
for (node_t el = NL_HEAD (NL_EL (type->u.tag_type->u.ops, 1)->u.ops); el != NULL;
el = NL_NEXT (el))
if (el->code == N_MEMBER) {
decl_t decl = el->attr;
@ -108,6 +109,7 @@ static void target_add_res_proto (c2m_ctx_t c2m_ctx, struct type *ret_type,
static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
target_arg_info_t *arg_info, size_t call_arg_area_offset) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
op_t temp;
@ -149,6 +151,7 @@ static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res,
MIR_insn_t call, size_t call_ops_start) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_insn_t insn;
@ -177,6 +180,7 @@ static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_t
}
static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_insn_t insn;
@ -241,6 +245,7 @@ static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct ty
static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
target_arg_info_t *arg_info, op_t arg) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_var_t var;
MIR_type_t type;
@ -274,6 +279,7 @@ static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
static int target_gen_gather_arg (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
decl_t param_decl, target_arg_info_t *arg_info) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_var_t var;
MIR_type_t type;

@ -55,6 +55,7 @@ static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct ty
static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
target_arg_info_t *arg_info, op_t arg) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
op_t temp;
if (arg_type->mode != TM_STRUCT && arg_type->mode != TM_UNION) {
@ -75,6 +76,7 @@ static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
static int target_gen_gather_arg (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
decl_t param_decl, target_arg_info_t *arg_info) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_op_t param_op;

@ -45,7 +45,7 @@ static int classify_arg (c2m_ctx_t c2m_ctx, struct type *type, MIR_type_t types[
if (n_qwords > MAX_QWORDS) return 0; /* too big aggregate */
#ifndef _WIN64
for (i = 0; i < n_qwords; i++) types[i] = NO_CLASS;
for (i = 0; i < n_qwords; i++) types[i] = (MIR_type_t) NO_CLASS;
switch (type->mode) {
case TM_ARR: { /* Arrays are handled as small records. */
@ -58,7 +58,7 @@ static int classify_arg (c2m_ctx_t c2m_ctx, struct type *type, MIR_type_t types[
}
case TM_STRUCT:
case TM_UNION:
for (node_t el = NL_HEAD (NL_EL (type->u.tag_type->ops, 1)->ops); el != NULL;
for (node_t el = NL_HEAD (NL_EL (type->u.tag_type->u.ops, 1)->u.ops); el != NULL;
el = NL_NEXT (el))
if (el->code == N_MEMBER) {
decl_t decl = el->attr;
@ -98,7 +98,7 @@ static int classify_arg (c2m_ctx_t c2m_ctx, struct type *type, MIR_type_t types[
case MIR_T_D: types[0] = MIR_T_D; return 1;
case MIR_T_LD:
types[0] = MIR_T_LD;
types[1] = X87UP_CLASS;
types[1] = (MIR_type_t) X87UP_CLASS;
return 2;
default: types[0] = MIR_T_I64; return 1;
}
@ -204,6 +204,7 @@ static void target_add_res_proto (c2m_ctx_t c2m_ctx, struct type *ret_type,
static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
target_arg_info_t *arg_info, size_t call_arg_area_offset) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_type_t qword_types[MAX_QWORDS];
@ -239,6 +240,7 @@ static int target_add_call_res_op (c2m_ctx_t c2m_ctx, struct type *ret_type,
static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res,
MIR_insn_t call, size_t call_ops_start) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_insn_t insn;
@ -263,6 +265,7 @@ static op_t target_gen_post_call_res_code (c2m_ctx_t c2m_ctx, struct type *ret_t
}
static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t res) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_type_t qword_types[MAX_QWORDS];
@ -356,6 +359,7 @@ static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct ty
static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
target_arg_info_t *arg_info, op_t arg) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_type_t qword_types[MAX_QWORDS];
@ -394,6 +398,7 @@ static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
static int target_gen_gather_arg (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
decl_t param_decl, target_arg_info_t *arg_info) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
reg_var_t reg_var;

@ -97,7 +97,7 @@ void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
static int setup_imm64_insns (MIR_context_t ctx, uint32_t *to, int reg, uint64_t imm64) {
static int setup_imm64_insns (uint32_t *to, int reg, uint64_t imm64) {
/* xd=imm64 */
static const uint32_t imm64_pat[] = {
0xd2800000, /* 0: mov xd, xxxx(0-15) */
@ -115,19 +115,19 @@ static int setup_imm64_insns (MIR_context_t ctx, uint32_t *to, int reg, uint64_t
return sizeof (imm64_pat) / sizeof (uint32_t);
}
static uint8_t *push_insns (MIR_context_t ctx, const uint32_t *pat, size_t pat_len) {
static uint8_t *push_insns (VARR (uint8_t) * insn_varr, const uint32_t *pat, size_t pat_len) {
uint8_t *p = (uint8_t *) pat;
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, insn_varr, p[i]);
return VARR_ADDR (uint8_t, insn_varr) + VARR_LENGTH (uint8_t, insn_varr) - pat_len;
}
static size_t gen_mov_addr (MIR_context_t ctx, int reg, void *addr) {
static size_t gen_mov_addr (VARR (uint8_t) * insn_varr, int reg, void *addr) {
uint32_t insns[4];
int insns_num = setup_imm64_insns (ctx, insns, reg, (uint64_t) addr);
int insns_num = setup_imm64_insns (insns, reg, (uint64_t) addr);
mir_assert (insns_num == 4 && sizeof (insns) == insns_num * sizeof (uint32_t));
push_insns (ctx, insns, insns_num * sizeof (uint32_t));
push_insns (insn_varr, insns, insns_num * sizeof (uint32_t));
return insns_num * sizeof (uint32_t);
}
@ -135,7 +135,8 @@ static size_t gen_mov_addr (MIR_context_t ctx, int reg, void *addr) {
#define MAX_BR_OFFSET (1 << (BR_OFFSET_BITS - 1)) /* 1 for sign */
#define BR_OFFSET_MASK (~(-1 << BR_OFFSET_BITS))
static void gen_call_addr (MIR_context_t ctx, void *base_addr, int temp_reg, void *call_addr) {
static void gen_call_addr (VARR (uint8_t) * insn_varr, void *base_addr, int temp_reg,
void *call_addr) {
static const uint32_t call_pat1 = 0x94000000; /* bl x */
static const uint32_t call_pat2 = 0xd63f0000; /* blr x */
uint32_t insn;
@ -145,10 +146,10 @@ static void gen_call_addr (MIR_context_t ctx, void *base_addr, int temp_reg, voi
if (base_addr != NULL && -(int64_t) MAX_BR_OFFSET <= offset && offset < (int64_t) MAX_BR_OFFSET) {
insn = call_pat1 | ((uint32_t) offset & BR_OFFSET_MASK);
} else {
gen_mov_addr (ctx, temp_reg, call_addr);
gen_mov_addr (insn_varr, temp_reg, call_addr);
insn = call_pat2 | (temp_reg << 5);
}
push_insns (ctx, &insn, sizeof (insn));
push_insns (insn_varr, &insn, sizeof (insn));
}
#define NOP 0xd503201f
@ -170,7 +171,7 @@ void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
code[0] = branch_pat2 | ((uint32_t) offset & BR_OFFSET_MASK);
_MIR_change_code (ctx, thunk, (uint8_t *) &code[0], sizeof (code[0]));
} else {
int n = setup_imm64_insns (ctx, code, 9, (uint64_t) to);
int n = setup_imm64_insns (code, 9, (uint64_t) to);
mir_assert (n == 4);
code[4] = branch_pat1;
@ -178,8 +179,8 @@ void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
}
}
static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offset, uint32_t qwords,
uint32_t addr_reg) {
static void gen_blk_mov (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t addr_offset,
uint32_t qwords, uint32_t addr_reg) {
static const uint32_t blk_mov_pat[] = {
/* 0:*/ 0xf940026c, /* ldr x12, [x19,<addr_offset>]*/
/* 4:*/ 0x910003e0, /* add <addr_reg>, sp, <offset>*/
@ -194,9 +195,9 @@ static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offse
};
if (qwords == 0) {
uint32_t pat = 0x910003e0 | addr_reg | (offset << 10); /* add <add_reg>, sp, <offset>*/
push_insns (ctx, &pat, sizeof (pat));
push_insns (insn_varr, &pat, sizeof (pat));
} else {
uint32_t *addr = (uint32_t *) push_insns (ctx, blk_mov_pat, sizeof (blk_mov_pat));
uint32_t *addr = (uint32_t *) push_insns (insn_varr, blk_mov_pat, sizeof (blk_mov_pat));
mir_assert (offset < (1 << 12) && addr_offset % 8 == 0 && (addr_offset >> 3) < (1 << 12));
mir_assert (addr_reg < 32 && qwords < (1 << 16));
addr[0] |= (addr_offset >> 3) << 10;
@ -272,7 +273,10 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
uint32_t sp = 31, addr_reg, qwords;
uint32_t *addr;
const uint32_t temp_reg = 10; /* x10 */
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
mir_assert (sizeof (long double) == 16);
for (size_t i = 0; i < nargs; i++) { /* caclulate offset for blk params */
type = arg_descs[i].type;
@ -286,12 +290,11 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
if (n_vregs++ >= 8) blk_offset += type == MIR_T_LD ? 16 : 8;
} else {
(*error_func) (MIR_call_op_error, "wrong type of arg value");
MIR_get_error_func (ctx) (MIR_call_op_error, "wrong type of arg value");
}
}
blk_offset = (blk_offset + 15) / 16 * 16;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prolog, sizeof (prolog));
push_insns (code, prolog, sizeof (prolog));
n_xregs = n_vregs = 0;
for (size_t i = 0; i < nargs; i++) { /* args */
type = arg_descs[i].type;
@ -302,29 +305,29 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
if (qwords <= 2) {
addr_reg = 13;
pat = ld_pat | offset_imm | addr_reg;
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
if (n_xregs + qwords <= 8) {
for (int n = 0; n < qwords; n++) {
pat = gen_ld_pat | (((n * 8) >> scale) << 10) | (n_xregs + n) | (addr_reg << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
}
} else {
for (int n = 0; n < qwords; n++) {
pat = gen_ld_pat | (((n * 8) >> scale) << 10) | temp_reg | (addr_reg << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
pat = st_pat | ((sp_offset >> scale) << 10) | temp_reg | (sp << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
sp_offset += 8;
}
}
n_xregs += qwords;
} else {
addr_reg = n_xregs < 8 ? n_xregs : 13;
gen_blk_mov (ctx, blk_offset, (i + nres) * sizeof (long double), qwords, addr_reg);
gen_blk_mov (code, blk_offset, (i + nres) * sizeof (long double), qwords, addr_reg);
blk_offset += qwords * 8;
if (n_xregs++ >= 8) {
pat = st_pat | ((sp_offset >> scale) << 10) | addr_reg | (sp << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
sp_offset += 8;
}
}
@ -335,11 +338,11 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
pat = ld_pat | offset_imm | n_xregs++;
} else {
pat = ld_pat | offset_imm | temp_reg;
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
pat = st_pat | ((sp_offset >> scale) << 10) | temp_reg | (sp << 5);
sp_offset += 8;
}
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
pat = type == MIR_T_F ? lds_pat : type == MIR_T_D ? ldd_pat : ldld_pat;
if (n_vregs < 8) {
@ -347,22 +350,23 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
} else {
if (type == MIR_T_LD) sp_offset = (sp_offset + 15) % 16;
pat |= offset_imm | temp_reg;
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
pat = type == MIR_T_F ? sts_pat : type == MIR_T_D ? std_pat : stld_pat;
pat |= ((sp_offset >> scale) << 10) | temp_reg | (sp << 5);
sp_offset += type == MIR_T_LD ? 16 : 8;
}
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
} else {
MIR_get_error_func (ctx) (MIR_call_op_error, "wrong type of arg value");
}
}
sp_offset = (sp_offset + 15) / 16 * 16;
blk_offset = (blk_offset + 15) / 16 * 16;
if (blk_offset != 0) sp_offset = blk_offset;
mir_assert (sp_offset < (1 << 12));
((uint32_t *) VARR_ADDR (uint8_t, machine_insns))[1] |= sp_offset << 10; /* sub sp,sp,<offset> */
push_insns (ctx, call_end, sizeof (call_end));
((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-1]
|= sp_offset << 10;
((uint32_t *) VARR_ADDR (uint8_t, code))[1] |= sp_offset << 10; /* sub sp,sp,<offset> */
push_insns (code, call_end, sizeof (call_end));
((uint32_t *) (VARR_ADDR (uint8_t, code) + VARR_LENGTH (uint8_t, code)))[-1] |= sp_offset << 10;
n_xregs = n_vregs = 0;
for (size_t i = 0; i < nres; i++) { /* results */
offset_imm = i * sizeof (long double) << 10;
@ -370,20 +374,22 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
&& n_xregs < 8) {
offset_imm >>= 3;
pat = st_pat | offset_imm | n_xregs++ | (19 << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
} else if ((res_types[i] == MIR_T_F || res_types[i] == MIR_T_D || res_types[i] == MIR_T_LD)
&& n_vregs < 8) {
offset_imm >>= res_types[i] == MIR_T_F ? 2 : res_types[i] == MIR_T_D ? 3 : 4;
pat = res_types[i] == MIR_T_F ? sts_pat : res_types[i] == MIR_T_D ? std_pat : stld_pat;
pat |= offset_imm | n_vregs++ | (19 << 5);
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
} else {
(*error_func) (MIR_ret_error, "aarch64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"aarch64 can not handle this combination of return values");
}
}
push_insns (ctx, epilog, sizeof (epilog));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
push_insns (code, epilog, sizeof (epilog));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
@ -423,22 +429,23 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
uint32_t nres = func->nres;
int x8_res_p = func->nargs != 0 && VARR_GET (MIR_var_t, func->vars, 0).type == MIR_T_RBLK;
MIR_type_t *results = func->res_types;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, &save_x19_pat, sizeof (save_x19_pat));
push_insns (ctx, save_insns, sizeof (save_insns));
VARR_CREATE (uint8_t, code, 128);
push_insns (code, &save_x19_pat, sizeof (save_x19_pat));
push_insns (code, save_insns, sizeof (save_insns));
if (x8_res_p)
push_insns (ctx, &set_x8_gr_offs, sizeof (set_x8_gr_offs));
push_insns (code, &set_x8_gr_offs, sizeof (set_x8_gr_offs));
else
push_insns (ctx, &set_gr_offs, sizeof (set_gr_offs));
push_insns (ctx, prepare_pat, sizeof (prepare_pat));
push_insns (code, &set_gr_offs, sizeof (set_gr_offs));
push_insns (code, prepare_pat, sizeof (prepare_pat));
imm = (nres + 1) * 16;
mir_assert (imm < (1 << 16));
((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-5]
|= imm << 5;
gen_mov_addr (ctx, 0, ctx); /* mov x0, ctx */
gen_mov_addr (ctx, 1, func_item); /* mov x1, func_item */
gen_call_addr (ctx, NULL, 9, handler);
((uint32_t *) (VARR_ADDR (uint8_t, code) + VARR_LENGTH (uint8_t, code)))[-5] |= imm << 5;
gen_mov_addr (code, 0, ctx); /* mov x0, ctx */
gen_mov_addr (code, 1, func_item); /* mov x1, func_item */
gen_call_addr (code, NULL, 9, handler);
/* move results: */
n_xregs = n_vregs = offset = 0;
mir_assert (sizeof (long double) == 16);
@ -451,21 +458,22 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
pat = ld_pat | n_xregs;
n_xregs++;
} else {
(*error_func) (MIR_ret_error, "aarch64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"aarch64 can not handle this combination of return values");
}
offset_imm = offset >> (results[i] == MIR_T_F ? 2 : results[i] == MIR_T_LD ? 4 : 3);
mir_assert (offset_imm < (1 << 12));
pat |= offset_imm << 10;
push_insns (ctx, &pat, sizeof (pat));
push_insns (code, &pat, sizeof (pat));
offset += 16;
}
push_insns (ctx, shim_end, sizeof (shim_end));
push_insns (code, shim_end, sizeof (shim_end));
imm = 240 + (nres + 1) * 16;
mir_assert (imm < (1 << 16));
((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-4]
|= imm << 5;
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
((uint32_t *) (VARR_ADDR (uint8_t, code) + VARR_LENGTH (uint8_t, code)))[-4] |= imm << 5;
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Save regs x8, x0-x7, q0-q7; x9 = call hook_address (ctx, called_func); restore regs; br x9 */
@ -474,26 +482,36 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
static const uint32_t move_insn = 0xaa0003e9; /* mov x9, x0 */
static const uint32_t save_fplr = 0xa9bf7bfd; /* stp R29, R30, [SP, #-16]! */
static const uint32_t restore_fplr = 0xa8c17bfd; /* ldp R29, R30, SP, #16 */
uint8_t *base_addr, *curr_addr, *code;
size_t len = sizeof (save_insns) + sizeof (restore_insns);
for (;;) {
uint8_t *base_addr, *curr_addr, *res_code = NULL;
size_t len = sizeof (save_insns) + sizeof (restore_insns); /* initial code length */
VARR (uint8_t) * code;
#if MIR_PARALLEL_GEN
pthread_mutex_lock (&code_mutex);
#endif
VARR_CREATE (uint8_t, code, 128);
for (;;) { /* dealing with moving code to another page */
curr_addr = base_addr = _MIR_get_new_code_addr (ctx, len);
if (curr_addr == NULL) return NULL;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, &save_fplr, sizeof (save_fplr));
if (curr_addr == NULL) break;
VARR_TRUNC (uint8_t, code, 0);
push_insns (code, &save_fplr, sizeof (save_fplr));
curr_addr += 4;
push_insns (ctx, save_insns, sizeof (save_insns));
push_insns (code, save_insns, sizeof (save_insns));
curr_addr += sizeof (save_insns);
curr_addr += gen_mov_addr (ctx, 0, ctx); /*mov x0,ctx */
curr_addr += gen_mov_addr (ctx, 1, called_func); /*mov x1,called_func */
gen_call_addr (ctx, curr_addr, 10, hook_address); /*call <hook_address>, use x10 as temp */
push_insns (ctx, &move_insn, sizeof (move_insn));
push_insns (ctx, restore_insns, sizeof (restore_insns));
push_insns (ctx, &restore_fplr, sizeof (restore_fplr));
push_insns (ctx, &jmp_insn, sizeof (jmp_insn));
len = VARR_LENGTH (uint8_t, machine_insns);
code = _MIR_publish_code_by_addr (ctx, base_addr, VARR_ADDR (uint8_t, machine_insns), len);
if (code != NULL) return code;
curr_addr += gen_mov_addr (code, 0, ctx); /*mov x0,ctx */
curr_addr += gen_mov_addr (code, 1, called_func); /*mov x1,called_func */
gen_call_addr (code, curr_addr, 10, hook_address); /*call <hook_address>, use x10 as temp */
push_insns (code, &move_insn, sizeof (move_insn));
push_insns (code, restore_insns, sizeof (restore_insns));
push_insns (code, &restore_fplr, sizeof (restore_fplr));
push_insns (code, &jmp_insn, sizeof (jmp_insn));
len = VARR_LENGTH (uint8_t, code);
res_code = _MIR_publish_code_by_addr (ctx, base_addr, VARR_ADDR (uint8_t, code), len);
if (res_code != NULL) break;
}
VARR_DESTROY (uint8_t, code);
#if MIR_PARALLEL_GEN
pthread_mutex_unlock (&code_mutex);
#endif
return res_code;
}

@ -1649,9 +1649,10 @@ static const struct pattern patterns[] = {
{MIR_BSTART, "r", "91000000:fffffc00 rd0 hn1f"}, /* Rd = sp */
{MIR_BEND, "r", "91000000:fffffc00 hd1f rn0"}, /* sp = Rn */
/* adr r9,PC-relative TableAddress; ldr r9,(r9,r,8);br r9; TableContent */
/* adr r10,PC-relative TableAddress; ldr r10,(r10,r,8);br r10; TableContent
We use r10 as r9 can be used if switch operand is memory. */
{MIR_SWITCH, "r $",
"10000000:ff000000 hd9 T; f8607800:ffe0fc00 hd9 hn9 rm0; d61f0000:fffffc00 hn9;"},
"10000000:ff000000 hda T; f8607800:ffe0fc00 hda hna rm0; d61f0000:fffffc00 hna;"},
};

@ -978,6 +978,7 @@ struct pattern {
X - match everything
$ - finish successfully matching
r - register (we don't care about bp and sp because they are fixed and used correctly)
t - ax, cx, dx, or bx register
h[0-31] - hard register with given number
z - operand is zero
i[0-3] - immediate of size 8,16,32,64-bits
@ -1068,12 +1069,12 @@ struct pattern {
/* cmp ...; setx r0; movzbl r0,r0: */
#define CMP0(ICODE, SUFF, PREF, SETX) \
{ICODE##SUFF, "r r r", #PREF " 3B r1 R2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,r2;...*/ \
{ICODE##SUFF, "r r m3", #PREF " 3B r1 m2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,m2;...*/ \
{ICODE##SUFF, "r r i0", #PREF " 83 /7 R1 i2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,i2;...*/ \
{ICODE##SUFF, "r r i2", #PREF " 81 /7 R1 I2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,i2;...*/ \
{ICODE##SUFF, "r m3 i0", #PREF " 83 /7 m1 i2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp m1,i2;...*/ \
{ICODE##SUFF, "r m3 i2", #PREF " 81 /7 m1 I2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp m1,i2;...*/
{ICODE##SUFF, "t r r", #PREF " 3B r1 R2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,r2;...*/ \
{ICODE##SUFF, "t r m3", #PREF " 3B r1 m2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,m2;...*/ \
{ICODE##SUFF, "t r i0", #PREF " 83 /7 R1 i2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,i2;...*/ \
{ICODE##SUFF, "t r i2", #PREF " 81 /7 R1 I2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp r1,i2;...*/ \
{ICODE##SUFF, "t m3 i0", #PREF " 83 /7 m1 i2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp m1,i2;...*/ \
{ICODE##SUFF, "t m3 i2", #PREF " 81 /7 m1 I2;" SETX " R0;X 0F B6 r0 R0"}, /* cmp m1,i2;...*/
#define CMP(ICODE, SET_OPCODE) \
CMP0 (ICODE, , X, SET_OPCODE) \
@ -1444,6 +1445,11 @@ static int pattern_match_p (gen_ctx_t gen_ctx, const struct pattern *pat, MIR_in
case 'r':
if (op.mode != MIR_OP_HARD_REG) return FALSE;
break;
case 't':
if (op.mode != MIR_OP_HARD_REG
|| !(AX_HARD_REG <= op.u.hard_reg && op.u.hard_reg <= BX_HARD_REG))
return FALSE;
break;
case 'h':
if (op.mode != MIR_OP_HARD_REG) return FALSE;
ch = *++p;
@ -2107,7 +2113,7 @@ static uint8_t *target_translate (gen_ctx_t gen_ctx, size_t *len) {
} else {
replacement = find_insn_pattern_replacement (gen_ctx, insn);
if (replacement == NULL) {
fprintf (stderr, "fatal failure in matching insn:");
fprintf (stderr, "%d: fatal failure in matching insn:", gen_ctx->gen_num);
MIR_output_insn (ctx, stderr, insn, curr_func_item->u.func, TRUE);
exit (1);
} else {

@ -125,10 +125,27 @@ struct fg_ctx;
typedef struct loop_node *loop_node_t;
DEF_VARR (loop_node_t);
typedef struct dead_var *dead_var_t;
DEF_DLIST_LINK (dead_var_t);
struct dead_var {
MIR_reg_t var;
DLIST_LINK (dead_var_t) dead_var_link;
};
DEF_DLIST (dead_var_t, dead_var_link);
struct all_gen_ctx;
typedef struct bb_insn *bb_insn_t;
DEF_VARR (bb_insn_t);
struct gen_ctx {
struct all_gen_ctx *all_gen_ctx;
int gen_num; /* always 1 for non-parallel generation */
#if MIR_PARALLEL_GEN
pthread_t gen_thread;
int busy_p;
#endif
MIR_context_t ctx;
unsigned optimize_level; /* 0:fast gen; 1:RA+combiner; 2: +GVN/CCP (default); >=3: everything */
MIR_item_t curr_func_item;
@ -139,6 +156,7 @@ struct gen_ctx {
bitmap_t call_used_hard_regs[MIR_T_BOUND], func_used_hard_regs;
func_cfg_t curr_cfg;
uint32_t curr_bb_index, curr_loop_node_index;
DLIST (dead_var_t) free_dead_vars;
struct target_ctx *target_ctx;
struct data_flow_ctx *data_flow_ctx;
struct ssa_ctx *ssa_ctx;
@ -155,8 +173,6 @@ struct gen_ctx {
size_t func_stack_slots_num;
};
static inline gen_ctx_t *gen_ctx_loc (MIR_context_t ctx) { return (gen_ctx_t *) ctx; }
#define optimize_level gen_ctx->optimize_level
#define curr_func_item gen_ctx->curr_func_item
#define debug_file gen_ctx->debug_file
@ -168,6 +184,7 @@ static inline gen_ctx_t *gen_ctx_loc (MIR_context_t ctx) { return (gen_ctx_t *)
#define curr_cfg gen_ctx->curr_cfg
#define curr_bb_index gen_ctx->curr_bb_index
#define curr_loop_node_index gen_ctx->curr_loop_node_index
#define free_dead_vars gen_ctx->free_dead_vars
#define dead_bb_insns gen_ctx->dead_bb_insns
#define loop_nodes gen_ctx->loop_nodes
#define queue_nodes gen_ctx->queue_nodes
@ -176,6 +193,31 @@ static inline gen_ctx_t *gen_ctx_loc (MIR_context_t ctx) { return (gen_ctx_t *)
#define max_fp_hard_regs gen_ctx->max_fp_hard_regs
#define func_stack_slots_num gen_ctx->func_stack_slots_num
DEF_VARR (MIR_item_t);
struct all_gen_ctx {
#if MIR_PARALLEL_GEN
mir_mutex_t queue_mutex;
mir_cond_t generate_signal, done_signal;
size_t funcs_start;
VARR (MIR_item_t) * funcs_to_generate;
#endif
MIR_context_t ctx;
size_t gens_num; /* size of the following array: */
struct gen_ctx gen_ctx[1];
};
#if MIR_PARALLEL_GEN
#define queue_mutex all_gen_ctx->queue_mutex
#define generate_signal all_gen_ctx->generate_signal
#define done_signal all_gen_ctx->done_signal
#define funcs_start all_gen_ctx->funcs_start
#define funcs_to_generate all_gen_ctx->funcs_to_generate
#endif
static inline struct all_gen_ctx **all_gen_ctx_loc (MIR_context_t ctx) {
return (struct all_gen_ctx **) ctx;
}
#if defined(__x86_64__) || defined(_M_AMD64)
#include "mir-gen-x86_64.c"
#elif defined(__aarch64__)
@ -251,10 +293,6 @@ static void make_io_dup_op_insns (gen_ctx_t gen_ctx) {
}
}
typedef struct dead_var *dead_var_t;
DEF_DLIST_LINK (dead_var_t);
typedef struct bb *bb_t;
DEF_DLIST_LINK (bb_t);
@ -283,13 +321,6 @@ struct edge {
DEF_DLIST (in_edge_t, in_link);
DEF_DLIST (out_edge_t, out_link);
struct dead_var {
MIR_reg_t var;
DLIST_LINK (dead_var_t) dead_var_link;
};
DEF_DLIST (dead_var_t, dead_var_link);
struct insn_data { /* used only for calls/labels in -O0 mode */
bb_t bb;
union {
@ -410,11 +441,11 @@ struct func_cfg {
loop_node_t root_loop_node;
};
static DLIST (dead_var_t) free_dead_vars;
static void init_dead_vars (gen_ctx_t gen_ctx) { DLIST_INIT (dead_var_t, free_dead_vars); }
static void init_dead_vars (void) { DLIST_INIT (dead_var_t, free_dead_vars); }
static void free_dead_var (dead_var_t dv) { DLIST_APPEND (dead_var_t, free_dead_vars, dv); }
static void free_dead_var (gen_ctx_t gen_ctx, dead_var_t dv) {
DLIST_APPEND (dead_var_t, free_dead_vars, dv);
}
static dead_var_t get_dead_var (gen_ctx_t gen_ctx) {
dead_var_t dv;
@ -425,7 +456,7 @@ static dead_var_t get_dead_var (gen_ctx_t gen_ctx) {
return dv;
}
static void finish_dead_vars (void) {
static void finish_dead_vars (gen_ctx_t gen_ctx) {
dead_var_t dv;
while ((dv = DLIST_HEAD (dead_var_t, free_dead_vars)) != NULL) {
@ -454,16 +485,16 @@ static dead_var_t find_bb_insn_dead_var (bb_insn_t bb_insn, MIR_reg_t var) {
return NULL;
}
static void clear_bb_insn_dead_vars (bb_insn_t bb_insn) {
static void clear_bb_insn_dead_vars (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
dead_var_t dv;
while ((dv = DLIST_HEAD (dead_var_t, bb_insn->dead_vars)) != NULL) {
DLIST_REMOVE (dead_var_t, bb_insn->dead_vars, dv);
free_dead_var (dv);
free_dead_var (gen_ctx, dv);
}
}
static void remove_bb_insn_dead_var (bb_insn_t bb_insn, MIR_reg_t hr) {
static void remove_bb_insn_dead_var (gen_ctx_t gen_ctx, bb_insn_t bb_insn, MIR_reg_t hr) {
dead_var_t dv, next_dv;
gen_assert (hr <= MAX_HARD_REG);
@ -471,7 +502,7 @@ static void remove_bb_insn_dead_var (bb_insn_t bb_insn, MIR_reg_t hr) {
next_dv = DLIST_NEXT (dead_var_t, dv);
if (dv->var != hr) continue;
DLIST_REMOVE (dead_var_t, bb_insn->dead_vars, dv);
free_dead_var (dv);
free_dead_var (gen_ctx, dv);
}
}
@ -521,7 +552,7 @@ static bb_insn_t create_bb_insn (gen_ctx_t gen_ctx, MIR_insn_t insn, bb_t bb) {
bb_insn->insn = insn;
bb_insn->flag = FALSE;
bb_insn->call_hard_reg_args = NULL;
gen_assert (curr_cfg->curr_bb_insn_index < (1ull << 32));
gen_assert (curr_cfg->curr_bb_insn_index != (uint32_t) ~0ull);
bb_insn->index = curr_cfg->curr_bb_insn_index++;
bb_insn->gvn_val = bb_insn->index;
DLIST_INIT (dead_var_t, bb_insn->dead_vars);
@ -536,10 +567,10 @@ static bb_insn_t add_new_bb_insn (gen_ctx_t gen_ctx, MIR_insn_t insn, bb_t bb) {
return bb_insn;
}
static void delete_bb_insn (bb_insn_t bb_insn) {
static void delete_bb_insn (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
DLIST_REMOVE (bb_insn_t, bb_insn->bb->bb_insns, bb_insn);
bb_insn->insn->data = NULL;
clear_bb_insn_dead_vars (bb_insn);
clear_bb_insn_dead_vars (gen_ctx, bb_insn);
if (bb_insn->call_hard_reg_args != NULL) bitmap_destroy (bb_insn->call_hard_reg_args);
free (bb_insn);
}
@ -588,7 +619,7 @@ static void gen_delete_insn (gen_ctx_t gen_ctx, MIR_insn_t insn) {
if (optimize_level == 0)
delete_insn_data (insn);
else
delete_bb_insn (insn->data);
delete_bb_insn (gen_ctx, insn->data);
MIR_remove_insn (gen_ctx->ctx, curr_func_item, insn);
}
@ -612,6 +643,16 @@ static void gen_add_insn_after (gen_ctx_t gen_ctx, MIR_insn_t after, MIR_insn_t
create_new_bb_insns (gen_ctx, after, DLIST_NEXT (MIR_insn_t, insn), after);
}
static void gen_move_insn_before (gen_ctx_t gen_ctx, MIR_insn_t before, MIR_insn_t insn) {
DLIST_REMOVE (MIR_insn_t, curr_func_item->u.func->insns, insn);
MIR_insert_insn_before (gen_ctx->ctx, curr_func_item, before, insn);
if (optimize_level != 0) {
bb_insn_t bb_insn = insn->data, before_bb_insn = before->data;
DLIST_REMOVE (bb_insn_t, bb_insn->bb->bb_insns, bb_insn);
DLIST_INSERT_BEFORE (bb_insn_t, before_bb_insn->bb->bb_insns, before_bb_insn, bb_insn);
}
}
static void setup_call_hard_reg_args (gen_ctx_t gen_ctx, MIR_insn_t call_insn, MIR_reg_t hard_reg) {
insn_data_t insn_data;
@ -1302,7 +1343,7 @@ static void destroy_func_cfg (gen_ctx_t gen_ctx) {
} else {
bb_insn = insn->data;
gen_assert (bb_insn != NULL);
delete_bb_insn (bb_insn);
delete_bb_insn (gen_ctx, bb_insn);
}
for (bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = next_bb) {
next_bb = DLIST_NEXT (bb_t, bb);
@ -3412,7 +3453,7 @@ static void add_bb_insn_dead_vars (gen_ctx_t gen_ctx) {
bitmap_copy (live, bb->live_out);
for (bb_insn = DLIST_TAIL (bb_insn_t, bb->bb_insns); bb_insn != NULL; bb_insn = prev_bb_insn) {
prev_bb_insn = DLIST_PREV (bb_insn_t, bb_insn);
clear_bb_insn_dead_vars (bb_insn);
clear_bb_insn_dead_vars (gen_ctx, bb_insn);
insn = bb_insn->insn;
FOREACH_INSN_VAR (gen_ctx, insn_var_iter, insn, var, op_num, out_p, mem_p, passed_mem_num) {
if (out_p) bitmap_clear_bit_p (live, var);
@ -4438,7 +4479,7 @@ static void combine_delete_insn (gen_ctx_t gen_ctx, MIR_insn_t def_insn, bb_insn
fprintf (debug_file, " deleting now dead insn ");
print_bb_insn (gen_ctx, def_insn->data, TRUE);
});
remove_bb_insn_dead_var (bb_insn, hr);
remove_bb_insn_dead_var (gen_ctx, bb_insn, hr);
move_bb_insn_dead_vars (bb_insn, def_insn->data);
/* We should delete the def insn here because of possible
substitution of the def insn 'r0 = ... r0 ...'. We still
@ -4459,20 +4500,35 @@ static int64_t power2 (int64_t p) {
static int64_t int_log2 (int64_t i) {
int64_t n;
if (i == 0) return -1;
if (i <= 0) return -1;
for (n = 0; (i & 1) == 0; n++, i >>= 1)
;
return i == 1 ? n : -1;
}
static int combine_substitute (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
static MIR_insn_t get_uptodate_def_insn (gen_ctx_t gen_ctx, int hr) {
MIR_insn_t def_insn;
if (!hreg_refs_addr[hr].def_p) return NULL;
gen_assert (!hreg_refs_addr[hr].del_p);
def_insn = hreg_refs_addr[hr].insn;
/* Checking hr0 = ... hr1 ...; ...; hr1 = ...; ...; insn */
if ((def_insn->nops > 1 && obsolete_op_p (gen_ctx, def_insn->ops[1], hreg_refs_addr[hr].insn_num))
|| (def_insn->nops > 2
&& obsolete_op_p (gen_ctx, def_insn->ops[2], hreg_refs_addr[hr].insn_num)))
return NULL;
return def_insn;
}
static int combine_substitute (gen_ctx_t gen_ctx, bb_insn_t *bb_insn_ref) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_insn_code_t code, new_code;
bb_insn_t bb_insn = *bb_insn_ref;
MIR_insn_t insn = bb_insn->insn, def_insn, new_insn;
size_t i, nops = insn->nops;
int out_p, insn_change_p, insn_hr_change_p, op_change_p, mem_reg_change_p, success_p;
MIR_op_t *op_ref, *src_op_ref, *src_op2_ref;
MIR_reg_t hr;
MIR_op_t *op_ref, *src_op_ref, *src_op2_ref, saved_op;
MIR_reg_t hr, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
int64_t scale, sh;
if (nops == 0) return FALSE;
@ -4485,17 +4541,51 @@ static int combine_substitute (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
if (out_p && insn->ops[i].mode != MIR_OP_HARD_REG_MEM) continue;
combine_process_op (gen_ctx, &insn->ops[i], bb_insn);
}
if (move_code_p (insn->code) && VARR_LENGTH (MIR_reg_t, insn_hard_regs) == 1) {
/* We processed all other regs already. Try to change insn the following way:
hr0 = hr2 op hr3; ...; ... = hr0 => ...; ... = hr2 op hr3 */
hr = VARR_GET (MIR_reg_t, insn_hard_regs, 0);
if ((def_insn = get_uptodate_def_insn (gen_ctx, hr)) == NULL
|| MIR_call_code_p (def_insn->code))
return FALSE;
target_get_early_clobbered_hard_regs (def_insn, &early_clobbered_hard_reg1,
&early_clobbered_hard_reg2);
if (!move_code_p (def_insn->code) && early_clobbered_hard_reg1 == MIR_NON_HARD_REG
&& early_clobbered_hard_reg2 == MIR_NON_HARD_REG && insn->ops[1].mode == MIR_OP_HARD_REG
&& insn->ops[1].u.hard_reg == hr
/* Check that insn->ops[0] is not mem[...hr0...]: */
&& (insn->ops[0].mode != MIR_OP_HARD_REG_MEM
|| (insn->ops[0].u.hard_reg_mem.base != hr
&& insn->ops[0].u.hard_reg_mem.index != hr))) {
saved_op = def_insn->ops[0];
def_insn->ops[0] = insn->ops[0];
success_p = target_insn_ok_p (gen_ctx, def_insn);
def_insn->ops[0] = saved_op;
if (!success_p) return FALSE;
gen_move_insn_before (gen_ctx, insn, def_insn);
DEBUG ({
fprintf (debug_file, " moving insn ");
print_bb_insn (gen_ctx, def_insn->data, FALSE);
fprintf (debug_file, " before insn ");
print_bb_insn (gen_ctx, bb_insn, TRUE);
});
def_insn->ops[0] = insn->ops[0];
DEBUG ({
fprintf (debug_file, " changing it to ");
print_bb_insn (gen_ctx, def_insn->data, TRUE);
// deleted_insns_num++;
fprintf (debug_file, " deleting insn ");
print_bb_insn (gen_ctx, bb_insn, TRUE);
});
gen_delete_insn (gen_ctx, insn);
*bb_insn_ref = def_insn->data;
return TRUE;
}
}
insn_change_p = FALSE;
while (VARR_LENGTH (MIR_reg_t, insn_hard_regs) != 0) {
hr = VARR_POP (MIR_reg_t, insn_hard_regs);
if (!hreg_refs_addr[hr].def_p) continue;
gen_assert (!hreg_refs_addr[hr].del_p);
def_insn = hreg_refs_addr[hr].insn;
if ((def_insn->nops > 1
&& obsolete_op_p (gen_ctx, def_insn->ops[1], hreg_refs_addr[hr].insn_num))
|| (def_insn->nops > 2
&& obsolete_op_p (gen_ctx, def_insn->ops[2], hreg_refs_addr[hr].insn_num)))
continue; /* hr0 = ... hr1 ...; ...; hr1 = ...; ...; insn */
if ((def_insn = get_uptodate_def_insn (gen_ctx, hr)) == NULL) continue;
insn_hr_change_p = FALSE;
for (i = 0; i < nops; i++) { /* Change all hr occurences: */
op_ref = &insn->ops[i];
@ -4589,28 +4679,6 @@ static int combine_substitute (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
}
if (op_change_p) VARR_PUSH (size_t, changed_op_numbers, i);
}
code = insn->code;
if (i >= nops && (code == MIR_MUL || code == MIR_MULS || code == MIR_UDIV || code == MIR_UDIVS)
&& insn->ops[2].mode == MIR_OP_INT && (sh = int_log2 (insn->ops[2].u.i)) >= 0) {
new_code = code; /* to remove an initialized warning */
switch (code) {
case MIR_MUL: new_code = MIR_LSH; break;
case MIR_MULS: new_code = MIR_LSHS; break;
case MIR_UDIV: new_code = MIR_URSH; break;
case MIR_UDIVS: new_code = MIR_URSHS; break;
default: gen_assert (FALSE);
}
new_insn = MIR_new_insn (ctx, new_code, insn->ops[0], insn->ops[1], MIR_new_int_op (ctx, sh));
MIR_insert_insn_after (ctx, curr_func_item, insn, new_insn);
if (target_insn_ok_p (gen_ctx, new_insn)) {
insn->code = new_insn->code;
insn->ops[0] = new_insn->ops[0];
insn->ops[1] = new_insn->ops[1];
insn->ops[2] = new_insn->ops[2];
}
MIR_remove_insn (ctx, curr_func_item, new_insn);
insn_hr_change_p = TRUE;
}
if (insn_hr_change_p) {
if ((success_p = i >= nops && target_insn_ok_p (gen_ctx, insn))) insn_change_p = TRUE;
while (VARR_LENGTH (size_t, changed_op_numbers)) {
@ -4714,6 +4782,110 @@ static MIR_insn_t combine_branch_and_cmp (gen_ctx_t gen_ctx, bb_insn_t bb_insn)
}
}
static MIR_insn_t combine_mul_div_substitute (gen_ctx_t gen_ctx, bb_insn_t bb_insn) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_insn_t def_insn = NULL, new_insns[6], insn = bb_insn->insn;
MIR_insn_code_t new_code, code = insn->code;
int n, sh, ok_p;
MIR_op_t op, temp;
switch (code) {
case MIR_MUL: new_code = MIR_LSH; break;
case MIR_MULS: new_code = MIR_LSHS; break;
case MIR_UDIV: new_code = MIR_URSH; break;
case MIR_UDIVS: new_code = MIR_URSHS; break;
case MIR_DIV: new_code = MIR_RSH; break;
case MIR_DIVS: new_code = MIR_RSHS; break;
default: return NULL;
}
op = insn->ops[2];
if (op.mode == MIR_OP_HARD_REG && safe_hreg_substitution_p (gen_ctx, op.u.hard_reg, bb_insn)) {
def_insn = hreg_refs_addr[op.u.hard_reg].insn;
if (def_insn->code != MIR_MOV) return NULL;
op = def_insn->ops[1];
}
if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT) return NULL;
if ((sh = int_log2 (op.u.i)) < 0) return NULL;
if (sh == 0) {
new_insns[0] = MIR_new_insn (ctx, MIR_MOV, insn->ops[0], insn->ops[1]);
gen_add_insn_before (gen_ctx, insn, new_insns[0]);
move_bb_insn_dead_vars (new_insns[0]->data, bb_insn);
DEBUG ({
fprintf (debug_file, " changing to ");
print_bb_insn (gen_ctx, new_insns[0]->data, TRUE);
});
gen_delete_insn (gen_ctx, insn);
if (def_insn != NULL) {
DEBUG ({
fprintf (debug_file, " deleting now dead insn ");
print_bb_insn (gen_ctx, def_insn->data, TRUE);
});
gen_delete_insn (gen_ctx, def_insn);
}
return new_insns[0];
} else if (code == MIR_MUL || code == MIR_MULS || code == MIR_UDIV || code == MIR_UDIVS) {
new_insns[0]
= MIR_new_insn (ctx, new_code, insn->ops[0], insn->ops[1], MIR_new_int_op (ctx, sh));
MIR_insert_insn_after (ctx, curr_func_item, insn, new_insns[0]);
if ((ok_p = target_insn_ok_p (gen_ctx, new_insns[0]))) {
insn->code = new_insns[0]->code;
insn->ops[2] = new_insns[0]->ops[2];
DEBUG ({
fprintf (debug_file, " changing to ");
print_bb_insn (gen_ctx, bb_insn, TRUE);
});
}
MIR_remove_insn (ctx, curr_func_item, new_insns[0]);
return ok_p ? insn : NULL;
} else if (insn->ops[1].mode == MIR_OP_HARD_REG
&& insn->ops[1].u.hard_reg == TEMP_INT_HARD_REG2) {
} else if (insn->ops[1].mode == MIR_OP_HARD_REG_MEM
&& (insn->ops[1].u.hard_reg_mem.base == TEMP_INT_HARD_REG2
|| insn->ops[1].u.hard_reg_mem.index == TEMP_INT_HARD_REG2)) {
} else {
temp = _MIR_new_hard_reg_op (ctx, TEMP_INT_HARD_REG2);
gen_assert (code == MIR_DIV || code == MIR_DIVS);
new_insns[0] = MIR_new_insn (ctx, MIR_MOV, temp, insn->ops[1]);
if (code == MIR_DIV) {
new_insns[1] = MIR_new_insn (ctx, MIR_RSH, temp, temp, MIR_new_int_op (ctx, 63));
new_insns[2] = MIR_new_insn (ctx, MIR_AND, temp, temp, MIR_new_int_op (ctx, op.u.i - 1));
new_insns[3] = MIR_new_insn (ctx, MIR_ADD, temp, temp, insn->ops[1]);
} else {
new_insns[1] = MIR_new_insn (ctx, MIR_RSHS, temp, temp, MIR_new_int_op (ctx, 31));
new_insns[2] = MIR_new_insn (ctx, MIR_ANDS, temp, temp, MIR_new_int_op (ctx, op.u.i - 1));
new_insns[3] = MIR_new_insn (ctx, MIR_ADDS, temp, temp, insn->ops[1]);
}
new_insns[4] = MIR_new_insn (ctx, new_code, temp, temp, MIR_new_int_op (ctx, sh));
new_insns[5] = MIR_new_insn (ctx, MIR_MOV, insn->ops[0], temp);
for (n = 0; n < 6; n++) gen_add_insn_before (gen_ctx, insn, new_insns[n]);
for (n = 0; n < 6; n++)
if (!target_insn_ok_p (gen_ctx, new_insns[n])) break;
if (n < 6) {
for (n = 0; n < 6; n++) gen_delete_insn (gen_ctx, new_insns[n]);
} else {
move_bb_insn_dead_vars (new_insns[3]->data, bb_insn);
add_bb_insn_dead_var (gen_ctx, new_insns[5]->data, TEMP_INT_HARD_REG2);
DEBUG ({
fprintf (debug_file, " changing to ");
for (n = 0; n < 6; n++) {
if (n != 0) fprintf (debug_file, " ");
print_bb_insn (gen_ctx, new_insns[n]->data, TRUE);
}
});
gen_delete_insn (gen_ctx, insn);
if (def_insn != NULL) {
DEBUG ({
fprintf (debug_file, " deleting now dead insn ");
print_bb_insn (gen_ctx, def_insn->data, TRUE);
});
gen_delete_insn (gen_ctx, def_insn);
}
return new_insns[0];
}
}
return NULL;
}
static void setup_hreg_ref (gen_ctx_t gen_ctx, MIR_reg_t hr, MIR_insn_t insn, size_t nop,
size_t insn_num, int def_p) {
if (hr == MIR_NON_HARD_REG) return;
@ -4771,20 +4943,27 @@ static void combine (gen_ctx_t gen_ctx) {
last_mem_ref_insn_num = curr_insn_num; /* Potentially call can change memory */
} else if (code == MIR_RET) {
/* ret is transformed in machinize and should be not modified after that */
} else if ((new_insn = combine_branch_and_cmp (gen_ctx, bb_insn)) != NULL) {
} else if ((new_insn = combine_branch_and_cmp (gen_ctx, bb_insn)) != NULL
|| (new_insn = combine_mul_div_substitute (gen_ctx, bb_insn)) != NULL) {
bb_insn = new_insn->data;
insn = new_insn;
nops = MIR_insn_nops (ctx, insn);
block_change_p = TRUE;
} else {
change_p = combine_substitute (gen_ctx, bb_insn);
if (!change_p && (new_code = commutative_insn_code (insn->code)) != MIR_INSN_BOUND) {
if ((change_p = combine_substitute (gen_ctx, &bb_insn))) {
insn = bb_insn->insn;
nops = MIR_insn_nops (ctx, insn);
} else if (!change_p
&& (new_code = commutative_insn_code (insn->code)) != MIR_INSN_BOUND) {
insn->code = new_code;
temp_op = insn->ops[1];
insn->ops[1] = insn->ops[2];
insn->ops[2] = temp_op;
if (combine_substitute (gen_ctx, bb_insn))
if (combine_substitute (gen_ctx, &bb_insn)) {
insn = bb_insn->insn;
nops = MIR_insn_nops (ctx, insn);
change_p = TRUE;
else {
} else {
insn->code = code;
temp_op = insn->ops[1];
insn->ops[1] = insn->ops[2];
@ -4992,7 +5171,7 @@ static void ssa_dead_code_elimination (gen_ctx_t gen_ctx) {
static void print_code (gen_ctx_t gen_ctx, uint8_t *code, size_t code_len, void *start_addr) {
size_t i;
int ch;
char cfname[30];
char cfname[50];
char command[500];
FILE *f;
#if !defined(__APPLE__)
@ -5000,7 +5179,7 @@ static void print_code (gen_ctx_t gen_ctx, uint8_t *code, size_t code_len, void
FILE *bf;
#endif
sprintf (cfname, "_mir_%lu.c", (unsigned long) getpid ());
sprintf (cfname, "_mir_%d_%lu.c", gen_ctx->gen_num, (unsigned long) getpid ());
if ((f = fopen (cfname, "w")) == NULL) return;
#if defined(__APPLE__)
fprintf (f, "unsigned char code[] = {");
@ -5013,7 +5192,7 @@ static void print_code (gen_ctx_t gen_ctx, uint8_t *code, size_t code_len, void
sprintf (command, "gcc -c -o %s.o %s 2>&1 && objdump --section=.data -D %s.o; rm -f %s.o %s",
cfname, cfname, cfname, cfname, cfname);
#else
sprintf (bfname, "_mir_%lu.bin", (unsigned long) getpid ());
sprintf (bfname, "_mir_%d_%lu.bin", gen_ctx->gen_num, (unsigned long) getpid ());
if ((bf = fopen (bfname, "w")) == NULL) return;
fprintf (f, "void code (void) {}\n");
for (i = 0; i < code_len; i++) fputc (code[i], bf);
@ -5045,14 +5224,23 @@ static void *print_and_execute_wrapper (gen_ctx_t gen_ctx, MIR_item_t called_fun
}
#endif
void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
gen_ctx_t gen_ctx = *gen_ctx_loc (ctx);
static void parallel_error (MIR_context_t ctx, const char *err_message) {
MIR_get_error_func (ctx) (MIR_parallel_error, err_message);
}
void *MIR_gen (MIR_context_t ctx, int gen_num, MIR_item_t func_item) {
struct all_gen_ctx *all_gen_ctx = *all_gen_ctx_loc (ctx);
gen_ctx_t gen_ctx;
uint8_t *code;
void *machine_code;
size_t code_len;
#if !MIR_NO_GEN_DEBUG
double start_time = 0.0;
#endif
double start_time = real_usec_time ();
#if !MIR_PARALLEL_GEN
gen_num = 0;
#endif
gen_assert (gen_num >= 0 && gen_num < all_gen_ctx->gens_num);
gen_ctx = &all_gen_ctx->gen_ctx[gen_num];
gen_assert (func_item->item_type == MIR_func_item && func_item->data == NULL);
if (func_item->u.func->machine_code != NULL) {
gen_assert (func_item->u.func->call_addr != NULL);
@ -5064,7 +5252,6 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
return func_item->addr;
}
DEBUG ({
start_time = real_usec_time ();
fprintf (debug_file, "+++++++++++++MIR before generator:\n");
MIR_output_item (ctx, debug_file, func_item);
});
@ -5180,15 +5367,13 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
print_CFG (gen_ctx, FALSE, FALSE, TRUE, FALSE, NULL);
});
code = target_translate (gen_ctx, &code_len);
func_item->u.func->machine_code = func_item->u.func->call_addr
= _MIR_publish_code (ctx, code, code_len);
target_rebase (gen_ctx, func_item->u.func->machine_code);
machine_code = func_item->u.func->call_addr = _MIR_publish_code (ctx, code, code_len);
target_rebase (gen_ctx, func_item->u.func->call_addr);
#if MIR_GEN_CALL_TRACE
func_item->u.func->call_addr = _MIR_get_wrapper (ctx, func_item, print_and_execute_wrapper);
#endif
DEBUG ({
print_code (gen_ctx, func_item->u.func->machine_code, code_len,
func_item->u.func->machine_code);
print_code (gen_ctx, machine_code, code_len, machine_code);
fprintf (debug_file, "code size = %lu:\n", (unsigned long) code_len);
});
_MIR_redirect_thunk (ctx, func_item->addr, func_item->u.func->call_addr);
@ -5196,118 +5381,296 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
if (optimize_level != 0) destroy_loop_tree (gen_ctx, curr_cfg->root_loop_node);
destroy_func_cfg (gen_ctx);
DEBUG ({
fprintf (debug_file, "Generation of code for %s: %lu MIR insns -- time %.0f usec\n",
fprintf (debug_file,
"Generation of code for %s: %lu MIR insns (addr=%lx, len=%lu) -- time %.2f ms\n",
MIR_item_name (ctx, func_item), DLIST_LENGTH (MIR_insn_t, func_item->u.func->insns),
real_usec_time () - start_time);
(unsigned long) machine_code, (unsigned long) code_len,
(real_usec_time () - start_time) / 1000.0);
});
_MIR_restore_func_insns (ctx, func_item);
/* ??? We should use atomic here but c2mir does not implement them yet. */
#if MIR_PARALLEL_GEN
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
#endif
func_item->u.func->machine_code = machine_code;
#if MIR_PARALLEL_GEN
if (mir_cond_broadcast (&done_signal)) parallel_error (ctx, "error in cond broadcast");
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
#endif
return func_item->addr;
}
void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f) {
void MIR_gen_set_debug_file (MIR_context_t ctx, int gen_num, FILE *f) {
#if !MIR_NO_GEN_DEBUG
gen_ctx_t gen_ctx = *gen_ctx_loc (ctx);
struct all_gen_ctx *all_gen_ctx = *all_gen_ctx_loc (ctx);
gen_ctx_t gen_ctx;
if (gen_ctx == NULL) {
if (all_gen_ctx == NULL) {
fprintf (stderr, "Calling MIR_gen_set_debug_file before MIR_gen_init -- good bye\n");
exit (1);
}
#if !MIR_PARALLEL_GEN
gen_num = 0;
#endif
gen_assert (gen_num >= 0 && gen_num < all_gen_ctx->gens_num);
gen_ctx = &all_gen_ctx->gen_ctx[gen_num];
debug_file = f;
#endif
}
void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level) {
gen_ctx_t gen_ctx = *gen_ctx_loc (ctx);
void MIR_gen_set_optimize_level (MIR_context_t ctx, int gen_num, unsigned int level) {
struct all_gen_ctx *all_gen_ctx = *all_gen_ctx_loc (ctx);
gen_ctx_t gen_ctx;
#if !MIR_PARALLEL_GEN
gen_num = 0;
#endif
gen_assert (gen_num >= 0 && gen_num < all_gen_ctx->gens_num);
gen_ctx = &all_gen_ctx->gen_ctx[gen_num];
optimize_level = level;
}
void MIR_gen_init (MIR_context_t ctx) {
gen_ctx_t *gen_ctx_ptr = gen_ctx_loc (ctx), gen_ctx;
MIR_reg_t i;
#if MIR_PARALLEL_GEN
static void *gen (void *arg) {
MIR_item_t func_item;
gen_ctx_t gen_ctx = arg;
struct all_gen_ctx *all_gen_ctx = gen_ctx->all_gen_ctx;
MIR_context_t ctx = all_gen_ctx->ctx;
size_t len;
for (;;) {
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
while (VARR_LENGTH (MIR_item_t, funcs_to_generate) <= funcs_start)
if (mir_cond_wait (&generate_signal, &queue_mutex))
parallel_error (ctx, "error in cond wait");
if ((func_item = VARR_GET (MIR_item_t, funcs_to_generate, funcs_start)) == NULL) {
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
break;
}
funcs_start++;
if (funcs_start > 64 && VARR_LENGTH (MIR_item_t, funcs_to_generate) < 2 * funcs_start) {
len = VARR_LENGTH (MIR_item_t, funcs_to_generate) - funcs_start;
memmove (VARR_ADDR (MIR_item_t, funcs_to_generate), /* compact */
VARR_ADDR (MIR_item_t, funcs_to_generate) + funcs_start, len * sizeof (MIR_item_t));
VARR_TRUNC (MIR_item_t, funcs_to_generate, len);
funcs_start = 0;
}
gen_ctx->busy_p = TRUE;
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
MIR_gen (gen_ctx->ctx, gen_ctx->gen_num, func_item);
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
gen_ctx->busy_p = FALSE;
if (mir_cond_signal (&done_signal)) parallel_error (ctx, "error in cond signal");
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
}
return NULL;
}
*gen_ctx_ptr = gen_ctx = gen_malloc (NULL, sizeof (struct gen_ctx));
gen_ctx->ctx = ctx;
optimize_level = 2;
gen_ctx->target_ctx = NULL;
gen_ctx->data_flow_ctx = NULL;
gen_ctx->gvn_ctx = NULL;
gen_ctx->ccp_ctx = NULL;
gen_ctx->lr_ctx = NULL;
gen_ctx->ra_ctx = NULL;
gen_ctx->selection_ctx = NULL;
static void signal_threads_to_finish (struct all_gen_ctx *all_gen_ctx) {
MIR_context_t ctx = all_gen_ctx->ctx;
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
funcs_start = 0;
VARR_TRUNC (MIR_item_t, funcs_to_generate, 0);
VARR_PUSH (MIR_item_t, funcs_to_generate, NULL); /* flag to finish threads */
if (mir_cond_broadcast (&generate_signal)) parallel_error (ctx, "error in cond broadcast");
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
}
#endif
void MIR_gen_init (MIR_context_t ctx, int gens_num) {
struct all_gen_ctx **all_gen_ctx_ptr = all_gen_ctx_loc (ctx), *all_gen_ctx;
gen_ctx_t gen_ctx;
MIR_reg_t reg;
#if !MIR_PARALLEL_GEN
gens_num = 1;
#else
if (gens_num < 1) gens_num = 1;
#endif
*all_gen_ctx_ptr = all_gen_ctx
= gen_malloc (NULL, sizeof (struct all_gen_ctx) + sizeof (struct gen_ctx) * (gens_num - 1));
all_gen_ctx->ctx = ctx;
all_gen_ctx->gens_num = gens_num;
#if MIR_PARALLEL_GEN
funcs_start = 0;
VARR_CREATE (MIR_item_t, funcs_to_generate, 0);
if (mir_mutex_init (&queue_mutex, NULL) != 0) {
(*MIR_get_error_func (ctx)) (MIR_parallel_error, "can not create a generator thread lock");
} else if (mir_cond_init (&generate_signal, NULL) != 0) {
mir_mutex_destroy (&queue_mutex);
(*MIR_get_error_func (ctx)) (MIR_parallel_error, "can not create a generator thread signal");
} else if (mir_cond_init (&done_signal, NULL) != 0) {
mir_cond_destroy (&generate_signal);
mir_mutex_destroy (&queue_mutex);
(*MIR_get_error_func (ctx)) (MIR_parallel_error, "can not create a generator thread signal");
} else {
for (int i = 0; i < gens_num; i++) {
gen_ctx = &all_gen_ctx->gen_ctx[i];
gen_ctx->busy_p = FALSE;
gen_ctx->gen_num = i;
gen_ctx->all_gen_ctx = all_gen_ctx;
if (mir_thread_create (&gen_ctx->gen_thread, NULL, gen, gen_ctx) != 0) {
signal_threads_to_finish (all_gen_ctx);
for (int j = 0; j < i; j++) mir_thread_join (all_gen_ctx->gen_ctx[j].gen_thread, NULL);
mir_cond_destroy (&done_signal);
mir_cond_destroy (&generate_signal);
mir_mutex_destroy (&queue_mutex);
(*MIR_get_error_func (ctx)) (MIR_parallel_error, "can not create a generator thread");
}
}
}
#endif
for (int n = 0; n < gens_num; n++) {
gen_ctx = &all_gen_ctx->gen_ctx[n];
#if !MIR_PARALLEL_GEN
gen_ctx->all_gen_ctx = all_gen_ctx;
gen_ctx->gen_num = n;
#endif
gen_ctx->ctx = ctx;
optimize_level = 2;
gen_ctx->target_ctx = NULL;
gen_ctx->data_flow_ctx = NULL;
gen_ctx->gvn_ctx = NULL;
gen_ctx->ccp_ctx = NULL;
gen_ctx->lr_ctx = NULL;
gen_ctx->ra_ctx = NULL;
gen_ctx->selection_ctx = NULL;
#if !MIR_NO_GEN_DEBUG
debug_file = NULL;
debug_file = NULL;
#endif
VARR_CREATE (bb_insn_t, dead_bb_insns, 16);
VARR_CREATE (loop_node_t, loop_nodes, 32);
VARR_CREATE (loop_node_t, queue_nodes, 32);
VARR_CREATE (loop_node_t, loop_entries, 16);
init_dead_vars ();
init_data_flow (gen_ctx);
init_ssa (gen_ctx);
init_gvn (gen_ctx);
init_ccp (gen_ctx);
temp_bitmap = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
temp_bitmap2 = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
init_live_ranges (gen_ctx);
init_ra (gen_ctx);
init_selection (gen_ctx);
target_init (gen_ctx);
max_int_hard_regs = max_fp_hard_regs = 0;
for (i = 0; i <= MAX_HARD_REG; i++) {
if (target_fixed_hard_reg_p (i)) continue;
target_hard_reg_type_ok_p (i, MIR_T_I32) ? max_int_hard_regs++ : max_fp_hard_regs++;
}
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++) {
call_used_hard_regs[type] = bitmap_create2 (MAX_HARD_REG + 1);
for (i = 0; i <= MAX_HARD_REG; i++) {
/* We need call_used_hard_regs even for fixed regs in combine. */
if (target_call_used_hard_reg_p (i, type)) bitmap_set_bit_p (call_used_hard_regs[type], i);
VARR_CREATE (bb_insn_t, dead_bb_insns, 16);
VARR_CREATE (loop_node_t, loop_nodes, 32);
VARR_CREATE (loop_node_t, queue_nodes, 32);
VARR_CREATE (loop_node_t, loop_entries, 16);
init_dead_vars (gen_ctx);
init_data_flow (gen_ctx);
init_ssa (gen_ctx);
init_gvn (gen_ctx);
init_ccp (gen_ctx);
temp_bitmap = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
temp_bitmap2 = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
init_live_ranges (gen_ctx);
init_ra (gen_ctx);
init_selection (gen_ctx);
target_init (gen_ctx);
max_int_hard_regs = max_fp_hard_regs = 0;
for (int i = 0; i <= MAX_HARD_REG; i++) {
if (target_fixed_hard_reg_p (i)) continue;
target_hard_reg_type_ok_p (i, MIR_T_I32) ? max_int_hard_regs++ : max_fp_hard_regs++;
}
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++) {
call_used_hard_regs[type] = bitmap_create2 (MAX_HARD_REG + 1);
for (int i = 0; i <= MAX_HARD_REG; i++) {
/* We need call_used_hard_regs even for fixed regs in combine. */
if (target_call_used_hard_reg_p (i, type)) bitmap_set_bit_p (call_used_hard_regs[type], i);
}
}
insn_to_consider = bitmap_create2 (1024);
func_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
}
insn_to_consider = bitmap_create2 (1024);
func_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
}
void MIR_gen_finish (MIR_context_t ctx) {
gen_ctx_t *gen_ctx_ptr = gen_ctx_loc (ctx);
gen_ctx_t gen_ctx = *gen_ctx_ptr;
finish_data_flow (gen_ctx);
finish_ssa (gen_ctx);
finish_gvn (gen_ctx);
finish_ccp (gen_ctx);
bitmap_destroy (temp_bitmap);
bitmap_destroy (temp_bitmap2);
finish_live_ranges (gen_ctx);
finish_ra (gen_ctx);
finish_selection (gen_ctx);
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++)
bitmap_destroy (call_used_hard_regs[type]);
bitmap_destroy (insn_to_consider);
bitmap_destroy (func_used_hard_regs);
target_finish (gen_ctx);
finish_dead_vars ();
free (gen_ctx->data_flow_ctx);
VARR_DESTROY (bb_insn_t, dead_bb_insns);
VARR_DESTROY (loop_node_t, loop_nodes);
VARR_DESTROY (loop_node_t, queue_nodes);
VARR_DESTROY (loop_node_t, loop_entries);
free (gen_ctx);
*gen_ctx_ptr = NULL;
struct all_gen_ctx **all_gen_ctx_ptr = all_gen_ctx_loc (ctx), *all_gen_ctx = *all_gen_ctx_ptr;
gen_ctx_t gen_ctx;
#if MIR_PARALLEL_GEN
signal_threads_to_finish (all_gen_ctx);
for (int i = 0; i < all_gen_ctx->gens_num; i++)
mir_thread_join (all_gen_ctx->gen_ctx[i].gen_thread, NULL);
if (mir_mutex_destroy (&queue_mutex) != 0 || mir_cond_destroy (&generate_signal) != 0
|| mir_cond_destroy (&done_signal) != 0) { // ???
(*MIR_get_error_func (all_gen_ctx->ctx)) (MIR_parallel_error,
"can not destroy generator mutex or signals");
}
#endif
for (int i = 0; i < all_gen_ctx->gens_num; i++) {
gen_ctx = &all_gen_ctx->gen_ctx[i];
finish_data_flow (gen_ctx);
finish_ssa (gen_ctx);
finish_gvn (gen_ctx);
finish_ccp (gen_ctx);
bitmap_destroy (temp_bitmap);
bitmap_destroy (temp_bitmap2);
finish_live_ranges (gen_ctx);
finish_ra (gen_ctx);
finish_selection (gen_ctx);
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++)
bitmap_destroy (call_used_hard_regs[type]);
bitmap_destroy (insn_to_consider);
bitmap_destroy (func_used_hard_regs);
target_finish (gen_ctx);
finish_dead_vars (gen_ctx);
free (gen_ctx->data_flow_ctx);
VARR_DESTROY (bb_insn_t, dead_bb_insns);
VARR_DESTROY (loop_node_t, loop_nodes);
VARR_DESTROY (loop_node_t, queue_nodes);
VARR_DESTROY (loop_node_t, loop_entries);
}
free (all_gen_ctx);
*all_gen_ctx_ptr = NULL;
}
void MIR_set_gen_interface (MIR_context_t ctx, MIR_item_t func_item) {
if (func_item == NULL) return; /* finish setting interfaces */
MIR_gen (ctx, 0, func_item);
}
void MIR_set_parallel_gen_interface (MIR_context_t ctx, MIR_item_t func_item) {
struct all_gen_ctx *all_gen_ctx = *all_gen_ctx_loc (ctx);
#if !MIR_PARALLEL_GEN
if (func_item == NULL) return; /* finish setting interfaces */
MIR_gen (ctx, 0, func_item);
#else
if (func_item == NULL) {
size_t i;
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
for (;;) {
for (i = 0; i < all_gen_ctx->gens_num; i++)
if (all_gen_ctx->gen_ctx[i].busy_p) break;
if (VARR_LENGTH (MIR_item_t, funcs_to_generate) <= funcs_start && i >= all_gen_ctx->gens_num)
break; /* nothing to generate and nothing is being generated */
if (mir_cond_wait (&done_signal, &queue_mutex)) parallel_error (ctx, "error in cond wait");
}
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
} else {
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
VARR_PUSH (MIR_item_t, funcs_to_generate, func_item);
if (mir_cond_broadcast (&generate_signal)) parallel_error (ctx, "error in cond broadcast");
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
}
#endif
}
void MIR_set_gen_interface (MIR_context_t ctx, MIR_item_t func_item) { MIR_gen (ctx, func_item); }
static void *gen_and_redirect (MIR_context_t ctx, MIR_item_t func_item) {
MIR_gen (ctx, func_item);
#if !MIR_PARALLEL_GEN
MIR_gen (ctx, 0, func_item);
#else
struct all_gen_ctx *all_gen_ctx = *all_gen_ctx_loc (ctx);
MIR_func_t func = func_item->u.func;
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
VARR_PUSH (MIR_item_t, funcs_to_generate, func_item);
if (mir_cond_broadcast (&generate_signal)) parallel_error (ctx, "error in cond broadcast");
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
if (mir_mutex_lock (&queue_mutex)) parallel_error (ctx, "error in mutex lock");
for (;;) {
if (func->machine_code != NULL) break;
if (mir_cond_wait (&done_signal, &queue_mutex)) parallel_error (ctx, "error in cond wait");
}
if (mir_mutex_unlock (&queue_mutex)) parallel_error (ctx, "error in mutex unlock");
#endif
return func_item->u.func->machine_code;
}
void MIR_set_lazy_gen_interface (MIR_context_t ctx, MIR_item_t func_item) {
void *addr = _MIR_get_wrapper (ctx, func_item, gen_and_redirect);
void *addr;
if (func_item == NULL) return;
addr = _MIR_get_wrapper (ctx, func_item, gen_and_redirect);
_MIR_redirect_thunk (ctx, func_item->addr, addr);
}

@ -12,11 +12,12 @@
#define MIR_NO_GEN_DEBUG 0
#endif
extern void MIR_gen_init (MIR_context_t ctx);
extern void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f);
extern void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level);
extern void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item);
extern void MIR_gen_init (MIR_context_t ctx, int gens_num);
extern void MIR_gen_set_debug_file (MIR_context_t ctx, int gen_num, FILE *f);
extern void MIR_gen_set_optimize_level (MIR_context_t ctx, int gen_num, unsigned int level);
extern void *MIR_gen (MIR_context_t ctx, int gen_num, MIR_item_t func_item);
extern void MIR_set_gen_interface (MIR_context_t ctx, MIR_item_t func_item);
extern void MIR_set_parallel_gen_interface (MIR_context_t ctx, MIR_item_t func_item);
extern void MIR_set_lazy_gen_interface (MIR_context_t ctx, MIR_item_t func_item);
extern void MIR_gen_finish (MIR_context_t ctx);

@ -1527,7 +1527,7 @@ static void interp_init (MIR_context_t ctx) {
struct interp_ctx *interp_ctx;
if ((interp_ctx = ctx->interp_ctx = malloc (sizeof (struct interp_ctx))) == NULL)
(*error_func) (MIR_alloc_error, "Not enough memory for ctx");
MIR_get_error_func (ctx) (MIR_alloc_error, "Not enough memory for ctx");
#if DIRECT_THREADED_DISPATCH
eval (ctx, NULL, NULL, NULL);
#endif
@ -1696,7 +1696,7 @@ static void redirect_interface_to_interp (MIR_context_t ctx, MIR_item_t func_ite
}
void MIR_set_interp_interface (MIR_context_t ctx, MIR_item_t func_item) {
redirect_interface_to_interp (ctx, func_item);
if (func_item != NULL) redirect_interface_to_interp (ctx, func_item);
}
#endif /* #ifdef MIR_NO_INTERP */

@ -17,13 +17,13 @@
#define PPC64_FUNC_DESC_LEN 24
#endif
static void ppc64_push_func_desc (MIR_context_t ctx);
void (*ppc64_func_desc) (MIR_context_t ctx) = ppc64_push_func_desc;
static void ppc64_push_func_desc (VARR (uint8_t) ** insn_varr);
void (*ppc64_func_desc) (VARR (uint8_t) ** insn_varr) = ppc64_push_func_desc;
static void ppc64_push_func_desc (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
static void ppc64_push_func_desc (VARR (uint8_t) ** insn_varr) {
VARR_CREATE (uint8_t, *insn_varr, 128);
for (int i = 0; i < PPC64_FUNC_DESC_LEN; i++)
VARR_PUSH (uint8_t, machine_insns, ((uint8_t *) ppc64_func_desc)[i]);
VARR_PUSH (uint8_t, *insn_varr, ((uint8_t *) ppc64_func_desc)[i]);
}
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
@ -33,99 +33,102 @@ static void ppc64_redirect_func_desc (MIR_context_t ctx, void *desc, void *to) {
}
#endif
static void *ppc64_publish_func_and_redirect (MIR_context_t ctx) {
void *res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
static void *ppc64_publish_func_and_redirect (MIR_context_t ctx, VARR (uint8_t) * insn_varr) {
void *res
= _MIR_publish_code (ctx, VARR_ADDR (uint8_t, insn_varr), VARR_LENGTH (uint8_t, insn_varr));
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ppc64_redirect_func_desc (ctx, res, (uint8_t *) res + PPC64_FUNC_DESC_LEN);
#endif
VARR_DESTROY (uint8_t, insn_varr);
return res;
}
static void push_insn (MIR_context_t ctx, uint32_t insn) {
static void push_insn (VARR (uint8_t) * insn_varr, uint32_t insn) {
uint8_t *p = (uint8_t *) &insn;
for (size_t i = 0; i < 4; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
for (size_t i = 0; i < 4; i++) VARR_PUSH (uint8_t, insn_varr, p[i]);
}
static void push_insns (MIR_context_t ctx, const uint32_t *pat, size_t pat_len) {
static void push_insns (VARR (uint8_t) * insn_varr, const uint32_t *pat, size_t pat_len) {
uint8_t *p = (uint8_t *) pat;
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, insn_varr, p[i]);
}
static void ppc64_gen_mov (MIR_context_t ctx, unsigned to, unsigned from) {
static void ppc64_gen_mov (VARR (uint8_t) * insn_varr, unsigned to, unsigned from) {
/* or to,from,from: */
push_insn (ctx, (31 << 26) | (444 << 1) | (from << 21) | (to << 16) | (from << 11));
push_insn (insn_varr, (31 << 26) | (444 << 1) | (from << 21) | (to << 16) | (from << 11));
}
static void ppc64_gen_addi (MIR_context_t ctx, unsigned rt_reg, unsigned ra_reg, int disp) {
push_insn (ctx, (14 << 26) | (rt_reg << 21) | (ra_reg << 16) | (disp & 0xffff));
static void ppc64_gen_addi (VARR (uint8_t) * insn_varr, unsigned rt_reg, unsigned ra_reg,
int disp) {
push_insn (insn_varr, (14 << 26) | (rt_reg << 21) | (ra_reg << 16) | (disp & 0xffff));
}
static void ppc64_gen_add (MIR_context_t ctx, unsigned rt_reg, unsigned ra_reg, unsigned rb_reg) {
push_insn (ctx, (31 << 26) | (266 << 1) | (rt_reg << 21) | (ra_reg << 16) | (rb_reg << 11));
static void ppc64_gen_add (VARR (uint8_t) * insn_varr, unsigned rt_reg, unsigned ra_reg,
unsigned rb_reg) {
push_insn (insn_varr, (31 << 26) | (266 << 1) | (rt_reg << 21) | (ra_reg << 16) | (rb_reg << 11));
}
static void ppc64_gen_ld (MIR_context_t ctx, unsigned to, unsigned base, int disp,
static void ppc64_gen_ld (VARR (uint8_t) * insn_varr, unsigned to, unsigned base, int disp,
MIR_type_t type) {
int single_p = type == MIR_T_F;
int double_p = type == MIR_T_D || type == MIR_T_LD;
/* (ld | lf[sd]) to, disp(base): */
assert (base != 0 && base < 32 && to < 32 && (single_p || double_p || (disp & 0x3) == 0));
push_insn (ctx, ((single_p ? 48 : double_p ? 50 : 58) << 26) | (to << 21) | (base << 16)
| (disp & 0xffff));
push_insn (insn_varr, ((single_p ? 48 : double_p ? 50 : 58) << 26) | (to << 21) | (base << 16)
| (disp & 0xffff));
}
static void ppc64_gen_st (MIR_context_t ctx, unsigned from, unsigned base, int disp,
static void ppc64_gen_st (VARR (uint8_t) * insn_varr, unsigned from, unsigned base, int disp,
MIR_type_t type) {
int single_p = type == MIR_T_F;
int double_p = type == MIR_T_D || type == MIR_T_LD;
/* std|stf[sd] from, disp(base): */
assert (base != 0 && base < 32 && from < 32 && (single_p || double_p || (disp & 0x3) == 0));
push_insn (ctx, ((single_p ? 52 : double_p ? 54 : 62) << 26) | (from << 21) | (base << 16)
| (disp & 0xffff));
push_insn (insn_varr, ((single_p ? 52 : double_p ? 54 : 62) << 26) | (from << 21) | (base << 16)
| (disp & 0xffff));
}
static void ppc64_gen_stdu (MIR_context_t ctx, int disp) {
static void ppc64_gen_stdu (VARR (uint8_t) * insn_varr, int disp) {
assert ((disp & 0x3) == 0);
push_insn (ctx, 0xf8210001 | disp & 0xfffc); /* stdu 1, disp (1) */
push_insn (insn_varr, 0xf8210001 | disp & 0xfffc); /* stdu 1, disp (1) */
}
static void ppc64_gen_address (MIR_context_t ctx, unsigned int reg, void *p) {
static void ppc64_gen_address (VARR (uint8_t) * insn_varr, unsigned int reg, void *p) {
uint64_t a = (uint64_t) p;
if ((a >> 32) == 0) {
if (((a >> 31) & 1) == 0) { /* lis r,0,Z2 */
push_insn (ctx, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 16) & 0xffff);
push_insn (insn_varr, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 16) & 0xffff);
} else { /* xor r,r,r; oris r,r,Z2 */
push_insn (ctx, (31 << 26) | (316 << 1) | (reg << 21) | (reg << 16) | (reg << 11));
push_insn (ctx, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
push_insn (insn_varr, (31 << 26) | (316 << 1) | (reg << 21) | (reg << 16) | (reg << 11));
push_insn (insn_varr, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
}
} else {
/* lis r,0,Z0; ori r,r,Z1; rldicr r,r,32,31; oris r,r,Z2; ori r,r,Z3: */
push_insn (ctx, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 48));
push_insn (ctx, (24 << 26) | (reg << 21) | (reg << 16) | (a >> 32) & 0xffff);
push_insn (ctx, (30 << 26) | (reg << 21) | (reg << 16) | 0x07c6);
push_insn (ctx, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
push_insn (insn_varr, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 48));
push_insn (insn_varr, (24 << 26) | (reg << 21) | (reg << 16) | (a >> 32) & 0xffff);
push_insn (insn_varr, (30 << 26) | (reg << 21) | (reg << 16) | 0x07c6);
push_insn (insn_varr, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
}
push_insn (ctx, (24 << 26) | (reg << 21) | (reg << 16) | a & 0xffff);
push_insn (insn_varr, (24 << 26) | (reg << 21) | (reg << 16) | a & 0xffff);
}
static void ppc64_gen_jump (MIR_context_t ctx, unsigned int reg, int call_p) {
static void ppc64_gen_jump (VARR (uint8_t) * insn_varr, unsigned int reg, int call_p) {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
assert (reg != 0);
ppc64_gen_ld (ctx, 0, reg, 0, MIR_T_I64); /* 0 = func addr */
ppc64_gen_ld (ctx, 2, reg, 8, MIR_T_I64); /* r2 = TOC */
push_insn (ctx, (31 << 26) | (467 << 1) | (0 << 21) | (9 << 16)); /* mctr 0 */
ppc64_gen_ld (insn_varr, 0, reg, 0, MIR_T_I64); /* 0 = func addr */
ppc64_gen_ld (insn_varr, 2, reg, 8, MIR_T_I64); /* r2 = TOC */
push_insn (insn_varr, (31 << 26) | (467 << 1) | (0 << 21) | (9 << 16)); /* mctr 0 */
#else
if (reg != 12) ppc64_gen_mov (ctx, 12, reg); /* 12 = func addr */
push_insn (ctx, (31 << 26) | (467 << 1) | (12 << 21) | (9 << 16)); /* mctr 12 */
if (reg != 12) ppc64_gen_mov (insn_varr, 12, reg); /* 12 = func addr */
push_insn (insn_varr, (31 << 26) | (467 << 1) | (12 << 21) | (9 << 16)); /* mctr 12 */
#endif
push_insn (ctx, (19 << 26) | (528 << 1) | (20 << 21) | (call_p ? 1 : 0)); /* bcctr[l] */
push_insn (insn_varr, (19 << 26) | (528 << 1) | (20 << 21) | (call_p ? 1 : 0)); /* bcctr[l] */
}
/* r11=addr_reg+addr_disp; r15=r1(sp)+sp_offset; r0=qwords-1;
ctr=r0; L: r0=mem[r11]; r11+=8; mem[r15]=r0; r15+=8; bdnz L; */
static void gen_blk_mov (MIR_context_t ctx, size_t sp_offset, unsigned int addr_reg, int addr_disp,
size_t qwords) {
static void gen_blk_mov (VARR (uint8_t) * insn_varr, size_t sp_offset, unsigned int addr_reg,
int addr_disp, size_t qwords) {
static const uint32_t blk_mov_loop[] = {
/*0:*/ 0x7c0903a6, /*mctr r0*/
/*4:*/ 0xe80b0000, /*ld r0,0(r11)*/
@ -135,15 +138,15 @@ static void gen_blk_mov (MIR_context_t ctx, size_t sp_offset, unsigned int addr_
/*20:*/ 0x4200fff0, /*bdnz 4*/
};
/* r11=addr_reg+addr_disp: */
if (addr_reg != 11 || addr_disp != 0) ppc64_gen_addi (ctx, 11, addr_reg, addr_disp);
if (addr_reg != 11 || addr_disp != 0) ppc64_gen_addi (insn_varr, 11, addr_reg, addr_disp);
if (sp_offset < 0x10000) {
ppc64_gen_addi (ctx, 15, 1, sp_offset);
ppc64_gen_addi (insn_varr, 15, 1, sp_offset);
} else {
ppc64_gen_address (ctx, 15, (void *) sp_offset);
ppc64_gen_add (ctx, 15, 15, 1);
ppc64_gen_address (insn_varr, 15, (void *) sp_offset);
ppc64_gen_add (insn_varr, 15, 15, 1);
}
ppc64_gen_address (ctx, 0, (void *) qwords); /*r0 = qwords*/
push_insns (ctx, blk_mov_loop, sizeof (blk_mov_loop));
ppc64_gen_address (insn_varr, 0, (void *) qwords); /*r0 = qwords*/
push_insns (insn_varr, blk_mov_loop, sizeof (blk_mov_loop));
}
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
@ -151,9 +154,11 @@ void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
0x7c230b78, /* mr 3,1 */
0x4e800020, /* blr */
};
ppc64_push_func_desc (ctx);
push_insns (ctx, bstart_code, sizeof (bstart_code));
return ppc64_publish_func_and_redirect (ctx);
VARR (uint8_t) * code;
ppc64_push_func_desc (&code);
push_insns (code, bstart_code, sizeof (bstart_code));
return ppc64_publish_func_and_redirect (ctx, code);
}
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
@ -161,26 +166,33 @@ void *_MIR_get_bend_builtin (MIR_context_t ctx) {
0x7c611b78, /* mr r1,r3 */
0x4e800020, /* blr */
};
ppc64_push_func_desc (ctx);
ppc64_gen_ld (ctx, 0, 1, 0, MIR_T_I64); /* r0 = 0(r1) */
ppc64_gen_st (ctx, 0, 3, 0, MIR_T_I64); /* 0(r3) = r0 */
ppc64_gen_ld (ctx, 0, 1, PPC64_TOC_OFFSET, MIR_T_I64); /* r0 = toc_offset(r1) */
ppc64_gen_st (ctx, 0, 3, PPC64_TOC_OFFSET, MIR_T_I64); /* toc_offset(r3) = r0 */
push_insns (ctx, bend_finish_code, sizeof (bend_finish_code));
return ppc64_publish_func_and_redirect (ctx);
VARR (uint8_t) * code;
ppc64_push_func_desc (&code);
ppc64_gen_ld (code, 0, 1, 0, MIR_T_I64); /* r0 = 0(r1) */
ppc64_gen_st (code, 0, 3, 0, MIR_T_I64); /* 0(r3) = r0 */
ppc64_gen_ld (code, 0, 1, PPC64_TOC_OFFSET, MIR_T_I64); /* r0 = toc_offset(r1) */
ppc64_gen_st (code, 0, 3, PPC64_TOC_OFFSET, MIR_T_I64); /* toc_offset(r3) = r0 */
push_insns (code, bend_finish_code, sizeof (bend_finish_code));
return ppc64_publish_func_and_redirect (ctx, code);
}
void *_MIR_get_thunk (MIR_context_t ctx) { /* emit 3 doublewords for func descriptor: */
ppc64_push_func_desc (ctx);
VARR (uint8_t) * code;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return ppc64_publish_func_and_redirect (ctx);
ppc64_push_func_desc (&code);
return ppc64_publish_func_and_redirect (ctx, code);
#else
const uint32_t nop_insn = 24 << (32 - 6); /* ori 0,0,0 */
const uint32_t nop_insn = 24 << (32 - 6); /* ori 0,0,0 */
const int max_thunk_len = (7 * 8);
VARR_TRUNC (uint8_t, machine_insns, 0);
for (int i = 0; i < max_thunk_len; i++) push_insn (ctx, nop_insn);
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
void *res;
VARR_CREATE (uint8_t, code, 128);
for (int i = 0; i < max_thunk_len; i++) push_insn (code, nop_insn);
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
#endif
}
@ -192,11 +204,13 @@ void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
0x7d8903a6, /* mtctr r12 */
0x4e800420, /* bctr */
};
VARR_TRUNC (uint8_t, machine_insns, 0);
ppc64_gen_address (ctx, 12, to);
push_insns (ctx, global_entry_end, sizeof (global_entry_end));
_MIR_change_code (ctx, thunk, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
VARR (uint8_t) * code;
VARR_CREATE (uint8_t, code, 256);
ppc64_gen_address (code, 12, to);
push_insns (code, global_entry_end, sizeof (global_entry_end));
_MIR_change_code (ctx, thunk, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
#endif
}
@ -259,8 +273,9 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
MIR_type_t type;
int n_gpregs = 0, n_fpregs = 0, res_reg = 14, qwords, frame_size;
int disp, blk_disp, param_offset, param_size = 0;
VARR (uint8_t) * code;
ppc64_push_func_desc (ctx);
ppc64_push_func_desc (&code);
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_descs[i].type) == MIR_T_BLK)
param_size += (arg_descs[i].size + 7) / 8 * 8;
@ -269,102 +284,104 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
if (param_size < 64) param_size = 64;
frame_size = PPC64_STACK_HEADER_SIZE + param_size + 16; /* +local var to save res_reg and 15 */
if (frame_size % 16 != 0) frame_size += 8; /* align */
ppc64_gen_st (ctx, 2, 1, PPC64_TOC_OFFSET, MIR_T_I64);
push_insns (ctx, start_pattern, sizeof (start_pattern));
ppc64_gen_stdu (ctx, -frame_size);
ppc64_gen_st (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
MIR_T_I64); /* save res_reg */
ppc64_gen_st (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* save 15 */
ppc64_gen_st (code, 2, 1, PPC64_TOC_OFFSET, MIR_T_I64);
push_insns (code, start_pattern, sizeof (start_pattern));
ppc64_gen_stdu (code, -frame_size);
ppc64_gen_st (code, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
MIR_T_I64); /* save res_reg */
ppc64_gen_st (code, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* save 15 */
mir_assert (sizeof (long double) == 16);
ppc64_gen_mov (ctx, res_reg, 4); /* results & args */
ppc64_gen_mov (ctx, 12, 3); /* func addr */
ppc64_gen_mov (code, res_reg, 4); /* results & args */
ppc64_gen_mov (code, 12, 3); /* func addr */
n_gpregs = n_fpregs = 0;
param_offset = nres * 16; /* args start */
disp = PPC64_STACK_HEADER_SIZE; /* param area start */
for (uint32_t i = 0; i < nargs; i++) { /* load args: */
type = arg_descs[i].type;
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 13) {
ppc64_gen_ld (ctx, 1 + n_fpregs, res_reg, param_offset, type);
ppc64_gen_ld (code, 1 + n_fpregs, res_reg, param_offset, type);
if (vararg_p) {
if (n_gpregs >= 8) {
ppc64_gen_st (ctx, 1 + n_fpregs, 1, disp, MIR_T_D);
ppc64_gen_st (code, 1 + n_fpregs, 1, disp, MIR_T_D);
} else { /* load into gp reg too */
ppc64_gen_st (ctx, 1 + n_fpregs, 1, -8, MIR_T_D);
ppc64_gen_ld (ctx, 3 + n_gpregs, 1, -8, MIR_T_I64);
ppc64_gen_st (code, 1 + n_fpregs, 1, -8, MIR_T_D);
ppc64_gen_ld (code, 3 + n_gpregs, 1, -8, MIR_T_I64);
}
}
n_fpregs++;
if (type == MIR_T_LD) {
if (n_fpregs < 13) {
ppc64_gen_ld (ctx, 1 + n_fpregs, res_reg, param_offset + 8, type);
ppc64_gen_ld (code, 1 + n_fpregs, res_reg, param_offset + 8, type);
if (vararg_p) {
if (n_gpregs + 1 >= 8) {
ppc64_gen_st (ctx, 1 + n_fpregs, 1, disp + 8, MIR_T_D);
ppc64_gen_st (code, 1 + n_fpregs, 1, disp + 8, MIR_T_D);
} else { /* load gp reg to */
ppc64_gen_st (ctx, 1 + n_fpregs, 1, -8, MIR_T_D);
ppc64_gen_ld (ctx, 4 + n_gpregs, 1, -8, MIR_T_I64);
ppc64_gen_st (code, 1 + n_fpregs, 1, -8, MIR_T_D);
ppc64_gen_ld (code, 4 + n_gpregs, 1, -8, MIR_T_I64);
}
}
n_fpregs++;
} else {
ppc64_gen_ld (ctx, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
ppc64_gen_ld (code, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
}
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
ppc64_gen_ld (ctx, 0, res_reg, param_offset, type);
ppc64_gen_st (ctx, 0, 1, disp, MIR_T_D);
ppc64_gen_ld (code, 0, res_reg, param_offset, type);
ppc64_gen_st (code, 0, 1, disp, MIR_T_D);
if (type == MIR_T_LD) {
ppc64_gen_ld (ctx, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
ppc64_gen_ld (code, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
if (qwords > 0) ppc64_gen_ld (ctx, 11, res_reg, param_offset, MIR_T_I64);
if (qwords > 0) ppc64_gen_ld (code, 11, res_reg, param_offset, MIR_T_I64);
for (blk_disp = 0; qwords > 0 && n_gpregs < 8; qwords--, n_gpregs++, blk_disp += 8, disp += 8)
ppc64_gen_ld (ctx, n_gpregs + 3, 11, blk_disp, MIR_T_I64);
if (qwords > 0) gen_blk_mov (ctx, disp, 11, blk_disp, qwords);
ppc64_gen_ld (code, n_gpregs + 3, 11, blk_disp, MIR_T_I64);
if (qwords > 0) gen_blk_mov (code, disp, 11, blk_disp, qwords);
disp += qwords * 8;
param_offset += 16;
continue;
} else if (n_gpregs < 8) { /* including RBLK */
ppc64_gen_ld (ctx, n_gpregs + 3, res_reg, param_offset, MIR_T_I64);
ppc64_gen_ld (code, n_gpregs + 3, res_reg, param_offset, MIR_T_I64);
} else {
ppc64_gen_ld (ctx, 0, res_reg, param_offset, MIR_T_I64);
ppc64_gen_st (ctx, 0, 1, disp, MIR_T_I64);
ppc64_gen_ld (code, 0, res_reg, param_offset, MIR_T_I64);
ppc64_gen_st (code, 0, 1, disp, MIR_T_I64);
}
disp += type == MIR_T_LD ? 16 : 8;
param_offset += 16;
n_gpregs += type == MIR_T_LD ? 2 : 1;
}
ppc64_gen_jump (ctx, 12, TRUE); /* call func_addr */
ppc64_gen_jump (code, 12, TRUE); /* call func_addr */
n_gpregs = n_fpregs = 0;
disp = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 8) {
ppc64_gen_st (ctx, n_fpregs + 1, res_reg, disp, type);
ppc64_gen_st (code, n_fpregs + 1, res_reg, disp, type);
n_fpregs++;
if (type == MIR_T_LD) {
if (n_fpregs >= 8)
(*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
ppc64_gen_st (ctx, n_fpregs + 1, res_reg, disp + 8, type);
MIR_get_error_func (ctx) (MIR_ret_error,
"ppc64 can not handle this combination of return values");
ppc64_gen_st (code, n_fpregs + 1, res_reg, disp + 8, type);
n_fpregs++;
}
} else if (n_gpregs < 2) { // just one-two gp reg
ppc64_gen_st (ctx, n_gpregs + 3, res_reg, disp, MIR_T_I64);
ppc64_gen_st (code, n_gpregs + 3, res_reg, disp, MIR_T_I64);
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"ppc64 can not handle this combination of return values");
}
disp += 16;
}
ppc64_gen_ld (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
ppc64_gen_ld (code, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
MIR_T_I64); /* restore res_reg */
ppc64_gen_ld (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* restore r15 */
ppc64_gen_addi (ctx, 1, 1, frame_size);
push_insns (ctx, finish_pattern, sizeof (finish_pattern));
return ppc64_publish_func_and_redirect (ctx);
ppc64_gen_ld (code, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* restore r15 */
ppc64_gen_addi (code, 1, 1, frame_size);
push_insns (code, finish_pattern, sizeof (finish_pattern));
return ppc64_publish_func_and_redirect (ctx, code);
}
/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
@ -390,16 +407,18 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
0x7c0803a6, /* mtlr r0 */
0x4e800020, /* blr */
};
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
VARR_CREATE (uint8_t, code, 256);
frame_size = PPC64_STACK_HEADER_SIZE + 64; /* header + 8(param area) */
local_var_size = nres * 16 + 16; /* saved r14, r15, results */
if (vararg_p) {
for (unsigned reg = 3; reg <= 10; reg++) /* std rn,dispn(r1) : */
ppc64_gen_st (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8, MIR_T_I64);
ppc64_gen_addi (ctx, va_reg, 1, PPC64_STACK_HEADER_SIZE);
ppc64_gen_st (code, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8, MIR_T_I64);
ppc64_gen_addi (code, va_reg, 1, PPC64_STACK_HEADER_SIZE);
} else {
ppc64_gen_mov (ctx, caller_r1, 1); /* caller frame r1 */
ppc64_gen_mov (code, caller_r1, 1); /* caller frame r1 */
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_vars[i].type) == MIR_T_BLK)
local_var_size += (arg_vars[i].size + 7) / 8 * 8;
@ -408,10 +427,10 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
}
frame_size += local_var_size;
if (frame_size % 16 != 0) frame_size += 8; /* align */
push_insns (ctx, start_pattern, sizeof (start_pattern));
ppc64_gen_stdu (ctx, -frame_size);
ppc64_gen_st (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* save res_reg */
ppc64_gen_st (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* save r15 */
push_insns (code, start_pattern, sizeof (start_pattern));
ppc64_gen_stdu (code, -frame_size);
ppc64_gen_st (code, res_reg, 1, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* save res_reg */
ppc64_gen_st (code, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* save r15 */
if (!vararg_p) { /* save args in local vars: */
/* header_size + 64 + nres * 16 + 16 -- start of stack memory to keep args: */
start_disp = disp = PPC64_STACK_HEADER_SIZE + 64 + nres * 16 + 16;
@ -420,80 +439,83 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
for (uint32_t i = 0; i < nargs; i++) {
type = arg_vars[i].type;
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 13) {
ppc64_gen_st (ctx, n_fpregs + 1, 1, disp, MIR_T_D);
ppc64_gen_st (code, n_fpregs + 1, 1, disp, MIR_T_D);
n_fpregs++;
if (type == MIR_T_LD) {
if (n_fpregs < 13) {
ppc64_gen_st (ctx, n_fpregs + 1, 1, disp + 8, MIR_T_D);
ppc64_gen_st (code, n_fpregs + 1, 1, disp + 8, MIR_T_D);
n_fpregs++;
} else {
ppc64_gen_ld (ctx, 0, caller_r1, param_offset + 8, MIR_T_D);
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
ppc64_gen_ld (code, 0, caller_r1, param_offset + 8, MIR_T_D);
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
}
} else if (type == MIR_T_BLK) {
qwords = (arg_vars[i].size + 7) / 8;
for (; qwords > 0 && n_gpregs < 8; qwords--, n_gpregs++, disp += 8, param_offset += 8)
ppc64_gen_st (ctx, n_gpregs + 3, 1, disp, MIR_T_I64);
ppc64_gen_st (code, n_gpregs + 3, 1, disp, MIR_T_I64);
if (qwords > 0) {
gen_blk_mov (ctx, disp, caller_r1, param_offset, qwords);
gen_blk_mov (code, disp, caller_r1, param_offset, qwords);
disp += qwords * 8;
param_offset += qwords * 8;
}
continue;
} else if (n_gpregs < 8) {
ppc64_gen_st (ctx, n_gpregs + 3, 1, disp, MIR_T_I64);
ppc64_gen_st (code, n_gpregs + 3, 1, disp, MIR_T_I64);
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
ppc64_gen_ld (ctx, 0, caller_r1, param_offset + (type == MIR_T_F ? 4 : 0), type);
ppc64_gen_st (ctx, 0, 1, disp, MIR_T_D);
ppc64_gen_ld (code, 0, caller_r1, param_offset + (type == MIR_T_F ? 4 : 0), type);
ppc64_gen_st (code, 0, 1, disp, MIR_T_D);
if (type == MIR_T_LD) {
ppc64_gen_ld (ctx, 0, caller_r1, param_offset + 8, MIR_T_D);
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
ppc64_gen_ld (code, 0, caller_r1, param_offset + 8, MIR_T_D);
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
} else {
ppc64_gen_ld (ctx, 0, caller_r1, param_offset, MIR_T_I64);
ppc64_gen_st (ctx, 0, 1, disp, MIR_T_I64);
ppc64_gen_ld (code, 0, caller_r1, param_offset, MIR_T_I64);
ppc64_gen_st (code, 0, 1, disp, MIR_T_I64);
}
size = type == MIR_T_LD ? 16 : 8;
disp += size;
param_offset += size;
n_gpregs += type == MIR_T_LD ? 2 : 1;
}
ppc64_gen_addi (ctx, va_reg, 1, start_disp);
ppc64_gen_addi (code, va_reg, 1, start_disp);
}
ppc64_gen_addi (ctx, res_reg, 1, 64 + PPC64_STACK_HEADER_SIZE + 16);
ppc64_gen_address (ctx, 3, ctx);
ppc64_gen_address (ctx, 4, func_item);
ppc64_gen_mov (ctx, 5, va_reg);
ppc64_gen_mov (ctx, 6, res_reg);
ppc64_gen_address (ctx, 12, handler);
ppc64_gen_jump (ctx, 12, TRUE);
ppc64_gen_addi (code, res_reg, 1, 64 + PPC64_STACK_HEADER_SIZE + 16);
ppc64_gen_address (code, 3, ctx);
ppc64_gen_address (code, 4, func_item);
ppc64_gen_mov (code, 5, va_reg);
ppc64_gen_mov (code, 6, res_reg);
ppc64_gen_address (code, 12, handler);
ppc64_gen_jump (code, 12, TRUE);
disp = n_gpregs = n_fpregs = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 8) {
ppc64_gen_ld (ctx, n_fpregs + 1, res_reg, disp, type);
ppc64_gen_ld (code, n_fpregs + 1, res_reg, disp, type);
n_fpregs++;
if (type == MIR_T_LD) {
if (n_fpregs >= 8)
(*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
ppc64_gen_ld (ctx, n_fpregs + 1, res_reg, disp + 8, type);
MIR_get_error_func (ctx) (MIR_ret_error,
"ppc64 can not handle this combination of return values");
ppc64_gen_ld (code, n_fpregs + 1, res_reg, disp + 8, type);
n_fpregs++;
}
} else if (n_gpregs < 2) { // just one-two gp reg
ppc64_gen_ld (ctx, n_gpregs + 3, res_reg, disp, MIR_T_I64);
ppc64_gen_ld (code, n_gpregs + 3, res_reg, disp, MIR_T_I64);
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"ppc64 can not handle this combination of return values");
}
disp += 16;
}
ppc64_gen_ld (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* restore res_reg */
ppc64_gen_ld (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* restore r15 */
ppc64_gen_addi (ctx, 1, 1, frame_size);
push_insns (ctx, finish_pattern, sizeof (finish_pattern));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
ppc64_gen_ld (code, res_reg, 1, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* restore res_reg */
ppc64_gen_ld (code, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* restore r15 */
ppc64_gen_addi (code, 1, 1, frame_size);
push_insns (code, finish_pattern, sizeof (finish_pattern));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Brief: save lr (r1+16); update r1, save all param regs (r1+header+64);
@ -510,29 +532,32 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
0x7c0803a6, /* mtlr r0 */
};
int frame_size = PPC64_STACK_HEADER_SIZE + 8 * 8 + 13 * 8 + 8 * 8;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prologue, sizeof (prologue));
VARR_CREATE (uint8_t, code, 256);
push_insns (code, prologue, sizeof (prologue));
/* stdu r1,n(r1): header + 8(gp args) + 13(fp args) + 8(param area): */
if (frame_size % 16 != 0) frame_size += 8;
ppc64_gen_stdu (ctx, -frame_size);
ppc64_gen_stdu (code, -frame_size);
for (unsigned reg = 3; reg <= 10; reg++) /* std rn,dispn(r1) : */
ppc64_gen_st (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8 + 64, MIR_T_I64);
ppc64_gen_st (code, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8 + 64, MIR_T_I64);
for (unsigned reg = 1; reg <= 13; reg++) /* stfd fn,dispn(r1) : */
ppc64_gen_st (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 1 + 8) * 8 + 64, MIR_T_D);
ppc64_gen_address (ctx, 3, ctx);
ppc64_gen_address (ctx, 4, called_func);
ppc64_gen_address (ctx, 12, hook_address);
ppc64_gen_jump (ctx, 12, TRUE);
ppc64_gen_mov (ctx, 12, 3);
ppc64_gen_st (code, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 1 + 8) * 8 + 64, MIR_T_D);
ppc64_gen_address (code, 3, ctx);
ppc64_gen_address (code, 4, called_func);
ppc64_gen_address (code, 12, hook_address);
ppc64_gen_jump (code, 12, TRUE);
ppc64_gen_mov (code, 12, 3);
for (unsigned reg = 3; reg <= 10; reg++) /* ld rn,dispn(r1) : */
ppc64_gen_ld (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8 + 64, MIR_T_I64);
ppc64_gen_ld (code, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8 + 64, MIR_T_I64);
for (unsigned reg = 1; reg <= 13; reg++) /* lfd fn,dispn(r1) : */
ppc64_gen_ld (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 1 + 8) * 8 + 64, MIR_T_D);
ppc64_gen_addi (ctx, 1, 1, frame_size);
push_insns (ctx, epilogue, sizeof (epilogue));
push_insn (ctx, (31 << 26) | (467 << 1) | (12 << 21) | (9 << 16)); /* mctr 12 */
push_insn (ctx, (19 << 26) | (528 << 1) | (20 << 21)); /* bcctr */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
ppc64_gen_ld (code, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 1 + 8) * 8 + 64, MIR_T_D);
ppc64_gen_addi (code, 1, 1, frame_size);
push_insns (code, epilogue, sizeof (epilogue));
push_insn (code, (31 << 26) | (467 << 1) | (12 << 21) | (9 << 16)); /* mctr 12 */
push_insn (code, (19 << 26) | (528 << 1) | (20 << 21)); /* bcctr */
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}

@ -14,25 +14,25 @@
#define S390X_STACK_HEADER_SIZE 160
static uint8_t *push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
static uint8_t *push_insns (VARR (uint8_t) * insn_varr, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, insn_varr, pat[i]);
return VARR_ADDR (uint8_t, insn_varr) + VARR_LENGTH (uint8_t, insn_varr) - pat_len;
}
static void s390x_gen_mov (MIR_context_t ctx, unsigned to, unsigned from) {
static void s390x_gen_mov (VARR (uint8_t) * insn_varr, unsigned to, unsigned from) {
uint32_t lgr = (0xb904 << 16) | (to << 4) | from; /* lgr to,from: */
assert (to < 16 && from < 16);
push_insns (ctx, (uint8_t *) &lgr, 4);
push_insns (insn_varr, (uint8_t *) &lgr, 4);
}
static void s390x_gen_mvi (MIR_context_t ctx, int val, unsigned base, int disp) {
static void s390x_gen_mvi (VARR (uint8_t) * insn_varr, int val, unsigned base, int disp) {
uint64_t mvghi /* mvghi disp(base), val: */
= ((0xe548l << 32) | ((uint64_t) base << 28) | ((disp & 0xfff) << 16) | (val & 0xffff)) << 16;
assert (base < 16 && 0 <= disp && disp < (1 << 12) && -(1 << 15) < val && val < (1 << 15));
push_insns (ctx, (uint8_t *) &mvghi, 6);
push_insns (insn_varr, (uint8_t *) &mvghi, 6);
}
static void s390x_gen_ld_st (MIR_context_t ctx, unsigned reg, unsigned base, int disp,
static void s390x_gen_ld_st (VARR (uint8_t) * insn_varr, unsigned reg, unsigned base, int disp,
MIR_type_t type, int ld_p) {
int single_p = type == MIR_T_F;
int double_p = type == MIR_T_D;
@ -54,66 +54,66 @@ static void s390x_gen_ld_st (MIR_context_t ctx, unsigned reg, unsigned base, int
uint64_t dy = ((0xedl << 40) | common | (ld_p ? 0x65 : 0x67)) << 16;
/* (lg|lgf|llgf|lgb|llgc|lhy|llgh|ley|ldy|stg|sty|sthy|stcy|stey|stdy) reg, disp(base): */
assert (type != MIR_T_LD && reg < 16 && base < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) (single_p ? &ey : double_p ? &dy : &g), 6);
push_insns (insn_varr, (uint8_t *) (single_p ? &ey : double_p ? &dy : &g), 6);
}
static void s390x_gen_ld (MIR_context_t ctx, unsigned to, unsigned base, int disp,
static void s390x_gen_ld (VARR (uint8_t) * insn_varr, unsigned to, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (ctx, to, base, disp, type, TRUE);
s390x_gen_ld_st (insn_varr, to, base, disp, type, TRUE);
}
static void s390x_gen_st (MIR_context_t ctx, unsigned from, unsigned base, int disp,
static void s390x_gen_st (VARR (uint8_t) * insn_varr, unsigned from, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (ctx, from, base, disp, type, FALSE);
s390x_gen_ld_st (insn_varr, from, base, disp, type, FALSE);
}
static void s390x_gen_ldstm (MIR_context_t ctx, unsigned from, unsigned to, unsigned base, int disp,
int ld_p) {
static void s390x_gen_ldstm (VARR (uint8_t) * insn_varr, unsigned from, unsigned to, unsigned base,
int disp, int ld_p) {
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t common = ((uint64_t) from << 36) | ((uint64_t) to << 32) | ((uint64_t) base << 28)
| (dl << 16) | (dh << 8);
uint64_t g = ((0xebl << 40) | common | (ld_p ? 0x4 : 0x24)) << 16;
/* (lmg|stmg) from,to,disp(base): */
assert (from < 16 && to < 16 && base < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) &g, 6);
push_insns (insn_varr, (uint8_t *) &g, 6);
}
static void s390x_gen_jump (MIR_context_t ctx, unsigned int reg, int call_p) {
static void s390x_gen_jump (VARR (uint8_t) * insn_varr, unsigned int reg, int call_p) {
uint16_t bcr = (0x7 << 8) | (15 << 4) | reg; /* bcr 15,reg: */
uint16_t balr = (0x5 << 8) | (14 << 4) | reg; /* balr 14,reg: */
assert (reg < 16);
push_insns (ctx, (uint8_t *) (call_p ? &balr : &bcr), 2);
push_insns (insn_varr, (uint8_t *) (call_p ? &balr : &bcr), 2);
}
static void s390x_gen_addi (MIR_context_t ctx, unsigned dst, unsigned src, int disp) {
static void s390x_gen_addi (VARR (uint8_t) * insn_varr, unsigned dst, unsigned src, int disp) {
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t ops = ((uint64_t) dst << 36) | ((uint64_t) src << 28) | (dl << 16) | (dh << 8);
uint64_t lay = ((0xe3l << 40) | ops | 0x71) << 16; /* lay dst,disp(src) */
assert (dst < 16 && src < 16 && -(1 << 19) < disp && disp < (1 << 19));
push_insns (ctx, (uint8_t *) &lay, 6);
push_insns (insn_varr, (uint8_t *) &lay, 6);
}
static void s390x_gen_3addrs (MIR_context_t ctx, unsigned int r1, void *a1, unsigned int r2,
void *a2, unsigned int r3, void *a3) {
static void s390x_gen_3addrs (VARR (uint8_t) * insn_varr, unsigned int r1, void *a1,
unsigned int r2, void *a2, unsigned int r3, void *a3) {
/* 6b:lalr r3,22+align;6b:lg r1,0(r3);6b:lg r2,8(r3);6b:lg r3,16(r3);4b:bc m15,28;align;a1-a3 */
size_t rem = (VARR_LENGTH (uint8_t, machine_insns) + 28) % 8;
size_t rem = (VARR_LENGTH (uint8_t, insn_varr) + 28) % 8;
size_t padding = rem == 0 ? 0 : 8 - rem;
uint64_t lalr = ((0xc0l << 40) | ((uint64_t) r1 << 36) | (28 + padding) / 2) << 16;
uint32_t brc = (0xa7 << 24) | (15 << 20) | (4 << 16) | (28 + padding) / 2; /* brc m15,28: */
assert (r1 != 0);
push_insns (ctx, (uint8_t *) &lalr, 6);
s390x_gen_ld (ctx, r3, r1, 16, MIR_T_I64); /* lg r3,16(r1) */
s390x_gen_ld (ctx, r2, r1, 8, MIR_T_I64); /* lg r2,8(r1) */
s390x_gen_ld (ctx, r1, r1, 0, MIR_T_I64); /* lg r1,0(r1) */
push_insns (ctx, (uint8_t *) &brc, 4);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, machine_insns, 0);
push_insns (ctx, (uint8_t *) &a1, 8);
push_insns (ctx, (uint8_t *) &a2, 8);
push_insns (ctx, (uint8_t *) &a3, 8);
push_insns (insn_varr, (uint8_t *) &lalr, 6);
s390x_gen_ld (insn_varr, r3, r1, 16, MIR_T_I64); /* lg r3,16(r1) */
s390x_gen_ld (insn_varr, r2, r1, 8, MIR_T_I64); /* lg r2,8(r1) */
s390x_gen_ld (insn_varr, r1, r1, 0, MIR_T_I64); /* lg r1,0(r1) */
push_insns (insn_varr, (uint8_t *) &brc, 4);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, insn_varr, 0);
push_insns (insn_varr, (uint8_t *) &a1, 8);
push_insns (insn_varr, (uint8_t *) &a2, 8);
push_insns (insn_varr, (uint8_t *) &a3, 8);
}
static void s390x_gen_blk_mov (MIR_context_t ctx, uint32_t param_offset, uint32_t addr_offset,
uint32_t qwords, uint32_t addr_reg) {
static void s390x_gen_blk_mov (VARR (uint8_t) * insn_varr, uint32_t param_offset,
uint32_t addr_offset, uint32_t qwords, uint32_t addr_reg) {
uint16_t *addr;
static const uint16_t blk_mov_pat[] = {
/*0:*/ 0xa7a9, 0x0000, /* lghi %r10,<size> */
@ -123,63 +123,77 @@ static void s390x_gen_blk_mov (MIR_context_t ctx, uint32_t param_offset, uint32_
/*20:*/ 0xb902, 0x00aa, /* ltgr %r10,%r10 */
/*24:*/ 0xa724, 0xfff6, /* jh 4 */
};
s390x_gen_addi (ctx, addr_reg, 15, addr_offset); /* lay <addr_reg>,addr_offset(r15) */
s390x_gen_addi (insn_varr, addr_reg, 15, addr_offset); /* lay <addr_reg>,addr_offset(r15) */
if (qwords == 0) return;
assert (qwords * 8 < (1 << 15) && addr_reg < 16 && addr_offset % 8 == 0);
s390x_gen_ld (ctx, 9, 7, param_offset, MIR_T_I64); /* lg* 9,param_offset(r7) */
addr = (uint16_t *) push_insns (ctx, (uint8_t *) blk_mov_pat, sizeof (blk_mov_pat));
s390x_gen_ld (insn_varr, 9, 7, param_offset, MIR_T_I64); /* lg* 9,param_offset(r7) */
addr = (uint16_t *) push_insns (insn_varr, (uint8_t *) blk_mov_pat, sizeof (blk_mov_pat));
addr[1] |= qwords * 8; /* lghi */
addr[8] |= addr_reg << 12; /* stg */
}
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_mov (ctx, 2, 15); /* lgr r2,15 */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
s390x_gen_mov (code, 2, 15); /* lgr r2,15 */
s390x_gen_jump (code, 14, FALSE); /* bcr m15,r14 */
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_ld (ctx, 0, 15, 0, MIR_T_I64); /* r0 = 0(r15) */
s390x_gen_st (ctx, 0, 2, 0, MIR_T_I64); /* 0(r2) = r0 */
s390x_gen_mov (ctx, 15, 2); /* lgr r15,2 */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
s390x_gen_ld (code, 0, 15, 0, MIR_T_I64); /* r0 = 0(r15) */
s390x_gen_st (code, 0, 2, 0, MIR_T_I64); /* 0(r2) = r0 */
s390x_gen_mov (code, 15, 2); /* lgr r15,2 */
s390x_gen_jump (code, 14, FALSE); /* bcr m15,r14 */
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
void *_MIR_get_thunk (MIR_context_t ctx) {
const int max_thunk_len = (4 * 8); /* see _MIR_redirect_thunk */
VARR_TRUNC (uint8_t, machine_insns, 0);
for (int i = 0; i < max_thunk_len; i++) VARR_PUSH (uint8_t, machine_insns, 0);
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
for (int i = 0; i < max_thunk_len; i++) VARR_PUSH (uint8_t, code, 0);
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
int64_t offset = (uint8_t *) to - (uint8_t *) thunk;
VARR_TRUNC (uint8_t, machine_insns, 0);
VARR (uint8_t) * code;
VARR_CREATE (uint8_t, code, 128);
assert (offset % 2 == 0);
offset /= 2;
if (-(1l << 31) < offset && offset < (1l << 31)) { /* brcl m15,offset: */
uint64_t brcl = ((0xc0l << 40) | (15l << 36) | (4l << 32) | offset & 0xffffffff) << 16;
push_insns (ctx, (uint8_t *) &brcl, 6);
push_insns (code, (uint8_t *) &brcl, 6);
} else { /* 6b:lalr r1,8+padding; 6b:lg r1,0(r1); 2b:bcr m15,r1;padding; 64-bit address: */
size_t rem = (VARR_LENGTH (uint8_t, machine_insns) + 14) % 8;
size_t rem = (VARR_LENGTH (uint8_t, code) + 14) % 8;
size_t padding = rem == 0 ? 0 : 8 - rem;
uint64_t lalr = ((0xc0l << 40) | (1l << 36) | (14 + padding) / 2) << 16;
uint64_t lg = ((0xe3l << 40) | (1l << 36) | (1l << 28) | 0x4) << 16;
uint16_t bcr = (0x7 << 8) | (15 << 4) | 1; /* bcr 15,r1: */
push_insns (ctx, (uint8_t *) &lalr, 6);
push_insns (ctx, (uint8_t *) &lg, 6);
push_insns (ctx, (uint8_t *) &bcr, 2);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, machine_insns, 0);
push_insns (ctx, (uint8_t *) &to, 8);
push_insns (code, (uint8_t *) &lalr, 6);
push_insns (code, (uint8_t *) &lg, 6);
push_insns (code, (uint8_t *) &bcr, 2);
for (size_t i = 0; i < padding; i++) VARR_PUSH (uint8_t, code, 0);
push_insns (code, (uint8_t *) &to, 8);
}
_MIR_change_code (ctx, thunk, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
_MIR_change_code (ctx, thunk, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
}
struct s390x_va_list {
@ -242,8 +256,10 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
MIR_type_t type;
int n_gpregs = 0, n_fpregs = 0, res_reg = 7, frame_size, disp, param_offset, blk_offset;
uint32_t qwords, addr_reg;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
VARR_CREATE (uint8_t, code, 128);
blk_offset = frame_size = S390X_STACK_HEADER_SIZE;
if (nres > 0 && res_types[0] == MIR_T_LD) n_gpregs++; /* ld address */
for (uint32_t i = 0; i < nargs; i++) { /* calculate param area size: */
@ -258,84 +274,86 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
blk_offset += 8;
}
}
s390x_gen_ldstm (ctx, 6, 7, 15, 48, FALSE); /* stmg 6,7,48(r15) : */
s390x_gen_ldstm (ctx, 8, 9, 15, 64, FALSE); /* stmg 8,9,64(r15) : */
s390x_gen_st (ctx, 10, 15, 80, MIR_T_I64); /* stg r10,80(r15) */
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg r14,112(r15) */
s390x_gen_addi (ctx, 15, 15, -frame_size); /* lay r15,-frame_size(r15) */
s390x_gen_mov (ctx, 1, 2); /* fun_addr */
s390x_gen_mov (ctx, res_reg, 3); /* results & args */
s390x_gen_ldstm (code, 6, 7, 15, 48, FALSE); /* stmg 6,7,48(r15) : */
s390x_gen_ldstm (code, 8, 9, 15, 64, FALSE); /* stmg 8,9,64(r15) : */
s390x_gen_st (code, 10, 15, 80, MIR_T_I64); /* stg r10,80(r15) */
s390x_gen_st (code, 14, 15, 112, MIR_T_I64); /* stg r14,112(r15) */
s390x_gen_addi (code, 15, 15, -frame_size); /* lay r15,-frame_size(r15) */
s390x_gen_mov (code, 1, 2); /* fun_addr */
s390x_gen_mov (code, res_reg, 3); /* results & args */
n_gpregs = n_fpregs = 0;
param_offset = nres * 16; /* args start */
disp = S390X_STACK_HEADER_SIZE; /* param area start */
if (nres > 0 && res_types[0] == MIR_T_LD) { /* ld address: */
s390x_gen_mov (ctx, 2, res_reg); /* lgr r2,r7 */
s390x_gen_mov (code, 2, res_reg); /* lgr r2,r7 */
n_gpregs++;
}
for (uint32_t i = 0; i < nargs; i++) { /* load args: */
type = arg_descs[i].type;
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
/* (le,ld) (f0,f2,f4,f6),param_ofset(r7) */
s390x_gen_ld (ctx, n_fpregs * 2, res_reg, param_offset, type);
s390x_gen_ld (code, n_fpregs * 2, res_reg, param_offset, type);
n_fpregs++;
} else if (type == MIR_T_F || type == MIR_T_D) {
s390x_gen_ld (ctx, 1, res_reg, param_offset, type); /* (le,ld) f1,param_offset(r7) */
s390x_gen_st (ctx, 1, 15, disp, type); /* (ste,std) f1,disp(r15) */
s390x_gen_ld (code, 1, res_reg, param_offset, type); /* (le,ld) f1,param_offset(r7) */
s390x_gen_st (code, 1, 15, disp, type); /* (ste,std) f1,disp(r15) */
disp += 8;
} else if (type == MIR_T_LD && n_gpregs < 5) { /* ld address */
s390x_gen_addi (ctx, n_gpregs + 2, res_reg, param_offset); /* lay rn,param_offset(r7) */
} else if (type == MIR_T_LD && n_gpregs < 5) { /* ld address */
s390x_gen_addi (code, n_gpregs + 2, res_reg, param_offset); /* lay rn,param_offset(r7) */
n_gpregs++;
} else if (type == MIR_T_LD) { /* pass address of location in the result: */
s390x_gen_addi (ctx, 0, res_reg, param_offset); /* lay r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg r0,disp(r15) */
} else if (type == MIR_T_LD) { /* pass address of location in the result: */
s390x_gen_addi (code, 0, res_reg, param_offset); /* lay r0,param_offset(r7) */
s390x_gen_st (code, 0, 15, disp, MIR_T_I64); /* stg r0,disp(r15) */
disp += 8;
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
addr_reg = n_gpregs < 5 ? n_gpregs + 2 : 8;
s390x_gen_blk_mov (ctx, param_offset, blk_offset, qwords, addr_reg);
s390x_gen_blk_mov (code, param_offset, blk_offset, qwords, addr_reg);
blk_offset += qwords * 8;
if (n_gpregs < 5) {
n_gpregs++;
} else {
s390x_gen_st (ctx, 8, 15, disp, MIR_T_I64); /* stg r8,disp(r15) */
s390x_gen_st (code, 8, 15, disp, MIR_T_I64); /* stg r8,disp(r15) */
disp += 8;
}
} else if (n_gpregs < 5) { /* RBLK too */
s390x_gen_ld (ctx, n_gpregs + 2, res_reg, param_offset,
s390x_gen_ld (code, n_gpregs + 2, res_reg, param_offset,
MIR_T_I64); /* lg* rn,param_offset(r7) */
n_gpregs++;
} else {
s390x_gen_ld (ctx, 0, res_reg, param_offset, MIR_T_I64); /* lg* r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg* r0,disp(r15) */
s390x_gen_ld (code, 0, res_reg, param_offset, MIR_T_I64); /* lg* r0,param_offset(r7) */
s390x_gen_st (code, 0, 15, disp, MIR_T_I64); /* stg* r0,disp(r15) */
disp += 8;
}
param_offset += 16;
}
s390x_gen_jump (ctx, 1, TRUE); /* call *r1 */
s390x_gen_jump (code, 1, TRUE); /* call *r1 */
n_gpregs = n_fpregs = 0;
disp = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if (type == MIR_T_LD) continue; /* do nothing: the result value is already in results */
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
s390x_gen_st (ctx, n_fpregs * 2, res_reg, disp, type);
s390x_gen_st (code, n_fpregs * 2, res_reg, disp, type);
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 1) { // just one gp reg
s390x_gen_st (ctx, n_gpregs + 2, res_reg, disp, MIR_T_I64);
s390x_gen_st (code, n_gpregs + 2, res_reg, disp, MIR_T_I64);
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "s390x can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"s390x can not handle this combination of return values");
}
disp += 16;
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ldstm (ctx, 6, 7, 15, 48, TRUE); /* lmg 6,7,48(r15) : */
s390x_gen_ldstm (ctx, 8, 9, 15, 64, TRUE); /* lmg 8,9,64(r15) : */
s390x_gen_ld (ctx, 10, 15, 80, MIR_T_I64); /* lg 10,80(r15) */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
s390x_gen_addi (code, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ldstm (code, 6, 7, 15, 48, TRUE); /* lmg 6,7,48(r15) : */
s390x_gen_ldstm (code, 8, 9, 15, 64, TRUE); /* lmg 8,9,64(r15) : */
s390x_gen_ld (code, 10, 15, 80, MIR_T_I64); /* lg 10,80(r15) */
s390x_gen_ld (code, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (code, 14, FALSE); /* bcr m15,r14 */
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
@ -348,63 +366,67 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
uint32_t nres = func->nres, nargs = func->nargs;
MIR_type_t type, *res_types = func->res_types;
int disp, frame_size, local_var_size, n_gpregs, n_fpregs, va_list_disp, results_disp;
VARR_TRUNC (uint8_t, machine_insns, 0);
frame_size = S390X_STACK_HEADER_SIZE; /* register save area */
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (ctx, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
frame_size = S390X_STACK_HEADER_SIZE; /* register save area */
s390x_gen_st (code, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (code, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (code, reg, 15, reg * 4 + 128, MIR_T_D);
local_var_size = sizeof (struct s390x_va_list) + nres * 16; /* allocate va and results */
va_list_disp = frame_size;
results_disp = va_list_disp + sizeof (struct s390x_va_list);
frame_size += local_var_size;
assert (frame_size % 8 == 0);
s390x_gen_addi (ctx, 15, 15, -frame_size);
s390x_gen_addi (code, 15, 15, -frame_size);
/* setup va: mvghi va(15),(0,1): __gpr */
s390x_gen_mvi (ctx, nres > 0 && res_types[0] == MIR_T_LD ? 1 : 0, 15, va_list_disp);
s390x_gen_mvi (ctx, 0, 15, va_list_disp + 8); /* mvghi va+8(15),0: __fpr */
s390x_gen_addi (ctx, 1, 15, frame_size); /* lay 1,frame_size(15) */
s390x_gen_st (ctx, 1, 15, va_list_disp + 24, MIR_T_I64); /* stg 1,va+24(r15): __reg_save_area */
s390x_gen_addi (ctx, 1, 1, S390X_STACK_HEADER_SIZE); /* lay 1,S390X_STACK_HEADER_SIZE(1) */
s390x_gen_mvi (code, nres > 0 && res_types[0] == MIR_T_LD ? 1 : 0, 15, va_list_disp);
s390x_gen_mvi (code, 0, 15, va_list_disp + 8); /* mvghi va+8(15),0: __fpr */
s390x_gen_addi (code, 1, 15, frame_size); /* lay 1,frame_size(15) */
s390x_gen_st (code, 1, 15, va_list_disp + 24, MIR_T_I64); /* stg 1,va+24(r15): __reg_save_area */
s390x_gen_addi (code, 1, 1, S390X_STACK_HEADER_SIZE); /* lay 1,S390X_STACK_HEADER_SIZE(1) */
/* stg 1,va+16(r15):__overflow_arg_area: */
s390x_gen_st (ctx, 1, 15, va_list_disp + 16, MIR_T_I64);
s390x_gen_st (code, 1, 15, va_list_disp + 16, MIR_T_I64);
/* call handler: */
s390x_gen_3addrs (ctx, 2, ctx, 3, func_item, 1, handler);
s390x_gen_addi (ctx, 4, 15, va_list_disp);
s390x_gen_addi (ctx, 5, 15, results_disp);
s390x_gen_jump (ctx, 1, TRUE);
s390x_gen_3addrs (code, 2, ctx, 3, func_item, 1, handler);
s390x_gen_addi (code, 4, 15, va_list_disp);
s390x_gen_addi (code, 5, 15, results_disp);
s390x_gen_jump (code, 1, TRUE);
/* setup result regs: */
disp = results_disp;
n_gpregs = n_fpregs = 0;
for (uint32_t i = 0; i < nres; i++) {
type = res_types[i];
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
s390x_gen_ld (ctx, n_fpregs * 2, 15, disp, type);
s390x_gen_ld (code, n_fpregs * 2, 15, disp, type);
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 1) { // just one gp reg
if (type != MIR_T_LD) {
s390x_gen_ld (ctx, n_gpregs + 2, 15, disp, MIR_T_I64);
s390x_gen_ld (code, n_gpregs + 2, 15, disp, MIR_T_I64);
} else {
/* ld address: lg r2,16+frame_size(r15) */
s390x_gen_ld (ctx, 2, 15, 16 + frame_size, MIR_T_I64);
s390x_gen_ld (ctx, 0, 15, disp, MIR_T_D); /* ld f0,disp(r15) */
s390x_gen_ld (ctx, 2, 15, disp + 8, MIR_T_D); /* ld f2,disp + 8(r15) */
s390x_gen_st (ctx, 0, 2, 0, MIR_T_D); /* st f0,0(r2) */
s390x_gen_st (ctx, 2, 2, 8, MIR_T_D); /* st f2,8(r2) */
s390x_gen_ld (code, 2, 15, 16 + frame_size, MIR_T_I64);
s390x_gen_ld (code, 0, 15, disp, MIR_T_D); /* ld f0,disp(r15) */
s390x_gen_ld (code, 2, 15, disp + 8, MIR_T_D); /* ld f2,disp + 8(r15) */
s390x_gen_st (code, 0, 2, 0, MIR_T_D); /* st f0,0(r2) */
s390x_gen_st (code, 2, 2, 8, MIR_T_D); /* st f2,8(r2) */
}
n_gpregs++;
} else {
(*error_func) (MIR_ret_error, "s390x can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"s390x can not handle this combination of return values");
}
disp += 16;
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ld (ctx, 6, 15, 48, MIR_T_I64); /* lg 6,48(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
s390x_gen_addi (code, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ld (code, 6, 15, 48, MIR_T_I64); /* lg 6,48(r15) : */
s390x_gen_ld (code, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (code, 14, FALSE); /* bcr m15,r14 */
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Brief: save r14 (r15+120); save all param regs r2-r6 (r15+16),f0,f2,f4,f6 (r15+128);
@ -412,23 +434,26 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
r2 = call hook_address (ctx, called_func); r1=r2; restore all params regs, r15, r14; bcr r1 */
void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
int frame_size = S390X_STACK_HEADER_SIZE;
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (ctx, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
VARR (uint8_t) * code;
void *res;
VARR_CREATE (uint8_t, code, 128);
s390x_gen_st (code, 14, 15, 112, MIR_T_I64); /* stg 14,112(r15) */
s390x_gen_ldstm (code, 2, 6, 15, 16, FALSE); /* stmg 2,6,16(r15) : */
for (unsigned reg = 0; reg <= 6; reg += 2) /* stdy f0,f2,f4,f6,128(r15) : */
s390x_gen_st (code, reg, 15, reg * 4 + 128, MIR_T_D);
/* r15 -= frame_size: */
s390x_gen_addi (ctx, 15, 15, -frame_size);
s390x_gen_3addrs (ctx, 2, ctx, 3, called_func, 4, hook_address);
s390x_gen_jump (ctx, 4, TRUE);
s390x_gen_mov (ctx, 1, 2);
s390x_gen_addi (ctx, 15, 15, frame_size);
s390x_gen_addi (code, 15, 15, -frame_size);
s390x_gen_3addrs (code, 2, ctx, 3, called_func, 4, hook_address);
s390x_gen_jump (code, 4, TRUE);
s390x_gen_mov (code, 1, 2);
s390x_gen_addi (code, 15, 15, frame_size);
for (unsigned reg = 0; reg <= 6; reg += 2) /* ldy fn,disp(r15) : */
s390x_gen_ld (ctx, reg, 15, reg * 4 + 128, MIR_T_D);
s390x_gen_ldstm (ctx, 2, 6, 15, 16, TRUE); /* lmg 2,6,16(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 1, FALSE);
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
s390x_gen_ld (code, reg, 15, reg * 4 + 128, MIR_T_D);
s390x_gen_ldstm (code, 2, 6, 15, 16, TRUE); /* lmg 2,6,16(r15) : */
s390x_gen_ld (code, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (code, 1, FALSE);
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}

@ -167,15 +167,15 @@ static const uint8_t restore_pat[] = {
#endif
};
static uint8_t *push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
static uint8_t *push_insns (VARR (uint8_t) * insn_varr, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, insn_varr, pat[i]);
return VARR_ADDR (uint8_t, insn_varr) + VARR_LENGTH (uint8_t, insn_varr) - pat_len;
}
static void gen_mov (MIR_context_t ctx, uint32_t offset, uint32_t reg, int ld_p) {
static void gen_mov (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t reg, int ld_p) {
static const uint8_t ld_gp_reg[] = {0x48, 0x8b, 0x83, 0, 0, 0, 0 /* mov <offset>(%rbx),%reg */};
static const uint8_t st_gp_reg[] = {0x48, 0x89, 0x83, 0, 0, 0, 0 /* mov %reg,<offset>(%rbx) */};
uint8_t *addr = push_insns (ctx, ld_p ? ld_gp_reg : st_gp_reg,
uint8_t *addr = push_insns (insn_varr, ld_p ? ld_gp_reg : st_gp_reg,
ld_p ? sizeof (ld_gp_reg) : sizeof (st_gp_reg));
memcpy (addr + 3, &offset, sizeof (uint32_t));
assert (reg <= 15);
@ -183,7 +183,7 @@ static void gen_mov (MIR_context_t ctx, uint32_t offset, uint32_t reg, int ld_p)
addr[2] |= (reg & 7) << 3;
}
static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offset,
static void gen_blk_mov (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t addr_offset,
uint32_t qwords) {
static const uint8_t blk_mov_pat[] = {
/*0:*/ 0x4c, 0x8b, 0xa3, 0, 0, 0, 0, /*mov <addr_offset>(%rbx),%r12*/
@ -194,20 +194,21 @@ static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offse
/*1e:*/ 0x48, 0x85, 0xc0, /*test %rax,%rax*/
/*21:*/ 0x7f, 0xeb, /*jg e <L0>*/
};
uint8_t *addr = push_insns (ctx, blk_mov_pat, sizeof (blk_mov_pat));
uint8_t *addr = push_insns (insn_varr, blk_mov_pat, sizeof (blk_mov_pat));
memcpy (addr + 3, &addr_offset, sizeof (uint32_t));
memcpy (addr + 10, &qwords, sizeof (uint32_t));
memcpy (addr + 26, &offset, sizeof (uint32_t));
}
static void gen_movxmm (MIR_context_t ctx, uint32_t offset, uint32_t reg, int b32_p, int ld_p) {
static void gen_movxmm (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t reg, int b32_p,
int ld_p) {
static const uint8_t ld_xmm_reg_pat[] = {
0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0 /* movs[sd] <offset>(%rbx),%xmm */
};
static const uint8_t st_xmm_reg_pat[] = {
0xf2, 0x0f, 0x11, 0x83, 0, 0, 0, 0 /* movs[sd] %xmm, <offset>(%rbx) */
};
uint8_t *addr = push_insns (ctx, ld_p ? ld_xmm_reg_pat : st_xmm_reg_pat,
uint8_t *addr = push_insns (insn_varr, ld_p ? ld_xmm_reg_pat : st_xmm_reg_pat,
ld_p ? sizeof (ld_xmm_reg_pat) : sizeof (st_xmm_reg_pat));
memcpy (addr + 4, &offset, sizeof (uint32_t));
assert (reg <= 7);
@ -215,12 +216,13 @@ static void gen_movxmm (MIR_context_t ctx, uint32_t offset, uint32_t reg, int b3
if (b32_p) addr[0] |= 1;
}
static void gen_ldst (MIR_context_t ctx, uint32_t sp_offset, uint32_t src_offset, int b64_p) {
static void gen_ldst (VARR (uint8_t) * insn_varr, uint32_t sp_offset, uint32_t src_offset,
int b64_p) {
static const uint8_t ldst_pat[] = {
0x44, 0x8b, 0x93, 0, 0, 0, 0, /* mov <src_offset>(%rbx),%r10 */
0x44, 0x89, 0x94, 0x24, 0, 0, 0, 0, /* mov %r10,<sp_offset>(%sp) */
};
uint8_t *addr = push_insns (ctx, ldst_pat, sizeof (ldst_pat));
uint8_t *addr = push_insns (insn_varr, ldst_pat, sizeof (ldst_pat));
memcpy (addr + 3, &src_offset, sizeof (uint32_t));
memcpy (addr + 11, &sp_offset, sizeof (uint32_t));
if (b64_p) {
@ -229,19 +231,19 @@ static void gen_ldst (MIR_context_t ctx, uint32_t sp_offset, uint32_t src_offset
}
}
static void gen_ldst80 (MIR_context_t ctx, uint32_t sp_offset, uint32_t src_offset) {
static void gen_ldst80 (VARR (uint8_t) * insn_varr, uint32_t sp_offset, uint32_t src_offset) {
static uint8_t const ldst80_pat[] = {
0xdb, 0xab, 0, 0, 0, 0, /* fldt <src_offset>(%rbx) */
0xdb, 0xbc, 0x24, 0, 0, 0, 0, /* fstpt <sp_offset>(%sp) */
};
uint8_t *addr = push_insns (ctx, ldst80_pat, sizeof (ldst80_pat));
uint8_t *addr = push_insns (insn_varr, ldst80_pat, sizeof (ldst80_pat));
memcpy (addr + 2, &src_offset, sizeof (uint32_t));
memcpy (addr + 9, &sp_offset, sizeof (uint32_t));
}
static void gen_st80 (MIR_context_t ctx, uint32_t src_offset) {
static void gen_st80 (VARR (uint8_t) * insn_varr, uint32_t src_offset) {
static const uint8_t st80_pat[] = {0xdb, 0xbb, 0, 0, 0, 0 /* fstpt <src_offset>(%rbx) */};
memcpy (push_insns (ctx, st80_pat, sizeof (st80_pat)) + 2, &src_offset, sizeof (uint32_t));
memcpy (push_insns (insn_varr, st80_pat, sizeof (st80_pat)) + 2, &src_offset, sizeof (uint32_t));
}
/* Generation: fun (fun_addr, res_arg_addresses):
@ -293,69 +295,74 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
#endif
uint32_t n_iregs = 0, n_xregs = 0, n_fregs, qwords;
uint8_t *addr;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prolog, sizeof (prolog));
VARR_CREATE (uint8_t, code, 128);
push_insns (code, prolog, sizeof (prolog));
for (size_t i = 0; i < nargs; i++) {
MIR_type_t type = arg_descs[i].type;
if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P || type == MIR_T_RBLK) {
if (n_iregs < max_iregs) {
gen_mov (ctx, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
gen_mov (code, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#ifdef _WIN64
n_xregs++;
#endif
} else {
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), TRUE);
gen_ldst (code, sp_offset, (i + nres) * sizeof (long double), TRUE);
sp_offset += 8;
}
} else if (type == MIR_T_F || type == MIR_T_D) {
if (n_xregs < max_xregs) {
gen_movxmm (ctx, (i + nres) * sizeof (long double), n_xregs++, type == MIR_T_F, TRUE);
gen_movxmm (code, (i + nres) * sizeof (long double), n_xregs++, type == MIR_T_F, TRUE);
#ifdef _WIN64
gen_mov (ctx, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
gen_mov (code, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#endif
} else {
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), type == MIR_T_D);
gen_ldst (code, sp_offset, (i + nres) * sizeof (long double), type == MIR_T_D);
sp_offset += 8;
}
} else if (type == MIR_T_LD) {
gen_ldst80 (ctx, sp_offset, (i + nres) * sizeof (long double));
gen_ldst80 (code, sp_offset, (i + nres) * sizeof (long double));
sp_offset += 16;
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
gen_blk_mov (ctx, sp_offset, (i + nres) * sizeof (long double), qwords);
gen_blk_mov (code, sp_offset, (i + nres) * sizeof (long double), qwords);
sp_offset += qwords * 8;
} else {
(*error_func) (MIR_call_op_error, "wrong type of arg value");
MIR_get_error_func (ctx) (MIR_call_op_error, "wrong type of arg value");
}
}
sp_offset = (sp_offset + 15) / 16 * 16;
sp_offset += 8;
addr = VARR_ADDR (uint8_t, machine_insns);
addr = VARR_ADDR (uint8_t, code);
memcpy (addr + 6, &sp_offset, sizeof (uint32_t));
addr = push_insns (ctx, call_end, sizeof (call_end));
addr = push_insns (code, call_end, sizeof (call_end));
memcpy (addr + sizeof (call_end) - 4, &sp_offset, sizeof (uint32_t));
#ifdef _WIN64
if (nres > 1)
(*error_func) (MIR_call_op_error, "Windows x86-64 doesn't support multiple return values");
MIR_get_error_func (ctx) (MIR_call_op_error,
"Windows x86-64 doesn't support multiple return values");
#endif
n_iregs = n_xregs = n_fregs = 0;
for (size_t i = 0; i < nres; i++) {
if (((MIR_T_I8 <= res_types[i] && res_types[i] <= MIR_T_U64) || res_types[i] == MIR_T_P)
&& n_iregs < 2) {
gen_mov (ctx, i * sizeof (long double), n_iregs++ == 0 ? 0 : 2, FALSE); /* rax or rdx */
gen_mov (code, i * sizeof (long double), n_iregs++ == 0 ? 0 : 2, FALSE); /* rax or rdx */
} else if ((res_types[i] == MIR_T_F || res_types[i] == MIR_T_D) && n_xregs < 2) {
gen_movxmm (ctx, i * sizeof (long double), n_xregs++, res_types[i] == MIR_T_F, FALSE);
gen_movxmm (code, i * sizeof (long double), n_xregs++, res_types[i] == MIR_T_F, FALSE);
} else if (res_types[i] == MIR_T_LD && n_fregs < 2) {
gen_st80 (ctx, i * sizeof (long double));
gen_st80 (code, i * sizeof (long double));
} else {
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"x86-64 can not handle this combination of return values");
}
}
push_insns (ctx, epilog, sizeof (epilog));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
push_insns (code, epilog, sizeof (epilog));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
@ -419,13 +426,15 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
uint32_t imm, n_iregs, n_xregs, n_fregs, offset;
uint32_t nres = func_item->u.func->nres;
MIR_type_t *results = func_item->u.func->res_types;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
VARR_CREATE (uint8_t, code, 128);
#ifndef _WIN64
push_insns (ctx, push_rbx, sizeof (push_rbx));
push_insns (code, push_rbx, sizeof (push_rbx));
#endif
push_insns (ctx, save_pat, sizeof (save_pat));
addr = push_insns (ctx, prepare_pat, sizeof (prepare_pat));
push_insns (code, save_pat, sizeof (save_pat));
addr = push_insns (code, prepare_pat, sizeof (prepare_pat));
imm = nres * 16;
memcpy (addr + nres_offset, &imm, sizeof (uint32_t));
memcpy (addr + ctx_offset, &ctx, sizeof (void *));
@ -434,40 +443,43 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
/* move results: */
#ifdef _WIN64
if (nres > 1)
(*error_func) (MIR_call_op_error, "Windows x86-64 doesn't support multiple return values");
MIR_get_error_func (ctx) (MIR_call_op_error,
"Windows x86-64 doesn't support multiple return values");
#endif
n_iregs = n_xregs = n_fregs = offset = 0;
for (uint32_t i = 0; i < nres; i++) {
if (results[i] == MIR_T_F && n_xregs < 2) {
addr = push_insns (ctx, movss_pat, sizeof (movss_pat));
addr = push_insns (code, movss_pat, sizeof (movss_pat));
addr[3] |= n_xregs << 3;
memcpy (addr + 4, &offset, sizeof (uint32_t));
n_xregs++;
} else if (results[i] == MIR_T_D && n_xregs < 2) {
addr = push_insns (ctx, movsd_pat, sizeof (movsd_pat));
addr = push_insns (code, movsd_pat, sizeof (movsd_pat));
addr[3] |= n_xregs << 3;
memcpy (addr + 4, &offset, sizeof (uint32_t));
n_xregs++;
} else if (results[i] == MIR_T_LD && n_fregs < 2) {
addr = push_insns (ctx, fldt_pat, sizeof (fldt_pat));
addr = push_insns (code, fldt_pat, sizeof (fldt_pat));
memcpy (addr + 2, &offset, sizeof (uint32_t));
if (n_fregs == 1) push_insns (ctx, fxch_pat, sizeof (fxch_pat));
if (n_fregs == 1) push_insns (code, fxch_pat, sizeof (fxch_pat));
n_fregs++;
} else if (n_iregs < 2) {
addr = push_insns (ctx, ld_pat, sizeof (ld_pat));
addr = push_insns (code, ld_pat, sizeof (ld_pat));
addr[2] |= n_iregs << 4;
memcpy (addr + 3, &offset, sizeof (uint32_t));
n_iregs++;
} else {
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
MIR_get_error_func (ctx) (MIR_ret_error,
"x86-64 can not handle this combination of return values");
}
offset += 16;
}
addr = push_insns (ctx, shim_end, sizeof (shim_end));
addr = push_insns (code, shim_end, sizeof (shim_end));
imm = prep_stack_size + nres * 16;
memcpy (addr + 3, &imm, sizeof (uint32_t));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}
/* save regs; r10 = call hook_address (ctx, called_func); restore regs; jmp *r10
@ -500,18 +512,21 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
#endif
};
uint8_t *addr;
VARR (uint8_t) * code;
void *res;
VARR_TRUNC (uint8_t, machine_insns, 0);
VARR_CREATE (uint8_t, code, 128);
#ifndef _WIN64
push_insns (ctx, push_rax, sizeof (push_rax));
push_insns (code, push_rax, sizeof (push_rax));
#endif
push_insns (ctx, save_pat, sizeof (save_pat));
addr = push_insns (ctx, call_pat, sizeof (call_pat));
push_insns (code, save_pat, sizeof (save_pat));
addr = push_insns (code, call_pat, sizeof (call_pat));
memcpy (addr + 2, &called_func, sizeof (void *));
memcpy (addr + 12, &ctx, sizeof (void *));
memcpy (addr + 22, &hook_address, sizeof (void *));
push_insns (ctx, restore_pat, sizeof (restore_pat));
push_insns (ctx, wrap_end, sizeof (wrap_end));
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
push_insns (code, restore_pat, sizeof (restore_pat));
push_insns (code, wrap_end, sizeof (wrap_end));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
}

File diff suppressed because it is too large Load Diff

@ -31,6 +31,15 @@ static inline int mir_assert (int cond) { return 0 && cond; }
#define MIR_NO_SCAN 0
#endif
#ifndef MIR_PARALLEL_GEN
#define MIR_PARALLEL_GEN 0
#endif
#if MIR_PARALLEL_GEN && defined(_WIN64) /* TODO: Win64 thread primitives ??? */
#undef MIR_PARALLEL_GEN
#define MIR_PARALLEL_GEN 0
#endif
#ifdef __GNUC__
#define MIR_UNUSED __attribute__ ((unused))
#else
@ -53,7 +62,7 @@ typedef enum MIR_error_type {
REP4 (ERR_EL, func, vararg_func, nested_func, wrong_param_value),
REP5 (ERR_EL, reserved_name, import_export, undeclared_func_reg, repeated_decl, reg_type),
REP6 (ERR_EL, wrong_type, unique_reg, undeclared_op_ref, ops_num, call_op, unspec_op),
REP4 (ERR_EL, ret, op_mode, out_op, invalid_insn)
REP6 (ERR_EL, ret, op_mode, out_op, invalid_insn, ctx_change, parallel)
} MIR_error_type_t;
#ifdef __GNUC__
@ -65,6 +74,28 @@ typedef enum MIR_error_type {
typedef void MIR_NO_RETURN (*MIR_error_func_t) (MIR_error_type_t error_type, const char *format,
...);
#if MIR_PARALLEL_GEN
#include <pthread.h>
typedef pthread_mutex_t mir_mutex_t;
typedef pthread_cond_t mir_cond_t;
#define mir_thread_create(m, attr, f, arg) pthread_create (m, attr, f, arg)
#define mir_thread_join(t, r) pthread_join (t, r)
#define mir_mutex_init(m, a) pthread_mutex_init (m, a)
#define mir_mutex_destroy(m) pthread_mutex_destroy (m)
#define mir_mutex_lock(m) pthread_mutex_lock (m)
#define mir_mutex_unlock(m) pthread_mutex_unlock (m)
#define mir_cond_init(m, a) pthread_cond_init (m, a)
#define mir_cond_destroy(m) pthread_cond_destroy (m)
#define mir_cond_wait(c, m) pthread_cond_wait (c, m)
#define mir_cond_signal(c) pthread_cond_signal (c)
#define mir_cond_broadcast(c) pthread_cond_broadcast (c)
#else
#define mir_mutex_init(m, a) 0
#define mir_mutex_destroy(m) 0
#define mir_mutex_lock(m) 0
#define mir_mutex_unlock(m) 0
#endif
#define INSN_EL(i) MIR_##i
/* The most MIR insns have destination operand and one or two source
@ -279,6 +310,7 @@ typedef struct MIR_func {
VARR (MIR_var_t) * vars; /* args and locals but temps */
void *machine_code; /* address of generated machine code or NULL */
void *call_addr; /* address to call the function, it can be the same as machine_code */
void *internal; /* internal data structure */
} * MIR_func_t;
typedef struct MIR_proto {
@ -493,6 +525,8 @@ extern void MIR_insert_insn_before (MIR_context_t ctx, MIR_item_t func, MIR_insn
MIR_insn_t insn);
extern void MIR_remove_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
extern void MIR_change_module_ctx (MIR_context_t old_ctx, MIR_module_t m, MIR_context_t new_ctx);
extern MIR_insn_code_t MIR_reverse_branch_code (MIR_insn_code_t code);
extern const char *MIR_type_str (MIR_context_t ctx, MIR_type_t tp);

@ -412,13 +412,12 @@ void *mir_get_func(MIR_context_t ctx, MIR_module_t module, const char *func_name
fprintf(stderr, "Error: Compiled function %s not found\n", func_name);
exit(1);
}
return MIR_gen (ctx, main_func);
return MIR_gen (ctx, 0, main_func);
}
void mir_prepare(MIR_context_t ctx, int optlevel) {
c2mir_init(ctx);
MIR_gen_init (ctx);
MIR_gen_set_optimize_level(ctx, optlevel);
MIR_gen_init (ctx, optlevel);
}
void mir_cleanup(MIR_context_t ctx) {

Loading…
Cancel
Save