X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-s390x.c;h=eb8fe17f2682b52dc8f6ee04ec5f899a7acc48b8;hb=8b9a653c5788b607691c2e973bd20211b0b34430;hp=f30ca2a9397d375b69449df809f44d150ce6a589;hpb=89385f38542b967234428a3619f72db972f9f337;p=mono.git diff --git a/mono/mini/mini-s390x.c b/mono/mini/mini-s390x.c index f30ca2a9397..eb8fe17f268 100644 --- a/mono/mini/mini-s390x.c +++ b/mono/mini/mini-s390x.c @@ -18,9 +18,6 @@ /* D e f i n e s */ /*------------------------------------------------------------------*/ -#define NOT_IMPLEMENTED(x) \ - g_error ("FIXME: %s is not yet implemented.", x); - #define EMIT_COND_BRANCH(ins,cond) \ { \ if (ins->flags & MONO_INST_BRLABEL) { \ @@ -159,6 +156,108 @@ if (ins->flags & MONO_INST_BRLABEL) { \ s390_ldr (code, ins->dreg, ins->sreg1); \ } +#define MONO_EMIT_NEW_MOVE2(cfg,dest,offset,src,imm,size) do { \ + MonoInst *inst; \ + int tmpr = 0; \ + int sReg, dReg; \ + MONO_INST_NEW (cfg, inst, OP_NOP); \ + if (size > 256) { \ + tmpr = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_ICONST(cfg,tmpr,size); \ + inst->dreg = dest; \ + inst->inst_offset = offset; \ + inst->sreg1 = src; \ + inst->inst_imm = imm; \ + inst->sreg2 = tmpr; \ + } else { \ + if (s390_is_uimm12(offset)) { \ + inst->dreg = dest; \ + inst->inst_offset = offset; \ + } else { \ + dReg = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \ + dReg, dest, offset); \ + inst->dreg = dReg; \ + inst->inst_offset = 0; \ + } \ + if (s390_is_uimm12(imm)) { \ + inst->sreg1 = src; \ + inst->inst_imm = imm; \ + } else { \ + sReg = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \ + sReg, src, imm); \ + inst->sreg1 = sReg; \ + inst->inst_imm = 0; \ + } \ + } \ + inst->opcode = OP_S390_MOVE; \ + inst->backend.size = size; \ + MONO_ADD_INS (cfg->cbb, inst); \ + } while (0) + +#define MONO_OUTPUT_VTR2(cfg, size, dr, sr, so) do { \ + int reg = mono_alloc_preg (cfg); \ + switch (size) { \ + case 0: \ + MONO_EMIT_NEW_ICONST(cfg, reg, 0); \ + break; \ + case 1: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \ + reg, sr, so); \ + break; \ + case 2: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \ + reg, sr, so); \ + break; \ + case 4: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \ + reg, sr, so); \ + break; \ + case 8: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, \ + reg, sr, so); \ + break; \ + } \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ +} while (0) + +#define MONO_OUTPUT_VTS2(cfg, size, dr, dx, sr, so) do { \ + int tmpr; \ + switch (size) { \ + case 0: \ + tmpr = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_ICONST(cfg, tmpr, 0); \ + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ + dr, dx, tmpr); \ + break; \ + case 1: \ + tmpr = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \ + tmpr, sr, so); \ + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ + dr, dx, tmpr); \ + break; \ + case 2: \ + tmpr = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \ + tmpr, sr, so); \ + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ + dr, dx, tmpr); \ + break; \ + case 4: \ + tmpr = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \ + tmpr, sr, so); \ + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ + dr, dx, tmpr); \ + break; \ + case 8: \ + MONO_EMIT_NEW_MOVE2 (cfg, dr, dx, sr, so, size); \ + break; \ + } \ +} while (0) + #undef DEBUG #define DEBUG(a) if (cfg->verbose_level > 1) a @@ -166,7 +265,7 @@ if (ins->flags & MONO_INST_BRLABEL) { \ #define S390_TRACE_STACK_SIZE (5*sizeof(gpointer)+4*sizeof(gdouble)) -#define MAX (a, b) ((a) > (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) /*========================= End of Defines =========================*/ @@ -185,6 +284,7 @@ if (ins->flags & MONO_INST_BRLABEL) { \ #include "mini-s390x.h" #include "inssel.h" #include "cpu-s390x.h" +#include "jit-icalls.h" /*========================= End of Includes ========================*/ @@ -223,20 +323,22 @@ struct InstList { MonoInst *data; }; -enum { +typedef enum { RegTypeGeneral, RegTypeBase, RegTypeFP, + RegTypeFPR4, RegTypeStructByVal, + RegTypeStructByValInFP, RegTypeStructByAddr -}; +} ArgStorage; typedef struct { gint32 offset; /* offset from caller's stack */ gint32 offparm; /* offset from callee's stack */ guint16 vtsize; /* in param area */ guint8 reg; - guint8 regtype; /* See RegType* */ + ArgStorage regtype; guint32 size; /* Size of structure used by RegTypeStructByVal */ gint32 type; /* Data type of argument */ } ArgInfo; @@ -248,6 +350,7 @@ typedef struct { guint32 struct_ret; ArgInfo ret; ArgInfo sigCookie; + size_data sz; ArgInfo args [1]; } CallInfo; @@ -271,13 +374,10 @@ static gboolean is_regsize_var (MonoType *); static inline void add_general (guint *, size_data *, ArgInfo *); static inline void add_stackParm (guint *, size_data *, ArgInfo *, gint); static inline void add_float (guint *, size_data *, ArgInfo *); -static CallInfo * calculate_sizes (MonoMethodSignature *, size_data *, gboolean); -static void peephole_pass (MonoCompile *, MonoBasicBlock *); +static CallInfo * get_call_info (MonoCompile *, MonoMemPool *, MonoMethodSignature *, gboolean); static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean); -static void mono_arch_break(void); gpointer mono_arch_get_lmf_addr (void); -static guint8 * emit_load_volatile_registers (guint8 *, MonoCompile *); -static CompRelation opcode_to_cond (int); +static guint8 * emit_load_volatile_arguments (guint8 *, MonoCompile *); static void catch_SIGILL(int, siginfo_t *, void *); static void emit_sig_cookie (MonoCompile *, MonoCallInst *, CallInfo *, int); @@ -296,7 +396,6 @@ int has_ld = 0; static gboolean tls_offset_inited = FALSE; static int appdomain_tls_offset = -1, - lmf_tls_offset = -1, thread_tls_offset = -1; pthread_key_t lmf_addr_key; @@ -409,7 +508,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, if (csig->pinvoke) size = mono_type_native_stack_size (csig->params [k], &align); else - size = mono_type_stack_size (csig->params [k], &align); + size = mini_type_stack_size (NULL, csig->params [k], &align); frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); arg_info [k].pad = pad; @@ -470,7 +569,7 @@ backUpStackPtr(MonoCompile *cfg, guint8 *code) { int stackSize = cfg->stack_usage; - if (s390_is_uimm16 (stackSize)) { + if (s390_is_imm16 (stackSize)) { s390_aghi (code, STK_BASE, stackSize); } else { while (stackSize > 32767) { @@ -682,7 +781,6 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp) guint64 ip; CallInfo *cinfo; ArgInfo *ainfo; - size_data sz; void *curParm; fname = mono_method_full_name (method, TRUE); @@ -698,7 +796,7 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp) sig = mono_method_signature (method); - cinfo = calculate_sizes (sig, &sz, sig->pinvoke); + cinfo = get_call_info (NULL, NULL, sig, sig->pinvoke); if (cinfo->struct_ret) { printf ("[STRUCTRET:%p], ", (gpointer) rParm->gr[0]); @@ -1058,6 +1156,23 @@ mono_arch_cpu_init (void) /*========================= End of Function ========================*/ + +/* + * Initialize architecture specific code. + */ +void +mono_arch_init (void) +{ +} + +/* + * Cleanup architecture specific code. + */ +void +mono_arch_cleanup (void) +{ +} + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_cpu_optimizazions */ @@ -1177,8 +1292,11 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses) cfg->frame_reg = s390_r11; + + /* FIXME: s390_r12 is reserved for bkchain_reg. Only reserve it if needed */ + top = 12; for (i = 8; i < top; ++i) { - if (cfg->frame_reg != i) + if (cfg->frame_reg != i) regs = g_list_prepend (regs, GUINT_TO_POINTER (i)); } @@ -1246,14 +1364,16 @@ add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size) { if (*gr > S390_LAST_ARG_REG) { sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); - ainfo->reg = STK_BASE; - sz->stack_size += sizeof(gpointer); + ainfo->reg = STK_BASE; + ainfo->offset = sz->stack_size; + sz->stack_size += sizeof (gpointer); + sz->parm_size += sizeof(gpointer); sz->offStruct += sizeof(gpointer); } else { ainfo->reg = *gr; + ainfo->offset = sz->stack_size; } (*gr) ++; - ainfo->offset = sz->stack_size; ainfo->offparm = sz->offset; sz->offset = S390_ALIGN(sz->offset+size, sizeof(long)); ainfo->size = size; @@ -1297,7 +1417,7 @@ add_float (guint *fr, size_data *sz, ArgInfo *ainfo) /*------------------------------------------------------------------*/ /* */ -/* Name - calculate_sizes */ +/* Name - get_call_info */ /* */ /* Function - Determine the amount of space required for code */ /* and stack. In addition determine starting points */ @@ -1307,18 +1427,26 @@ add_float (guint *fr, size_data *sz, ArgInfo *ainfo) /*------------------------------------------------------------------*/ static CallInfo * -calculate_sizes (MonoMethodSignature *sig, size_data *sz, - gboolean string_ctor) +get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke) { guint i, fr, gr, size; int nParm = sig->hasthis + sig->param_count; + MonoType *ret_type; guint32 simpletype, align; - CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * nParm); + CallInfo *cinfo; + size_data *sz; + MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL; + + if (mp) + cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + sizeof (ArgInfo) * nParm); + else + cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * nParm); fr = 0; gr = s390_r2; nParm = 0; cinfo->struct_ret = 0; + sz = &cinfo->sz; sz->retStruct = 0; sz->offset = 0; sz->offStruct = S390_MINIMAL_STACK_SIZE; @@ -1333,7 +1461,9 @@ calculate_sizes (MonoMethodSignature *sig, size_data *sz, /* area that the callee will use. */ /*----------------------------------------------------------*/ - simpletype = mono_type_get_underlying_type (sig->ret)->type; + ret_type = mono_type_get_underlying_type (sig->ret); + ret_type = mini_get_basic_type_from_generic (gsctx, ret_type); + simpletype = ret_type->type; enum_retvalue: switch (simpletype) { case MONO_TYPE_BOOLEAN: @@ -1382,7 +1512,7 @@ enum_retvalue: if (sig->pinvoke) size = mono_class_native_size (klass, &align); else - size = mono_class_value_size (klass, &align); + size = mono_class_value_size (klass, &align); cinfo->ret.reg = s390_r2; cinfo->struct_ret = 1; @@ -1418,6 +1548,8 @@ enum_retvalue: /*----------------------------------------------------------*/ for (i = 0; i < sig->param_count; ++i) { + MonoType *ptype; + /*--------------------------------------------------*/ /* Handle vararg type calls. All args are put on */ /* the stack. */ @@ -1435,7 +1567,9 @@ enum_retvalue: continue; } - simpletype = mono_type_get_underlying_type(sig->params [i])->type; + ptype = mono_type_get_underlying_type (sig->params [i]); + ptype = mini_get_basic_type_from_generic (gsctx, ptype); + simpletype = ptype->type; cinfo->args[nParm].type = simpletype; switch (simpletype) { case MONO_TYPE_BOOLEAN: @@ -1510,6 +1644,7 @@ enum_retvalue: (info->fields[0].field->type->type == MONO_TYPE_R4)) { cinfo->args[nParm].size = sizeof(float); add_float(&fr, sz, cinfo->args+nParm); + nParm ++; break; } @@ -1518,6 +1653,7 @@ enum_retvalue: (info->fields[0].field->type->type == MONO_TYPE_R8)) { cinfo->args[nParm].size = sizeof(double); add_float(&fr, sz, cinfo->args+nParm); + nParm ++; break; } @@ -1638,7 +1774,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) MonoMethodHeader *header; MonoInst *inst; CallInfo *cinfo; - size_data sz; int iParm, iVar, offset, size, align, curinst; int frame_reg = STK_BASE; int sArg, eArg; @@ -1662,16 +1797,20 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->frame_reg = frame_reg; + cfg->arch.bkchain_reg = -1; + if (frame_reg != STK_BASE) cfg->used_int_regs |= 1 << frame_reg; sig = mono_method_signature (cfg->method); - cinfo = calculate_sizes (sig, &sz, sig->pinvoke); + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); if (cinfo->struct_ret) { - cfg->ret->opcode = OP_REGVAR; - cfg->ret->inst_c0 = s390_r2; + if (!cfg->new_ir) { + cfg->vret_addr->opcode = OP_REGVAR; + cfg->vret_addr->inst_c0 = s390_r2; + } } else { switch (mono_type_get_underlying_type (sig->ret)->type) { case MONO_TYPE_VOID: @@ -1693,19 +1832,23 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->sig_cookie = 0; if (cinfo->struct_ret) { - inst = cfg->ret; + inst = cfg->vret_addr; offset = S390_ALIGN(offset, sizeof(gpointer)); inst->inst_offset = offset; inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; offset += sizeof(gpointer); - if ((sig->call_convention == MONO_CALL_VARARG) && + if (!cfg->new_ir && (sig->call_convention == MONO_CALL_VARARG) && (!retFitsInReg (cinfo->ret.size))) cfg->sig_cookie += cinfo->ret.size; + if (G_UNLIKELY (cfg->verbose_level > 1)) { + printf ("vret_addr ="); + mono_print_ins (cfg->vret_addr); + } } if (sig->hasthis) { - inst = cfg->varinfo [0]; + inst = cfg->args [0]; if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; @@ -1724,54 +1867,109 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->sig_cookie += S390_MINIMAL_STACK_SIZE; for (iParm = sArg; iParm < eArg; ++iParm) { - inst = cfg->varinfo [curinst]; + inst = cfg->args [curinst]; if (inst->opcode != OP_REGVAR) { switch (cinfo->args[iParm].regtype) { - case RegTypeStructByAddr : - if (cinfo->args[iParm].reg == STK_BASE) { - inst->opcode = OP_S390_LOADARG; + case RegTypeStructByAddr : + if (cfg->new_ir) { + MonoInst *indir; + + size = sizeof (gpointer); + + inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; - offset = S390_ALIGN(offset, sizeof(long)); - inst->inst_offset = offset; - size = abs(cinfo->args[iParm].vtsize); - inst->backend.arg_info = cinfo->args[iParm].offset; + offset = S390_ALIGN (offset, sizeof (gpointer)); + inst->inst_offset = offset; + + /* Add a level of indirection */ + MONO_INST_NEW (cfg, indir, 0); + *indir = *inst; + inst->opcode = OP_VTARG_ADDR; + inst->inst_left = indir; } else { - inst->opcode = OP_S390_ARGREG; - inst->inst_basereg = frame_reg; - size = sizeof(gpointer); - offset = S390_ALIGN(offset, size); - inst->inst_offset = offset; - inst->backend.arg_info = cinfo->args[iParm].offset; + if (cinfo->args[iParm].reg == STK_BASE) { + inst->opcode = OP_S390_LOADARG; + inst->inst_basereg = frame_reg; + offset = S390_ALIGN(offset, sizeof(long)); + inst->inst_offset = offset; + size = abs(cinfo->args[iParm].vtsize); + inst->backend.arg_info = cinfo->args[iParm].offset; + } else { + inst->opcode = OP_S390_ARGREG; + inst->inst_basereg = frame_reg; + size = sizeof(gpointer); + offset = S390_ALIGN(offset, size); + inst->inst_offset = offset; + inst->backend.arg_info = cinfo->args[iParm].offset; + } } - break; - case RegTypeStructByVal : + break; + case RegTypeStructByVal : + if (cfg->new_ir) { + size = cinfo->args[iParm].size; + offset = S390_ALIGN(offset, size); + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = frame_reg; + inst->inst_offset = offset; + } else { inst->opcode = OP_S390_ARGPTR; inst->inst_basereg = frame_reg; size = cinfo->args[iParm].size; offset = S390_ALIGN(offset, size); inst->inst_offset = offset; inst->backend.arg_info = cinfo->args[iParm].offset; - break; - default : - if (cinfo->args[iParm].reg != STK_BASE) { - inst->opcode = OP_REGOFFSET; - inst->inst_basereg = frame_reg; - size = (cinfo->args[iParm].size < 8 - ? sizeof(int) - : sizeof(long)); - offset = S390_ALIGN(offset, size); - inst->inst_offset = offset; + } + break; + default : + if (cfg->new_ir) { + if (cinfo->args [iParm].reg == STK_BASE) { + /* + * These arguments are in the previous frame, so we can't + * compute their offset from the current frame pointer right + * now, since cfg->stack_offset is not yet known, so dedicate a + * register holding the previous frame pointer. + */ + cfg->arch.bkchain_reg = s390_r12; + cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg; + + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = cfg->arch.bkchain_reg; + size = (cinfo->args[iParm].size < 8 + ? 8 - cinfo->args[iParm].size + : 0); + inst->inst_offset = cinfo->args [iParm].offset + size; + size = sizeof (long); + } else { + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = frame_reg; + size = (cinfo->args[iParm].size < 8 + ? sizeof(int) + : sizeof(long)); + offset = S390_ALIGN(offset, size); + inst->inst_offset = offset; + } } else { - inst->opcode = OP_S390_STKARG; - inst->inst_basereg = frame_reg; - size = ((cinfo->args[iParm].size < 8) - ? 8 - cinfo->args[iParm].size - : 0); - inst->inst_offset = cinfo->args[iParm].offset + - size; - inst->backend.arg_info = 0; - size = sizeof(long); - } + if (cinfo->args[iParm].reg != STK_BASE) { + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = frame_reg; + size = (cinfo->args[iParm].size < 8 + ? sizeof(int) + : sizeof(long)); + offset = S390_ALIGN(offset, size); + inst->inst_offset = offset; + } else { + inst->opcode = OP_S390_STKARG; + inst->inst_basereg = frame_reg; + size = ((cinfo->args[iParm].size < 8) + ? 8 - cinfo->args[iParm].size + : 0); + inst->inst_offset = cinfo->args[iParm].offset + + size; + inst->backend.arg_info = 0; + size = sizeof(long); + } + } + break; } if ((sig->call_convention == MONO_CALL_VARARG) && (cinfo->args[iParm].regtype != RegTypeGeneral) && @@ -1830,6 +2028,32 @@ mono_arch_allocate_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_create_vars */ +/*------------------------------------------------------------------*/ + +void +mono_arch_create_vars (MonoCompile *cfg) +{ + MonoMethodSignature *sig; + CallInfo *cinfo; + + sig = mono_method_signature (cfg->method); + + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); + + if (cinfo->struct_ret) { + cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG); + if (G_UNLIKELY (cfg->verbose_level > 1)) { + printf ("vret_addr = "); + mono_print_ins (cfg->vret_addr); + } + } +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_call_opcode */ @@ -1843,23 +2067,23 @@ mono_arch_allocate_vars (MonoCompile *cfg) MonoCallInst* mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, - MonoCallInst *call, int is_virtual) { + MonoCallInst *call, int is_virtual) +{ MonoInst *in; MonoCallArgParm *arg; MonoMethodSignature *sig; int i, n, lParamArea; CallInfo *cinfo; ArgInfo *ainfo; - size_data sz; sig = call->signature; n = sig->param_count + sig->hasthis; DEBUG (g_print ("Call requires: %d parameters\n",n)); - cinfo = calculate_sizes (sig, &sz, sig->pinvoke); + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); - call->stack_usage = MAX(sz.stack_size, call->stack_usage); - lParamArea = MAX((call->stack_usage - S390_MINIMAL_STACK_SIZE - sz.parm_size), 0); + call->stack_usage = MAX(cinfo->sz.stack_size, call->stack_usage); + lParamArea = MAX((call->stack_usage - S390_MINIMAL_STACK_SIZE - cinfo->sz.parm_size), 0); cfg->param_area = MAX (((signed) cfg->param_area), lParamArea); cfg->flags |= MONO_CFG_HAS_CALLS; @@ -1885,7 +2109,6 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, arg->ins.cil_code = in->cil_code; arg->ins.inst_left = in; arg->ins.type = in->type; - /* prepend, we'll need to reverse them later */ arg->ins.next = call->out_args; call->out_args = (MonoInst *) arg; @@ -1899,7 +2122,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, arg->ins.opcode = OP_OUTARG_VT; arg->size = -ainfo->vtsize; arg->offset = ainfo->offset; - arg->offPrm = ainfo->offparm + sz.offStruct; + arg->offPrm = ainfo->offparm + cinfo->sz.offStruct; } else if (ainfo->regtype == RegTypeStructByVal) { if (ainfo->reg != STK_BASE) call->used_iregs |= 1 << ainfo->reg; @@ -1907,7 +2130,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, arg->ins.opcode = OP_OUTARG_VT; arg->size = ainfo->size; arg->offset = ainfo->offset; - arg->offPrm = ainfo->offparm + sz.offStruct; + arg->offPrm = ainfo->offparm + cinfo->sz.offStruct; } else if (ainfo->regtype == RegTypeBase) { arg->ins.opcode = OP_OUTARG_MEMBASE; arg->ins.sreg1 = ainfo->reg; @@ -1950,12 +2173,317 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, call->out_args = prev; } - g_free (cinfo); return call; } /*========================= End of Function ========================*/ +static void +add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree) +{ + MonoInst *ins; + + switch (storage) { + case RegTypeGeneral: + MONO_INST_NEW (cfg, ins, OP_MOVE); + ins->dreg = mono_alloc_ireg (cfg); + ins->sreg1 = tree->dreg; + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE); + break; + case RegTypeFP: + MONO_INST_NEW (cfg, ins, OP_FMOVE); + ins->dreg = mono_alloc_freg (cfg); + ins->sreg1 = tree->dreg; + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE); + break; + case RegTypeFPR4: + MONO_INST_NEW (cfg, ins, OP_S390_SETF4RET); + ins->dreg = mono_alloc_freg (cfg); + ins->sreg1 = tree->dreg; + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE); + break; + default: + g_assert_not_reached (); + } +} + +static void +emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) +{ + MonoMethodSignature *tmpSig; + MonoInst *sig_arg; + + cfg->disable_aot = TRUE; + + /*----------------------------------------------------------*/ + /* mono_ArgIterator_Setup assumes the signature cookie is */ + /* passed first and all the arguments which were before it */ + /* passed on the stack after the signature. So compensate */ + /* by passing a different signature. */ + /*----------------------------------------------------------*/ + tmpSig = mono_metadata_signature_dup (call->signature); + tmpSig->param_count -= call->signature->sentinelpos; + tmpSig->sentinelpos = 0; + if (tmpSig->param_count > 0) + memcpy (tmpSig->params, + call->signature->params + call->signature->sentinelpos, + tmpSig->param_count * sizeof(MonoType *)); + + MONO_INST_NEW (cfg, sig_arg, OP_ICONST); + sig_arg->dreg = mono_alloc_ireg (cfg); + sig_arg->inst_p0 = tmpSig; + MONO_ADD_INS (cfg->cbb, sig_arg); + + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, STK_BASE, + cinfo->sigCookie.offset, sig_arg->dreg); +} + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_emit_call */ +/* */ +/*------------------------------------------------------------------*/ + +void +mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) +{ + MonoInst *in; + MonoMethodSignature *sig; + MonoInst *ins; + int i, n, lParamArea; + CallInfo *cinfo; + ArgInfo *ainfo = NULL; + int stackSize; + + sig = call->signature; + n = sig->param_count + sig->hasthis; + DEBUG (g_print ("Call requires: %d parameters\n",n)); + + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); + + stackSize = cinfo->sz.stack_size + cinfo->sz.local_size + cinfo->sz.parm_size + cinfo->sz.offset; + call->stack_usage = MAX(stackSize, call->stack_usage); + lParamArea = MAX((call->stack_usage-S390_MINIMAL_STACK_SIZE-cinfo->sz.parm_size), 0); + cfg->param_area = MAX(((signed) cfg->param_area), lParamArea); + cfg->flags |= MONO_CFG_HAS_CALLS; + + if (cinfo->struct_ret) { + MONO_INST_NEW (cfg, ins, OP_MOVE); + ins->sreg1 = call->vret_var->dreg; + ins->dreg = mono_alloc_preg (cfg); + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, cinfo->ret.reg, FALSE); + } + + for (i = 0; i < n; ++i) { + ainfo = cinfo->args + i; + MonoType *t; + + if (i >= sig->hasthis) + t = sig->params [i - sig->hasthis]; + else + t = &mono_defaults.int_class->byval_arg; + t = mono_type_get_underlying_type (t); + + in = call->args [i]; + + if ((sig->call_convention == MONO_CALL_VARARG) && + (i == sig->sentinelpos)) { + emit_sig_cookie2 (cfg, call, cinfo); + } + + switch (ainfo->regtype) { + case RegTypeGeneral: + add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in); + break; + case RegTypeFP: + if (MONO_TYPE_ISSTRUCT (t)) { + /* Valuetype passed in one fp register */ + ainfo->regtype = RegTypeStructByValInFP; + /* Fall through */ + } else { + if (ainfo->size == 4) + ainfo->regtype = RegTypeFPR4; + add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in); + break; + } + case RegTypeStructByVal: + case RegTypeStructByAddr: { + guint32 align; + guint32 size; + + if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) { + size = sizeof (MonoTypedRef); + align = sizeof (gpointer); + } + else + if (sig->pinvoke) + size = mono_type_native_stack_size (&in->klass->byval_arg, &align); + else { + /* + * Other backends use mono_type_stack_size (), but that + * aligns the size to 8, which is larger than the size of + * the source, leading to reads of invalid memory if the + * source is at the end of address space. + */ + size = mono_class_value_size (in->klass, &align); + } + + g_assert (in->klass); + + ainfo->offparm += cinfo->sz.offStruct; + + MONO_INST_NEW (cfg, ins, OP_OUTARG_VT); + ins->sreg1 = in->dreg; + ins->klass = in->klass; + ins->backend.size = ainfo->size; + ins->inst_p0 = call; + ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo)); + memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo)); + + MONO_ADD_INS (cfg->cbb, ins); + + if (ainfo->regtype == RegTypeStructByAddr) { + /* + * We use OP_OUTARG_VT to copy the valuetype to a stack location, then + * use the normal OUTARG opcodes to pass the address of the location to + * the callee. + */ + int treg = mono_alloc_preg (cfg); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, treg, + STK_BASE, ainfo->offparm); + mono_call_inst_add_outarg_reg (cfg, call, treg, ainfo->reg, FALSE); + } + break; + } + case RegTypeBase: + if (!t->byref && t->type == MONO_TYPE_R4) { + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, + STK_BASE, ainfo->offset + 4, + in->dreg); + } else if (!t->byref && (t->type == MONO_TYPE_R8)) { + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, + STK_BASE, ainfo->offset, + in->dreg); + } else { + MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG); + ins->inst_destbasereg = STK_BASE; + ins->inst_offset = ainfo->offset; + ins->sreg1 = in->dreg; + + /* This is needed by MonoTypedRef->value to point to the correct data */ + if ((sig->call_convention == MONO_CALL_VARARG) && + (i >= sig->sentinelpos)) { + switch (ainfo->size) { + case 1: + ins->opcode = OP_STOREI1_MEMBASE_REG; + break; + case 2: + ins->opcode = OP_STOREI2_MEMBASE_REG; + break; + case 4: + ins->opcode = OP_STOREI4_MEMBASE_REG; + break; + default: + break; + } + } + + MONO_ADD_INS (cfg->cbb, ins); + } + break; + default: + g_assert_not_reached (); + break; + } + } + + /* + * Handle the case where there are no implicit arguments + */ + if ((sig->call_convention == MONO_CALL_VARARG) && + (i == sig->sentinelpos)) { + emit_sig_cookie2 (cfg, call, cinfo); + } +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_emit_outarg_vt */ +/* */ +/*------------------------------------------------------------------*/ + +void +mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) +{ + MonoCallInst *call = (MonoCallInst*)ins->inst_p0; + ArgInfo *ainfo = (ArgInfo*)ins->inst_p1; + int size = ins->backend.size; + + if (ainfo->regtype == RegTypeStructByVal) { + /* + arg->ins.sreg1 = ainfo->reg; + arg->ins.opcode = OP_OUTARG_VT; + arg->size = ainfo->size; + arg->offset = ainfo->offset; + arg->offPrm = ainfo->offparm + cinfo->sz.offStruct; + */ + if (ainfo->reg != STK_BASE) { + MONO_OUTPUT_VTR2 (cfg, size, ainfo->reg, src->dreg, 0); + } else { + MONO_OUTPUT_VTS2 (cfg, size, ainfo->reg, ainfo->offset, + src->dreg, 0); + } + } else if (ainfo->regtype == RegTypeStructByValInFP) { + int dreg = mono_alloc_freg (cfg); + + if (ainfo->size == 4) { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, dreg, src->dreg, 0); + MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, dreg, dreg); + } else { + g_assert (ainfo->size == 8); + + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, dreg, src->dreg, 0); + } + + mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE); + } else { + MONO_EMIT_NEW_MOVE2 (cfg, STK_BASE, ainfo->offparm, + src->dreg, 0, size); + } +} + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_emit_setret */ +/* */ +/*------------------------------------------------------------------*/ + +void +mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) +{ + MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret); + + if (!ret->byref) { + if (ret->type == MONO_TYPE_R4) { + MONO_EMIT_NEW_UNALU (cfg, OP_S390_SETF4RET, s390_f0, val->dreg); + return; + } else if (ret->type == MONO_TYPE_R8) { + MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, s390_f0, val->dreg); + return; + } + } + + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - emit_sig_cookie. */ @@ -1997,10 +2525,8 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, arg->ins.inst_right = (MonoInst *) call; arg->size = argSize; arg->offset = cinfo->sigCookie.offset; - - /* prepend, we'll need to reverse them later */ - arg->ins.next = call->out_args; - call->out_args = (MonoInst *) arg; + arg->ins.next = call->out_args; + call->out_args = (MonoInst *) arg; } /*========================= End of Function ========================*/ @@ -2211,149 +2737,65 @@ handle_enum: /*========================= End of Function ========================*/ +void +mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) +{ +} + /*------------------------------------------------------------------*/ /* */ -/* Name - peephole_pass */ +/* Name - mono_arch_peephole_pass */ /* */ /* Function - Form a peephole pass at the code looking for */ /* simple optimizations. */ /* */ /*------------------------------------------------------------------*/ -static void -peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) +void +mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *ins, *last_ins = NULL; - ins = bb->code; + MonoInst *ins, *n; - while (ins) { + MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { + mono_peephole_ins (bb, ins); + } +} - switch (ins->opcode) { - case OP_MUL_IMM: - /* remove unnecessary multiplication with 1 */ - if (ins->inst_imm == 1) { - if (ins->dreg != ins->sreg1) { - ins->opcode = OP_MOVE; - } else { - last_ins->next = ins->next; - ins = ins->next; - continue; - } - } - break; - case OP_LOAD_MEMBASE: - case OP_LOADI4_MEMBASE: - /* - * OP_STORE_MEMBASE_REG reg, offset(basereg) - * OP_LOAD_MEMBASE offset(basereg), reg - */ - if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG - || last_ins->opcode == OP_STORE_MEMBASE_REG) && - ins->inst_basereg == last_ins->inst_destbasereg && - ins->inst_offset == last_ins->inst_offset) { - if (ins->dreg == last_ins->sreg1) { - last_ins->next = ins->next; - ins = ins->next; - continue; - } else { - ins->opcode = OP_MOVE; - ins->sreg1 = last_ins->sreg1; - } +/*========================= End of Function ========================*/ - /* - * Note: reg1 must be different from the basereg in the second load - * OP_LOAD_MEMBASE offset(basereg), reg1 - * OP_LOAD_MEMBASE offset(basereg), reg2 - * --> - * OP_LOAD_MEMBASE offset(basereg), reg1 - * OP_MOVE reg1, reg2 - */ - } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE - || last_ins->opcode == OP_LOAD_MEMBASE) && - ins->inst_basereg != last_ins->dreg && - ins->inst_basereg == last_ins->inst_basereg && - ins->inst_offset == last_ins->inst_offset) { - - if (ins->dreg == last_ins->dreg) { - last_ins->next = ins->next; - ins = ins->next; - continue; - } else { - ins->opcode = OP_MOVE; - ins->sreg1 = last_ins->dreg; - } +void +mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) +{ + MonoInst *ins, *next; - } - break; - case OP_LOADU1_MEMBASE: - case OP_LOADI1_MEMBASE: - if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) && - ins->inst_basereg == last_ins->inst_destbasereg && - ins->inst_offset == last_ins->inst_offset) { - ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1; - ins->sreg1 = last_ins->sreg1; - } - break; - case OP_LOADU2_MEMBASE: - case OP_LOADI2_MEMBASE: - if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) && - ins->inst_basereg == last_ins->inst_destbasereg && - ins->inst_offset == last_ins->inst_offset) { - ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2; - ins->sreg1 = last_ins->sreg1; - } + if (bb->max_vreg > cfg->rs->next_vreg) + cfg->rs->next_vreg = bb->max_vreg; + + MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) { + switch (ins->opcode) { + case OP_DIV_IMM: + case OP_REM_IMM: + case OP_IDIV_IMM: + case OP_IREM_IMM: + case OP_IDIV_UN_IMM: + case OP_IREM_UN_IMM: + case OP_LAND_IMM: + case OP_LOR_IMM: + case OP_LXOR_IMM: + case OP_LOCALLOC_IMM: + mono_decompose_op_imm (cfg, bb, ins); + break; + case OP_LADD_IMM: + if (!s390_is_imm16 (ins->inst_imm)) + /* This is created by the memcpy code which ignores is_inst_imm */ + mono_decompose_op_imm (cfg, bb, ins); break; - case CEE_CONV_I4: - case CEE_CONV_U4: - case OP_MOVE: - /* - * OP_MOVE reg, reg - */ - if (ins->dreg == ins->sreg1) { - if (last_ins) - last_ins->next = ins->next; - ins = ins->next; - continue; - } - /* - * OP_MOVE sreg, dreg - * OP_MOVE dreg, sreg - */ - if (last_ins && last_ins->opcode == OP_MOVE && - ins->sreg1 == last_ins->dreg && - ins->dreg == last_ins->sreg1) { - last_ins->next = ins->next; - ins = ins->next; - continue; - } + default: break; } - last_ins = ins; - ins = ins->next; } - bb->last_ins = last_ins; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_local_regalloc. */ -/* */ -/* Function - We first scan the list of instructions and we */ -/* save the liveness information of each register */ -/* (when the register is first used, when its value */ -/* is set etc.). We also reverse the list of instr- */ -/* uctions (in the InstList list) because assigning */ -/* registers backwards allows for more tricks to be */ -/* used. */ -/* */ -/*------------------------------------------------------------------*/ -void -mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb) -{ - mono_local_regalloc(cfg, bb); + bb->max_vreg = cfg->rs->next_vreg; } /*========================= End of Function ========================*/ @@ -2415,6 +2857,28 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, /*========================= End of Function ========================*/ +static gboolean is_unsigned (MonoInst *next) +{ + if ((next) && + (((next->opcode >= OP_IBNE_UN) && + (next->opcode <= OP_IBLT_UN)) || + ((next->opcode >= OP_LBNE_UN) && + (next->opcode <= OP_LBLT_UN)) || + ((next->opcode >= OP_COND_EXC_NE_UN) && + (next->opcode <= OP_COND_EXC_LT_UN)) || + ((next->opcode >= OP_COND_EXC_INE_UN) && + (next->opcode <= OP_COND_EXC_ILT_UN)) || + ((next->opcode == OP_CLT_UN) || + (next->opcode == OP_CGT_UN)) || + ((next->opcode == OP_ICLT_UN) || + (next->opcode == OP_ICGT_UN) || + (next->opcode == OP_LCLT_UN) || + (next->opcode == OP_LCGT_UN)))) + return TRUE; + else + return FALSE; +} + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_output_basic_block */ @@ -2431,13 +2895,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) MonoCallInst *call; guint offset; guint8 *code = cfg->native_code + cfg->code_len; - MonoInst *last_ins = NULL; guint last_offset = 0; int max_len, cpos, src2; - if (cfg->opt & MONO_OPT_PEEPHOLE) - peephole_pass (cfg, bb); - /* we don't align basic blocks of loops on s390 */ if (cfg->verbose_level > 2) @@ -2456,8 +2916,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) //x86_inc_mem (code, &cov->data [bb->dfn].count); } - ins = bb->code; - while (ins) { + MONO_BB_FOR_EACH_INS (bb, ins) { offset = code - cfg->native_code; max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; @@ -2531,23 +2990,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_destbasereg, ins->inst_offset); } break; - case CEE_LDIND_I: - case CEE_LDIND_I4: { - s390_basr (code, s390_r13, 0); - s390_j (code, 6); - s390_llong(code, ins->inst_p0); - s390_lg (code, s390_r13, 0, s390_r13, 4); - s390_lgf (code, ins->dreg, 0, s390_r13, 0); - } - break; - case CEE_LDIND_U4: { - s390_basr (code, s390_r13, 0); - s390_j (code, 6); - s390_llong(code, ins->inst_p0); - s390_lg (code, s390_r13, 0, s390_r13, 4); - s390_llgf (code, ins->dreg, 0, s390_r13, 0); - } - break; case OP_LOADU4_MEM: g_assert_not_reached (); break; @@ -2587,7 +3029,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_basereg, ins->inst_offset); } break; - case CEE_CONV_I1: { + case OP_LCONV_TO_I1: { s390_lghi (code, s390_r0, 0x80); if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2599,7 +3041,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ogr (code, ins->dreg, s390_r13); } break; - case CEE_CONV_I2: { + case OP_LCONV_TO_I2: { s390_lghi (code, s390_r0, 0x80); s390_sllg (code, s390_r0, s390_r0, 0, 8); if (ins->dreg != ins->sreg1) { @@ -2612,7 +3054,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ogr (code, ins->dreg, s390_r13); } break; - case CEE_CONV_U1: { + case OP_LCONV_TO_U1: { s390_lghi (code, s390_r0, 0xff); if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2620,7 +3062,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ngr (code, ins->dreg, s390_r0); } break; - case CEE_CONV_U2: { + case OP_LCONV_TO_U2: { s390_lghi (code, s390_r0, -1); s390_sllg (code, s390_r0, s390_r0, 0, 16); s390_srlg (code, s390_r0, s390_r0, 0, 16); @@ -2630,49 +3072,87 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ngr (code, ins->dreg, s390_r0); } break; + case OP_ICONV_TO_I1: { + s390_lhi (code, s390_r0, 0x80); + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } + s390_nr (code, s390_r0, ins->sreg1); + s390_jz (code, 7); + s390_lhi (code, s390_r13, -1); + s390_sll (code, s390_r13, 0, 8); + s390_or (code, ins->dreg, s390_r13); + } + break; + case OP_ICONV_TO_I2: { + s390_lhi (code, s390_r0, 0x80); + s390_sll (code, s390_r0, 0, 8); + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } + s390_nr (code, s390_r0, ins->sreg1); + s390_jz (code, 7); + s390_lhi (code, s390_r13, -1); + s390_sll (code, s390_r13, 0, 16); + s390_or (code, ins->dreg, s390_r13); + } + break; + case OP_ICONV_TO_U1: { + s390_lhi (code, s390_r0, 0xff); + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } + s390_nr (code, ins->dreg, s390_r0); + } + break; + case OP_ICONV_TO_U2: { + s390_lhi (code, s390_r0, -1); + s390_sll (code, s390_r0, 0, 16); + s390_srl (code, s390_r0, 0, 16); + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } + s390_nr (code, ins->dreg, s390_r0); + } + break; case OP_COMPARE: case OP_LCOMPARE: { - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) + if (is_unsigned (ins->next)) s390_clgr (code, ins->sreg1, ins->sreg2); else s390_cgr (code, ins->sreg1, ins->sreg2); } break; - case OP_COMPARE_IMM: { + case OP_ICOMPARE: { + if (is_unsigned (ins->next)) + s390_clr (code, ins->sreg1, ins->sreg2); + else + s390_cr (code, ins->sreg1, ins->sreg2); + } + break; + case OP_COMPARE_IMM: + case OP_LCOMPARE_IMM: { if (s390_is_imm16 (ins->inst_imm)) { s390_lghi (code, s390_r0, ins->inst_imm); - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) + if (is_unsigned (ins->next)) s390_clgr (code, ins->sreg1, s390_r0); else s390_cgr (code, ins->sreg1, s390_r0); - } - else { + } else { s390_basr (code, s390_r13, 0); s390_j (code, 6); s390_llong(code, ins->inst_imm); - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) + if (is_unsigned (ins->next)) s390_clg (code, ins->sreg1, 0, s390_r13, 4); else s390_cg (code, ins->sreg1, 0, s390_r13, 4); } } break; - case OP_ICOMPARE: { - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) - s390_clr (code, ins->sreg1, ins->sreg2); - else - s390_cr (code, ins->sreg1, ins->sreg2); - } - break; case OP_ICOMPARE_IMM: { if (s390_is_imm16 (ins->inst_imm)) { s390_lghi (code, s390_r0, ins->inst_imm); - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) + if (is_unsigned (ins->next)) s390_clr (code, ins->sreg1, s390_r0); else s390_cr (code, ins->sreg1, s390_r0); @@ -2681,30 +3161,29 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_basr (code, s390_r13, 0); s390_j (code, 4); s390_word (code, ins->inst_imm); - if ((ins->next) && - (opcode_to_cond(ins->next->opcode) >= CMP_LE_UN)) + if (is_unsigned (ins->next)) s390_cl (code, ins->sreg1, 0, s390_r13, 4); else s390_c (code, ins->sreg1, 0, s390_r13, 4); } } break; - case CEE_BREAK: { + case OP_BREAK: { s390_basr (code, s390_r13, 0); s390_j (code, 6); - mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, - mono_arch_break); - s390_llong (code, mono_arch_break); + mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_ABS, + mono_break); + s390_llong (code, mono_break); s390_lg (code, s390_r14, 0, s390_r13, 4); s390_basr (code, s390_r14, s390_r14); } break; case OP_ADDCC: { CHECK_SRCDST_COM; - s390_algr (code, ins->dreg, src2); + s390_agr (code, ins->dreg, src2); } break; - case CEE_ADD: { + case OP_LADD: { CHECK_SRCDST_COM; s390_agr (code, ins->dreg, src2); } @@ -2728,6 +3207,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; + case OP_LADD_IMM: { + if (ins->dreg != ins->sreg1) { + s390_lgr (code, ins->dreg, ins->sreg1); + } + g_assert (s390_is_imm16 (ins->inst_imm)); + s390_aghi (code, ins->dreg, ins->inst_imm); + } + break; case OP_ADC_IMM: { if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2744,16 +3231,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_LADD_OVF: { + case OP_IADD_OVF: + case OP_S390_IADD_OVF: { CHECK_SRCDST_COM; - s390_agr (code, ins->dreg, src2); + s390_ar (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + s390_lgfr (code, ins->dreg, ins->dreg); } break; - case OP_LADD_OVF_UN: { + case OP_IADD_OVF_UN: + case OP_S390_IADD_OVF_UN: { CHECK_SRCDST_COM; s390_algr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException"); + s390_llgfr (code, ins->dreg, ins->dreg); } break; case OP_ADD_OVF_CARRY: { @@ -2775,10 +3266,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_SUBCC: { CHECK_SRCDST_NCOM; - s390_slgr (code, ins->dreg, src2); + s390_sgr (code, ins->dreg, src2); } break; - case CEE_SUB: { + case OP_LSUB: { CHECK_SRCDST_NCOM; s390_sgr (code, ins->dreg, src2); } @@ -2803,6 +3294,21 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; + case OP_LSUB_IMM: { + if (ins->dreg != ins->sreg1) { + s390_lgr (code, ins->dreg, ins->sreg1); + } + if (s390_is_imm16 (-ins->inst_imm)) { + s390_lghi (code, s390_r0, ins->inst_imm); + s390_slgr (code, ins->dreg, s390_r0); + } else { + s390_basr (code, s390_r13, 0); + s390_j (code, 6); + s390_llong(code, ins->inst_imm); + s390_slg (code, ins->dreg, 0, s390_r13, 4); + } + } + break; case OP_SBB_IMM: { if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); @@ -2818,18 +3324,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_LSUB_OVF: { - CHECK_SRCDST_NCOM; - s390_sgr (code, ins->dreg, src2); - EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); - } - break; - case OP_LSUB_OVF_UN: { - CHECK_SRCDST_NCOM; - s390_slgr (code, ins->dreg, src2); - EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException"); - } - break; case OP_SUB_OVF_CARRY: { CHECK_SRCDST_NCOM; s390_lghi (code, s390_r0, 0); @@ -2847,7 +3341,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException"); } break; - case CEE_AND: { + case OP_LAND: { if (ins->sreg1 == ins->dreg) { s390_ngr (code, ins->dreg, ins->sreg2); } @@ -2890,21 +3384,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgr (code, ins->dreg, s390_r1); } break; - case OP_DIV_IMM: { - if (s390_is_imm16 (ins->inst_imm)) { - s390_lghi (code, s390_r13, ins->inst_imm); - s390_lgr (code, s390_r1, ins->sreg1); - } else { - s390_basr (code, s390_r13, 0); - s390_j (code, 6); - s390_llong(code, ins->inst_imm); - s390_lgr (code, s390_r1, ins->sreg1); - s390_lg (code, s390_r13, 0, s390_r13, 4); - } - s390_dsgr (code, s390_r0, s390_r13); - s390_lgr (code, ins->dreg, s390_r1); - } - break; case OP_LREM: { s390_lgr (code, s390_r1, ins->sreg1); s390_dsgr (code, s390_r0, ins->sreg2); @@ -2918,22 +3397,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgr (code, ins->dreg, s390_r0); } break; - case OP_REM_IMM: { - if (s390_is_imm16 (ins->inst_imm)) { - s390_lghi (code, s390_r13, ins->inst_imm); - s390_lgr (code, s390_r0, ins->sreg1); - } else { - s390_basr (code, s390_r13, 0); - s390_j (code, 6); - s390_llong(code, ins->inst_imm); - s390_lgr (code, s390_r0, ins->sreg1); - s390_lg (code, s390_r13, 0, s390_r13, 4); - } - s390_dsgr(code, s390_r0, s390_r13); - s390_lgr (code, ins->dreg, s390_r0); - } - break; - case CEE_OR: { + case OP_LOR: { if (ins->sreg1 == ins->dreg) { s390_ogr (code, ins->dreg, ins->sreg2); } @@ -2963,7 +3427,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_XOR: { + case OP_LXOR: { if (ins->sreg1 == ins->dreg) { s390_xgr (code, ins->dreg, ins->sreg2); } @@ -2993,7 +3457,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_SHL: case OP_LSHL: { CHECK_SRCDST_NCOM; s390_sllg (code, ins->dreg, ins->dreg, src2, 0); @@ -3007,7 +3470,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_sllg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f)); } break; - case CEE_SHR: case OP_LSHR: { CHECK_SRCDST_NCOM; s390_srag (code, ins->dreg, ins->dreg, src2, 0); @@ -3029,13 +3491,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_srlg (code, ins->dreg, ins->dreg, 0, (ins->inst_imm & 0x3f)); } break; - case CEE_SHR_UN: case OP_LSHR_UN: { CHECK_SRCDST_NCOM; s390_srlg (code, ins->dreg, ins->dreg, src2, 0); } break; - case CEE_NOT: { + case OP_LNOT: { if (ins->sreg1 != ins->dreg) { s390_lgr (code, ins->dreg, ins->sreg1); } @@ -3043,11 +3504,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_xgr (code, ins->dreg, s390_r0); } break; - case CEE_NEG: { + case OP_LNEG: { s390_lcgr (code, ins->dreg, ins->sreg1); } break; - case CEE_MUL: case OP_LMUL: { CHECK_SRCDST_COM; s390_msgr (code, ins->dreg, src2); @@ -3069,8 +3529,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_msgr (code, ins->dreg, s390_r13); } break; - case OP_LMUL_OVF: - case CEE_MUL_OVF: { + case OP_LMUL_OVF: { short int *o[2]; s390_ltgr (code, s390_r1, ins->sreg1); s390_jz (code, 0); CODEPTR(code, o[0]); @@ -3089,8 +3548,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lgr (code, ins->dreg, s390_r1); } break; - case OP_LMUL_OVF_UN: - case CEE_MUL_OVF_UN: { + case OP_LMUL_OVF_UN: { s390_lghi (code, s390_r0, 0); s390_lgr (code, s390_r1, ins->sreg1); s390_mlgr (code, s390_r0, ins->sreg2); @@ -3146,18 +3604,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_ADD_OVF: { + case OP_LADD_OVF: + case OP_S390_LADD_OVF: { CHECK_SRCDST_COM; - s390_ar (code, ins->dreg, src2); + s390_agr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); - s390_lgfr (code, ins->dreg, ins->dreg); } break; - case CEE_ADD_OVF_UN: { + case OP_LADD_OVF_UN: + case OP_S390_LADD_OVF_UN: { CHECK_SRCDST_COM; s390_algr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException"); - s390_llgfr (code, ins->dreg, ins->dreg); } break; case OP_ISUBCC: { @@ -3196,20 +3654,36 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_slgf (code, ins->dreg, 0, s390_r13, 4); } break; - case CEE_SUB_OVF: { + case OP_ISUB_OVF: + case OP_S390_ISUB_OVF: { CHECK_SRCDST_NCOM; s390_sr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); s390_lgfr (code, ins->dreg, ins->dreg); } break; - case CEE_SUB_OVF_UN: { + case OP_ISUB_OVF_UN: + case OP_S390_ISUB_OVF_UN: { CHECK_SRCDST_NCOM; s390_slr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException"); s390_llgfr(code, ins->dreg, ins->dreg); } break; + case OP_LSUB_OVF: + case OP_S390_LSUB_OVF: { + CHECK_SRCDST_NCOM; + s390_sgr (code, ins->dreg, src2); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + } + break; + case OP_LSUB_OVF_UN: + case OP_S390_LSUB_OVF_UN: { + CHECK_SRCDST_NCOM; + s390_slgr (code, ins->dreg, src2); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException"); + } + break; case OP_IAND: { CHECK_SRCDST_NCOM_I; s390_ngr (code, ins->dreg, src2); @@ -3330,10 +3804,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_ISHL: { - if (ins->sreg1 != ins->dreg) { - s390_lgfr (code, ins->dreg, ins->sreg1); - } - s390_sll (code, ins->dreg, ins->sreg2, 0); + CHECK_SRCDST_NCOM; + s390_sll (code, ins->dreg, src2, 0); } break; case OP_ISHL_IMM: { @@ -3344,10 +3816,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_ISHR: { - if (ins->sreg1 != ins->dreg) { - s390_lgfr (code, ins->dreg, ins->sreg1); - } - s390_sra (code, ins->dreg, ins->sreg2, 0); + CHECK_SRCDST_NCOM; + s390_sra (code, ins->dreg, src2, 0); } break; case OP_ISHR_IMM: { @@ -3365,10 +3835,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_ISHR_UN: { - if (ins->sreg1 != ins->dreg) { - s390_lgfr (code, ins->dreg, ins->sreg1); - } - s390_srl (code, ins->dreg, ins->sreg2, 0); + CHECK_SRCDST_NCOM; + s390_srl (code, ins->dreg, src2, 0); } break; case OP_INOT: { @@ -3432,8 +3900,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_ICONST: - case OP_I8CONST: - case OP_SETREGIMM: { + case OP_I8CONST: { if (s390_is_imm16(ins->inst_c0)) { s390_lghi (code, ins->dreg, ins->inst_c0); } else { @@ -3453,24 +3920,35 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lg (code,ins->dreg, 0, s390_r13, 4); } break; - case CEE_CONV_I: - case CEE_CONV_I8: + case OP_JUMP_TABLE: { + mono_add_patch_info (cfg, code - cfg->native_code, + (MonoJumpInfoType)ins->inst_i1, ins->inst_p0); + s390_basr (code, s390_r13, 0); + s390_j (code, 6); + s390_llong (code, 0); + s390_lg (code, ins->dreg, 0, s390_r13, 4); + } + break; case OP_MOVE: - case OP_SETREG: { if (ins->dreg != ins->sreg1) { s390_lgr (code, ins->dreg, ins->sreg1); } - } break; - case CEE_CONV_I4: + case OP_LCONV_TO_I: + case OP_LCONV_TO_I8: + case OP_SEXT_I4: + s390_lgfr (code, ins->dreg, ins->sreg1); + break; + case OP_LCONV_TO_I4: s390_lgfr (code, ins->dreg, ins->sreg1); break; - case CEE_CONV_U: - case CEE_CONV_U8: - case CEE_CONV_U4: + case OP_LCONV_TO_U: + case OP_LCONV_TO_U8: + case OP_LCONV_TO_U4: + case OP_ZEXT_I4: s390_llgfr (code, ins->dreg, ins->sreg1); break; - case CEE_CONV_OVF_U4: + case OP_LCONV_TO_OVF_U4: s390_basr (code, s390_r13, 0); s390_j (code, 6); s390_llong(code, 4294967295); @@ -3480,7 +3958,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException"); s390_llgfr(code, ins->dreg, ins->sreg1); break; - case CEE_CONV_OVF_I4_UN: + case OP_LCONV_TO_OVF_I4_UN: s390_basr (code, s390_r13, 0); s390_j (code, 6); s390_llong(code, 2147483647); @@ -3490,8 +3968,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException"); s390_lgfr (code, ins->dreg, ins->sreg1); break; - case OP_SETFREG: - case OP_FMOVE: { + case OP_FMOVE: + case OP_FCONV_TO_R4: { if (ins->dreg != ins->sreg1) { s390_ldr (code, ins->dreg, ins->sreg1); } @@ -3501,20 +3979,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ledbr (code, ins->dreg, ins->sreg1); } break; - case OP_FCONV_TO_R4: { - g_error ("Shouldn't be reached"); - if ((ins->next) && - (ins->next->opcode != OP_FMOVE) && - (ins->next->opcode != OP_STORER4_MEMBASE_REG)) - s390_ledbr (code, ins->dreg, ins->sreg1); - } - break; - case CEE_JMP: { + case OP_JMP: { if (cfg->method->save_lmf) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); if (cfg->flags & MONO_CFG_HAS_TAIL) { - code = emit_load_volatile_registers(code, cfg); + code = emit_load_volatile_arguments (code, cfg); } code = backUpStackPtr(cfg, code); @@ -3567,8 +4037,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LCALL: case OP_VCALL: + case OP_VCALL2: case OP_VOIDCALL: - case CEE_CALL: { + case OP_CALL: { s390_basr (code, s390_r13, 0); s390_j (code, 6); call = (MonoCallInst*)ins; @@ -3595,6 +4066,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LCALL_REG: case OP_VCALL_REG: + case OP_VCALL2_REG: case OP_VOIDCALL_REG: case OP_CALL_REG: { s390_lgr (code, s390_r1, ins->sreg1); @@ -3611,6 +4083,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_LCALL_MEMBASE: case OP_VCALL_MEMBASE: + case OP_VCALL2_MEMBASE: case OP_VOIDCALL_MEMBASE: case OP_CALL_MEMBASE: { s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset); @@ -3636,7 +4109,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) int lmfOffset = cfg->stack_usage - sizeof(MonoLMF); s390_lgr (code, s390_r13, cfg->frame_reg); - if (s390_is_uimm16(lmfOffset)) + if (s390_is_imm16(lmfOffset)) s390_aghi (code, s390_r13, lmfOffset); else { s390_basr (code, s390_r14, 0); @@ -3666,11 +4139,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_RET: { - s390_br (code, s390_r14); - } - break; - case CEE_THROW: { + case OP_THROW: { s390_lgr (code, s390_r2, ins->sreg1); s390_basr (code, s390_r13, 0); s390_j (code, 6); @@ -3693,24 +4162,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_START_HANDLER: { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); + S390_LONG (code, stg, stg, s390_r14, 0, - ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + spvar->inst_basereg, + spvar->inst_offset); } break; case OP_ENDFILTER: { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); + if (ins->sreg1 != s390_r2) s390_lgr(code, s390_r2, ins->sreg1); S390_LONG (code, lg, lg, s390_r14, 0, - ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + spvar->inst_basereg, + spvar->inst_offset); s390_br (code, s390_r14); } break; - case CEE_ENDFINALLY: { + case OP_ENDFINALLY: { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); + S390_LONG (code, lg, lg, s390_r14, 0, - ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + spvar->inst_basereg, + spvar->inst_offset); s390_br (code, s390_r14); } break; @@ -3724,7 +4199,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_c0 = code - cfg->native_code; } break; - case CEE_BR: + case OP_NOP: + case OP_DUMMY_USE: + case OP_DUMMY_STORE: + case OP_NOT_REACHED: + case OP_NOT_NULL: { + } + break; + case OP_BR: EMIT_UNCOND_BRANCH(ins); break; case OP_BR_REG: { @@ -3732,102 +4214,121 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_CEQ: - case OP_ICEQ: { + case OP_ICEQ: + case OP_LCEQ: { s390_lghi(code, ins->dreg, 1); s390_jz (code, 4); s390_lghi(code, ins->dreg, 0); } break; case OP_CLT: - case OP_ICLT: { + case OP_ICLT: + case OP_LCLT: { s390_lghi(code, ins->dreg, 1); s390_jl (code, 4); s390_lghi(code, ins->dreg, 0); } break; case OP_CLT_UN: - case OP_ICLT_UN: { + case OP_ICLT_UN: + case OP_LCLT_UN: { s390_lghi(code, ins->dreg, 1); s390_jlo (code, 4); s390_lghi(code, ins->dreg, 0); } break; case OP_CGT: - case OP_ICGT: { + case OP_ICGT: + case OP_LCGT: { s390_lghi(code, ins->dreg, 1); s390_jh (code, 4); s390_lghi(code, ins->dreg, 0); } break; case OP_CGT_UN: - case OP_ICGT_UN: { + case OP_ICGT_UN: + case OP_LCGT_UN: { s390_lghi(code, ins->dreg, 1); s390_jho (code, 4); s390_lghi(code, ins->dreg, 0); } break; case OP_COND_EXC_EQ: + case OP_COND_EXC_IEQ: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_EQ, ins->inst_p1); break; case OP_COND_EXC_NE_UN: + case OP_COND_EXC_INE_UN: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NE, ins->inst_p1); break; case OP_COND_EXC_LT: + case OP_COND_EXC_ILT: case OP_COND_EXC_LT_UN: + case OP_COND_EXC_ILT_UN: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, ins->inst_p1); break; case OP_COND_EXC_GT: + case OP_COND_EXC_IGT: case OP_COND_EXC_GT_UN: + case OP_COND_EXC_IGT_UN: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GT, ins->inst_p1); break; case OP_COND_EXC_GE: + case OP_COND_EXC_IGE: case OP_COND_EXC_GE_UN: + case OP_COND_EXC_IGE_UN: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_GE, ins->inst_p1); break; case OP_COND_EXC_LE: + case OP_COND_EXC_ILE: case OP_COND_EXC_LE_UN: + case OP_COND_EXC_ILE_UN: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LE, ins->inst_p1); break; case OP_COND_EXC_OV: + case OP_COND_EXC_IOV: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, ins->inst_p1); break; case OP_COND_EXC_NO: + case OP_COND_EXC_INO: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NO, ins->inst_p1); break; case OP_COND_EXC_C: + case OP_COND_EXC_IC: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, ins->inst_p1); break; case OP_COND_EXC_NC: + case OP_COND_EXC_INC: EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, ins->inst_p1); break; - case CEE_BEQ: + case OP_LBEQ: case OP_IBEQ: EMIT_COND_BRANCH (ins, S390_CC_EQ); break; - case CEE_BNE_UN: + case OP_LBNE_UN: case OP_IBNE_UN: EMIT_COND_BRANCH (ins, S390_CC_NE); break; - case CEE_BLT: - case CEE_BLT_UN: + case OP_LBLT: + case OP_LBLT_UN: case OP_IBLT: case OP_IBLT_UN: EMIT_COND_BRANCH (ins, S390_CC_LT); break; - case CEE_BGT: - case CEE_BGT_UN: + case OP_LBGT: + case OP_LBGT_UN: case OP_IBGT: case OP_IBGT_UN: EMIT_COND_BRANCH (ins, S390_CC_GT); break; - case CEE_BGE: - case CEE_BGE_UN: + case OP_LBGE: + case OP_LBGE_UN: case OP_IBGE: case OP_IBGE_UN: EMIT_COND_BRANCH (ins, S390_CC_GE); break; - case CEE_BLE: - case CEE_BLE_UN: + case OP_LBLE: + case OP_LBLE_UN: case OP_IBLE: case OP_IBLE_UN: EMIT_COND_BRANCH (ins, S390_CC_LE); @@ -3880,7 +4381,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ldebr (code, ins->dreg, s390_f15); } break; - case CEE_CONV_R_UN: { + case OP_ICONV_TO_R_UN: { + s390_cdfbr (code, ins->dreg, ins->sreg1); + s390_ltr (code, ins->sreg1, ins->sreg1); + s390_jnl (code, 12); + s390_basr (code, s390_r13, 0); + s390_j (code, 6); + s390_word (code, 0x41f00000); + s390_word (code, 0); + s390_adb (code, ins->dreg, 0, s390_r13, 4); + } + break; + case OP_LCONV_TO_R_UN: { s390_cdgbr (code, ins->dreg, ins->sreg1); s390_ltgr (code, ins->sreg1, ins->sreg1); s390_jnl (code, 12); @@ -3891,13 +4403,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_adb (code, ins->dreg, 0, s390_r13, 4); } break; - case OP_LCONV_TO_R4: - case CEE_CONV_R4: { + case OP_LCONV_TO_R4: + case OP_ICONV_TO_R4: { s390_cdgbr (code, ins->dreg, ins->sreg1); } break; - case OP_LCONV_TO_R8: - case CEE_CONV_R8: { + case OP_LCONV_TO_R8: + case OP_ICONV_TO_R8: { s390_cdgbr (code, ins->dreg, ins->sreg1); } break; @@ -3924,14 +4436,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FCONV_TO_I8: s390_cgdbr (code, ins->dreg, 5, ins->sreg1); break; - case OP_FCONV_TO_U8: - g_assert_not_reached (); - /* Implemented as helper calls */ - break; - case OP_LCONV_TO_R_UN: - g_assert_not_reached (); - /* Implemented as helper calls */ - break; case OP_LCONV_TO_OVF_I: { /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */ short int *o[5]; @@ -4082,7 +4586,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_FBLE_UN: EMIT_COND_BRANCH (ins, S390_CC_LE|S390_CC_OV); break; - case CEE_CKFINITE: { + case OP_CKFINITE: { short *o; s390_lhi (code, s390_r13, 0x7f); s390_tcdb (code, ins->sreg1, 0, s390_r13, 0); @@ -4203,10 +4707,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos += max_len; - last_ins = ins; last_offset = offset; - - ins = ins->next; } cfg->code_len = code - cfg->native_code; @@ -4225,26 +4726,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) void mono_arch_register_lowlevel_calls (void) { - mono_register_jit_icall (mono_arch_break, "mono_arch_break", NULL, TRUE); mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr", NULL, TRUE); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_break */ -/* */ -/* Function - Process a "break" operation for debugging. */ -/* */ -/*------------------------------------------------------------------*/ - -static void -mono_arch_break(void) { -} - -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_patch_code */ @@ -4314,7 +4800,7 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, /*------------------------------------------------------------------*/ /* */ -/* Name - emit_load_volatile_registers */ +/* Name - emit_load_volatile_arguments */ /* */ /* Function - Emit the instructions to reload parameter regist- */ /* registers for use with "tail" operations. */ @@ -4327,26 +4813,25 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, /*------------------------------------------------------------------*/ guint8 * -emit_load_volatile_registers (guint8 *code, MonoCompile *cfg) +emit_load_volatile_arguments (guint8 *code, MonoCompile *cfg) { MonoInst *inst; MonoMethod *method = cfg->method; MonoMethodSignature *sig = mono_method_signature(method); int pos = 0, i; CallInfo *cinfo; - size_data sz; - cinfo = calculate_sizes (sig, &sz, sig->pinvoke); + cinfo = get_call_info (NULL, NULL, sig, sig->pinvoke); if (cinfo->struct_ret) { ArgInfo *ainfo = &cinfo->ret; - inst = cfg->ret; + inst = cfg->vret_addr; s390_lg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); } for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; - inst = cfg->varinfo [pos]; + inst = cfg->args [pos]; if (inst->opcode == OP_REGVAR) { if (ainfo->regtype == RegTypeGeneral) @@ -4416,8 +4901,6 @@ emit_load_volatile_registers (guint8 *code, MonoCompile *cfg) pos++; } - g_free (cinfo); - return code; } @@ -4442,7 +4925,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) int alloc_size, pos, max_offset, i; guint8 *code; CallInfo *cinfo; - size_data sz; int tracing = 0; int lmfOffset; @@ -4460,6 +4942,9 @@ mono_arch_emit_prolog (MonoCompile *cfg) s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + if (cfg->arch.bkchain_reg != -1) + s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE); + if (cfg->flags & MONO_CFG_HAS_ALLOCA) { cfg->used_int_regs |= 1 << 11; } @@ -4468,7 +4953,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) cfg->stack_usage = alloc_size; s390_lgr (code, s390_r11, STK_BASE); - if (s390_is_uimm16 (alloc_size)) { + if (s390_is_imm16 (alloc_size)) { s390_aghi (code, STK_BASE, -alloc_size); } else { int stackSize = alloc_size; @@ -4489,34 +4974,35 @@ mono_arch_emit_prolog (MonoCompile *cfg) */ max_offset = 0; for (bb = cfg->bb_entry; bb; bb = bb->next_bb) { - MonoInst *ins = bb->code; + MonoInst *ins; bb->max_offset = max_offset; if (cfg->prof_options & MONO_PROFILE_COVERAGE) max_offset += 6; - while (ins) { + MONO_BB_FOR_EACH_INS (bb, ins) max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; - ins = ins->next; - } } /* load arguments allocated to register from the stack */ sig = mono_method_signature (method); pos = 0; - cinfo = calculate_sizes (sig, &sz, sig->pinvoke); + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); if (cinfo->struct_ret) { ArgInfo *ainfo = &cinfo->ret; - inst = cfg->ret; + inst = cfg->vret_addr; inst->backend.size = ainfo->vtsize; s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); } for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; - inst = cfg->varinfo [pos]; + inst = cfg->args [pos]; + + if (inst->opcode == OP_VTARG_ADDR) + inst = inst->inst_left; if (inst->opcode == OP_REGVAR) { if (ainfo->regtype == RegTypeGeneral) @@ -4695,8 +5181,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) cfg->code_len = code - cfg->native_code; g_assert (cfg->code_len < cfg->code_size); - g_free (cinfo); - return code; } @@ -4841,7 +5325,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) /*---------------------------------------------*/ /* Load return address & parameter register */ /*---------------------------------------------*/ - s390_larl (code, s390_r14, S390_RELATIVE((patch_info->ip.i + + s390_larl (code, s390_r14, (guint64)S390_RELATIVE((patch_info->ip.i + cfg->native_code + 8), code)); s390_lg (code, s390_r2, 0, s390_r13, 4); /*---------------------------------------------*/ @@ -4951,7 +5435,7 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re /* add the this argument */ if (this_reg != -1) { MonoInst *this; - MONO_INST_NEW (cfg, this, OP_SETREG); + MONO_INST_NEW (cfg, this, OP_MOVE); this->type = this_type; this->sreg1 = this_reg; this->dreg = mono_regstate_next_int (cfg->rs); @@ -4961,7 +5445,7 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re if (vt_reg != -1) { MonoInst *vtarg; - MONO_INST_NEW (cfg, vtarg, OP_SETREG); + MONO_INST_NEW (cfg, vtarg, OP_MOVE); vtarg->type = STACK_MP; vtarg->sreg1 = vt_reg; vtarg->dreg = mono_regstate_next_int (cfg->rs); @@ -4996,84 +5480,62 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, // MONO_INST_NEW (cfg, ins, OP_ABS); // ins->inst_i0 = args [0]; // } - } else if (cmethod->klass == mono_defaults.thread_class && - strcmp (cmethod->name, "MemoryBarrier") == 0) { - MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER); - } else if(cmethod->klass->image == mono_defaults.corlib && - (strcmp (cmethod->klass->name_space, "System.Threading") == 0) && - (strcmp (cmethod->klass->name, "Interlocked") == 0)) { - - if (strcmp (cmethod->name, "Increment") == 0) { - MonoInst *ins_iconst; - guint32 opcode = 0; - - if (fsig->params [0]->type == MONO_TYPE_I4) - opcode = OP_ATOMIC_ADD_NEW_I4; - else if (fsig->params [0]->type == MONO_TYPE_I8) - opcode = OP_ATOMIC_ADD_NEW_I8; - else - g_assert_not_reached (); - - MONO_INST_NEW (cfg, ins, opcode); - MONO_INST_NEW (cfg, ins_iconst, OP_ICONST); - ins_iconst->inst_c0 = 1; + } - ins->inst_i0 = args [0]; - ins->inst_i1 = ins_iconst; - } else if (strcmp (cmethod->name, "Decrement") == 0) { - MonoInst *ins_iconst; - guint32 opcode = 0; - - if (fsig->params [0]->type == MONO_TYPE_I4) - opcode = OP_ATOMIC_ADD_NEW_I4; - else if (fsig->params [0]->type == MONO_TYPE_I8) - opcode = OP_ATOMIC_ADD_NEW_I8; - else - g_assert_not_reached (); - MONO_INST_NEW (cfg, ins, opcode); - MONO_INST_NEW (cfg, ins_iconst, OP_ICONST); - ins_iconst->inst_c0 = -1; + return ins; +} - ins->inst_i0 = args [0]; - ins->inst_i1 = ins_iconst; - /* FIXME: */ - } else if (strcmp (cmethod->name, "Exchange") == 0) { - guint32 opcode = 0; - - if (fsig->params [0]->type == MONO_TYPE_I4) - opcode = OP_ATOMIC_EXCHANGE_I4; - else if ((fsig->params [0]->type == MONO_TYPE_I8) || - (fsig->params [0]->type == MONO_TYPE_I) || - (fsig->params [0]->type == MONO_TYPE_OBJECT)) - opcode = OP_ATOMIC_EXCHANGE_I8; - else - return NULL; +/*========================= End of Function ========================*/ - MONO_INST_NEW (cfg, ins, opcode); +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_emit_inst_for_method */ +/* */ +/*------------------------------------------------------------------*/ - ins->inst_i0 = args [0]; - ins->inst_i1 = args [1]; - } else if (strcmp (cmethod->name, "Add") == 0) { - guint32 opcode = 0; - - if (fsig->params [0]->type == MONO_TYPE_I4) - opcode = OP_ATOMIC_ADD_I4; - else if (fsig->params [0]->type == MONO_TYPE_I8) - opcode = OP_ATOMIC_ADD_I8; - else - g_assert_not_reached (); +MonoInst* +mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) +{ + return NULL; +} - MONO_INST_NEW (cfg, ins, opcode); +/*========================= End of Function ========================*/ - ins->inst_i0 = args [0]; - ins->inst_i1 = args [1]; - } else if ((strcmp (cmethod->name, "Read") == 0 && - (fsig->params [0]->type == MONO_TYPE_I8))) { - MONO_INST_NEW (cfg, ins, CEE_LDIND_I8); - ins->inst_i0 = args [0]; - } +void +mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) +{ + /* + * Have to rename these to avoid being decomposed normally, since the normal + * decomposition does not work on S390. + */ + switch (ins->opcode) { + case OP_ISUB_OVF: + ins->opcode = OP_S390_ISUB_OVF; + break; + case OP_ISUB_OVF_UN: + ins->opcode = OP_S390_ISUB_OVF_UN; + break; + case OP_IADD_OVF: + ins->opcode = OP_S390_IADD_OVF; + break; + case OP_IADD_OVF_UN: + ins->opcode = OP_S390_IADD_OVF_UN; + break; + case OP_LADD_OVF: + ins->opcode = OP_S390_LADD_OVF; + break; + case OP_LADD_OVF_UN: + ins->opcode = OP_S390_LADD_OVF_UN; + break; + case OP_LSUB_OVF: + ins->opcode = OP_S390_LSUB_OVF; + break; + case OP_LSUB_OVF_UN: + ins->opcode = OP_S390_LSUB_OVF_UN; + break; + default: + break; } - return ins; } /*========================= End of Function ========================*/ @@ -5265,94 +5727,6 @@ mono_arch_is_inst_imm (gint64 imm) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - opcode_to_cond */ -/* */ -/* Function - Simplify the branch on condition opcode from */ -/* more than 20 to just a handful for easy manipu- */ -/* lation within the instruction emitting code. */ -/* */ -/* Returns - CMP_xxx - this simplified condition type. */ -/* */ -/*------------------------------------------------------------------*/ - -static CompRelation -opcode_to_cond (int opcode) -{ - switch (opcode) { - case CEE_BEQ: - case OP_CEQ: - case OP_IBEQ: - case OP_ICEQ: - case OP_FBEQ: - case OP_FCEQ: - case OP_COND_EXC_EQ: - return CMP_EQ; - case CEE_BNE_UN: - case OP_COND_EXC_NE_UN: - case OP_IBNE_UN: - case OP_FBNE_UN: - return CMP_NE; - case CEE_BLE: - case OP_IBLE: - case OP_FBLE: - return CMP_LE; - case CEE_BGE: - case OP_IBGE: - case OP_FBGE: - return CMP_GE; - case CEE_BLT: - case OP_COND_EXC_LT: - case OP_CLT: - case OP_IBLT: - case OP_ICLT: - case OP_FBLT: - case OP_FCLT: - return CMP_LT; - case CEE_BGT: - case OP_COND_EXC_GT: - case OP_CGT: - case OP_IBGT: - case OP_ICGT: - case OP_FBGT: - case OP_FCGT: - return CMP_GT; - - case CEE_BLE_UN: - case OP_COND_EXC_LE_UN: - case OP_IBLE_UN: - case OP_FBLE_UN: - return CMP_LE_UN; - case CEE_BGE_UN: - case OP_IBGE_UN: - case OP_FBGE_UN: - return CMP_GE_UN; - case CEE_BLT_UN: - case OP_CLT_UN: - case OP_IBLT_UN: - case OP_ICLT_UN: - case OP_FBLT_UN: - case OP_FCLT_UN: - case OP_COND_EXC_LT_UN: - return CMP_LT_UN; - case CEE_BGT_UN: - case OP_COND_EXC_GT_UN: - case OP_CGT_UN: - case OP_IBGT_UN: - case OP_ICGT_UN: - case OP_FCGT_UN: - case OP_FBGT_UN: - return CMP_GT_UN; - default: - printf ("%s\n", mono_inst_name (opcode)); - g_error("Not implemented\n"); - } - return CMP_EQ; -} - -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_get_patch_offset */ @@ -5370,3 +5744,11 @@ mono_arch_get_patch_offset (guint8 *code) } /*========================= End of Function ========================*/ + +gpointer +mono_arch_context_get_int_reg (MonoContext *ctx, int reg) +{ + /* FIXME: implement */ + g_assert_not_reached (); + return NULL; +}