Compare commits

...

5 Commits

Author SHA1 Message Date
Dibyendu Majumdar cadee5563f issue #198 add another test for sieve - but using while loop
4 years ago
Dibyendu Majumdar 66bf2c6c17 issue #198 tests for farray opcodes
4 years ago
Dibyendu Majumdar faff7902b3 issue #198 tests for iarray opcodes
4 years ago
Dibyendu Majumdar 4b9c746526 issue #169 debug output
4 years ago
Dibyendu Majumdar ba0c697c9a issue #169 non-ssa branch
4 years ago

@ -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;"},
};

@ -2107,7 +2107,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 {

File diff suppressed because it is too large Load Diff

@ -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
@ -131,7 +162,6 @@ typedef enum {
INSN_EL (VA_END), /* operand is va_list */
INSN_EL (LABEL), /* One immediate operand is unique label number */
INSN_EL (UNSPEC), /* First operand unspec code and the rest are args */
INSN_EL (PHI), /* Used only internally in the generator, the first operand is output */
INSN_EL (INVALID_INSN),
INSN_EL (INSN_BOUND), /* Should be the last */
} MIR_insn_code_t;
@ -279,6 +309,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 +524,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);

@ -389,6 +389,7 @@ MIR_module_t mir_compile_C_module(
options->module_num++;
snprintf(module_name, sizeof module_name, "__mod_%lld__", options->module_num);
options->message_file = stderr;
//MIR_gen_set_debug_file(ctx, 0, stdout);
if (!c2mir_compile(ctx, options, t_getc, &read_buffer, module_name, NULL)) {
ret_code = 1;
}
@ -412,13 +413,13 @@ 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, 0);
MIR_gen_set_optimize_level(ctx, 0, optlevel);
}
void mir_cleanup(MIR_context_t ctx) {

@ -0,0 +1,21 @@
f = compiler.load([[
local arr: integer[] = table.intarray(10)
arr[0] = 10
arr[4] = 2
arr[11] = 6
local sum: integer = 0
for i=0,11 do
print(arr[i])
sum = sum + arr[i]
end
return sum, arr
]]
)
assert(f and type(f) == 'function')
local s,arr = f()
assert(s == 18)
assert(arr[0] == 10)
assert(arr[4] == 2)
assert(arr[11] == 6)
assert(#arr == 11)

@ -0,0 +1,30 @@
local sieve = compiler.load([[
local i: integer, k: integer, prime: integer, count: integer
local flags: integer[] = table.intarray(8190)
for iter=0,100000 do
count = 0
for i=0,8190 do
flags[i] = 1
end
for i=0,8190 do
if flags[i] == 1 then
prime = i + i + 3;
for k = i + prime, 8190, prime do
flags[k] = 0
end
count = count + 1
end
end
end
return count
]]
)
assert(sieve and type(sieve) == 'function')
local t1 = os.clock()
local count = sieve()
local t2 = os.clock()
print("time taken ", t2-t1)
print(count)
assert(count == 1899)

@ -0,0 +1,21 @@
f = compiler.load([[
return function(arr: number[], i: integer, value: number)
arr[i] = value
end
]]
)
assert(f and type(f) == 'function')
z = f()
assert(z and type(z) == 'function')
x = table.numarray(10)
z(x, 1, 1.1)
assert(x[1] == 1.1)
z(x, 2, 2.2)
assert(x[1] == 1.1)
assert(x[2] == 2.2)
z(x, 11, 11.11)
assert(x[1] == 1.1)
assert(x[2] == 2.2)
assert(x[11] == 11.11)
z(x, 12, 12)
assert(x[12] == 12.0)

@ -0,0 +1,38 @@
local sieve = compiler.load([[
local i: integer, k: integer, prime: integer, count: integer
local flags: integer[] = table.intarray(8190)
local iter: integer = 0
while iter <= 100000 do
count = 0
i = 0
while i <= 8190 do
flags[i] = 1
i = i + 1
end
i = 0
while i <= 8190 do
if flags[i] == 1 then
prime = i + i + 3;
k = i + prime
while k <= 8190 do
flags[k] = 0
k = k + prime
end
count = count + 1
end
i = i + 1
end
iter = iter + 1
end
return count
]]
)
assert(sieve and type(sieve) == 'function')
local t1 = os.clock()
local count = sieve()
local t2 = os.clock()
print("time taken ", t2-t1)
print(count)
assert(count == 1899)

@ -1,5 +1,5 @@
local function x()
local j = 0.0
local j = 0
for i=2,1000000000 do
j = i
end

Loading…
Cancel
Save