You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/mir/mir-s390x.c

462 lines
21 KiB

/* This file is a part of MIR project.
Copyright (C) 2018-2021 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* Long doubles (-mlong-double=128) are always passed by its address (for args and results) */
/* All BLK type values and RBLK args are always passed by address. */
#if 0 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#error "s390x works only in BE mode"
#endif
#define VA_LIST_IS_ARRAY_P 1 /* one element array of struct s390x_va_list */
#define S390X_STACK_HEADER_SIZE 160
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 (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 (insn_varr, (uint8_t *) &lgr, 4);
}
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 (insn_varr, (uint8_t *) &mvghi, 6);
}
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;
uint64_t dl = disp & 0xfff, dh = (disp >> 12) & 0xff;
uint64_t common = ((uint64_t) reg << 36) | ((uint64_t) base << 28) | (dl << 16) | (dh << 8);
uint64_t lgopcode
= (type == MIR_T_I8
? (ld_p ? 0x77 : 0x72)
: type == MIR_T_U8 ? (ld_p ? 0x90 : 0x72)
: type == MIR_T_I16
? (ld_p ? 0x78 : 0x70)
: type == MIR_T_U16
? (ld_p ? 0x91 : 0x70)
: type == MIR_T_I32 ? (ld_p ? 0x14 : 0x50)
: type == MIR_T_U32 ? (ld_p ? 0x16 : 0x50)
: (ld_p ? 0x04 : 0x24));
uint64_t g = ((0xe3l << 40) | common | lgopcode) << 16;
uint64_t ey = ((0xedl << 40) | common | (ld_p ? 0x64 : 0x66)) << 16;
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 (insn_varr, (uint8_t *) (single_p ? &ey : double_p ? &dy : &g), 6);
}
static void s390x_gen_ld (VARR (uint8_t) * insn_varr, unsigned to, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (insn_varr, to, base, disp, type, TRUE);
}
static void s390x_gen_st (VARR (uint8_t) * insn_varr, unsigned from, unsigned base, int disp,
MIR_type_t type) {
s390x_gen_ld_st (insn_varr, from, base, disp, type, FALSE);
}
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 (insn_varr, (uint8_t *) &g, 6);
}
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 (insn_varr, (uint8_t *) (call_p ? &balr : &bcr), 2);
}
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 (insn_varr, (uint8_t *) &lay, 6);
}
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, 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 (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 (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> */
/*4:*/ 0xa7ab, 0xfff8, /* aghi %r10,-8 */
/*8:*/ 0xe30a, 0x9000, 0x0004, /* lg %r0,0(%r10,%r9) */
/*14:*/ 0xe30a, 0x0000, 0x0024, /* stg %r0,0(%r10,<addr_reg:2-6,8>) */
/*20:*/ 0xb902, 0x00aa, /* ltgr %r10,%r10 */
/*24:*/ 0xa724, 0xfff6, /* jh 4 */
};
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 (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 (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 (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 (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 (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 (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, 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 (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, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
}
struct s390x_va_list {
long __gpr, __fpr; /* number of args read until now */
void *__overflow_arg_area; /* argument on the stack to read next */
void *__reg_save_area; /* curr func frame start */
};
void *va_arg_builtin (void *p, uint64_t t) {
struct s390x_va_list *va = p;
MIR_type_t type = t;
int fp_p = type == MIR_T_F || type == MIR_T_D;
void *a;
if (!fp_p) {
if (va->__gpr < 5) {
a = (char *) va->__reg_save_area + 16 + 8 * va->__gpr;
} else {
a = va->__overflow_arg_area;
va->__overflow_arg_area = (char *) va->__overflow_arg_area + 8;
}
va->__gpr++;
if (type == MIR_T_LD) a = *(void **) a; /* always passed by address */
} else {
if (va->__fpr < 4) {
a = (char *) va->__reg_save_area + 128 + 8 * va->__fpr;
} else {
a = va->__overflow_arg_area;
va->__overflow_arg_area = (char *) va->__overflow_arg_area + 8;
}
va->__fpr++;
}
if (type == MIR_T_F || type == MIR_T_I32) a = (char *) a + 4; /* 2nd word of doubleword */
return a;
}
void va_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
memcpy (res, *(void **) va_arg_builtin (p, MIR_T_I64), s);
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct s390x_va_list *va = p;
va_list *vap = a;
assert (sizeof (struct s390x_va_list) == sizeof (va_list));
*va = *(struct s390x_va_list *) vap;
}
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
/* Generation: fun (fun_addr, res_arg_addresses):
save r6, r7, r14 (r15 + 48,112);
allocate and stack frame (S390X_STACK_HEADER_SIZE + param area size + ld arg values size);
r1=r2 (fun_addr);
r7=r3 (res_arg_addresses);
(arg_reg=mem[r7,arg_offset] or
(f1,r0)=mem[r7,arg_offset];mem[r15,S390X_STACK_HEADER_SIZE+offset]=(f1,r0)) ... call *r1;
r0=mem[r7,<res_offset>]; res_reg=mem[r0]; ...
restore r15; restore r6, r7, r14; return. */
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
_MIR_arg_desc_t *arg_descs, int vararg_p) {
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_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: */
type = arg_descs[i].type;
if (MIR_blk_type_p (type)) frame_size += (arg_descs[i].size + 7) / 8; /* blk value space */
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 5) { /* RBLK too */
n_gpregs++;
} else {
frame_size += 8;
blk_offset += 8;
}
}
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 (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 (code, n_fpregs * 2, res_reg, param_offset, type);
n_fpregs++;
} else if (type == MIR_T_F || type == MIR_T_D) {
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 (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 (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 (MIR_blk_type_p (type)) {
qwords = (arg_descs[i].size + 7) / 8;
addr_reg = n_gpregs < 5 ? n_gpregs + 2 : 8;
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 (code, 8, 15, disp, MIR_T_I64); /* stg r8,disp(r15) */
disp += 8;
}
} else if (n_gpregs < 5) { /* RBLK too */
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 (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 (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 (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 (code, n_gpregs + 2, res_reg, disp, MIR_T_I64);
n_gpregs++;
} else {
MIR_get_error_func (ctx) (MIR_ret_error,
"s390x can not handle this combination of return values");
}
disp += 16;
}
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,
va_list va, MIR_val_t *results):
Brief: save all C call args to register save area; save r7, r14;
allocate shim stack frame (S390X_STACK_HEADER_SIZE + space for results and va);
call handler with args; move results to return regs; restore r7,r14,r15; return */
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
MIR_func_t func = func_item->u.func;
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 (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 (code, 15, 15, -frame_size);
/* setup va: mvghi va(15),(0,1): __gpr */
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 (code, 1, 15, va_list_disp + 16, MIR_T_I64);
/* call handler: */
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 (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 (code, n_gpregs + 2, 15, disp, MIR_T_I64);
} else {
/* ld address: lg r2,16+frame_size(r15) */
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 {
MIR_get_error_func (ctx) (MIR_ret_error,
"s390x can not handle this combination of return values");
}
disp += 16;
}
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);
update r15; allocate and form minimal wrapper stack frame (S390X_STACK_HEADER_SIZE);
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 (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 (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 (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;
}