X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-s390.c;h=a001ef7decfe11b13f7695a69cb72bab7b8cbe7d;hb=9342e7d1d4e5d0d3248de33d05b2c2b993314bd6;hp=6ed6b83abd3d943751fda1d640eff81d70f4f388;hpb=ff228e1c801bda9666b6edab3ee962e05edcf480;p=mono.git diff --git a/mono/mini/mini-s390.c b/mono/mini/mini-s390.c index 6ed6b83abd3..a001ef7decf 100644 --- a/mono/mini/mini-s390.c +++ b/mono/mini/mini-s390.c @@ -18,75 +18,40 @@ /* 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) { \ - if (ins->inst_i0->inst_c0) { \ - int displace; \ - displace = ((cfg->native_code + ins->inst_i0->inst_c0) - code) / 2; \ - if (s390_is_uimm16(displace)) { \ - s390_brc (code, cond, displace); \ - } else { \ - s390_jcl (code, cond, displace); \ - } \ - } else { \ - mono_add_patch_info (cfg, code - cfg->native_code, \ - MONO_PATCH_INFO_LABEL, ins->inst_i0); \ - s390_jcl (code, cond, 0); \ - } \ -} else { \ - if (ins->inst_true_bb->native_offset) { \ - int displace; \ - displace = ((cfg->native_code + \ - ins->inst_true_bb->native_offset) - code) / 2; \ - if (s390_is_uimm16(displace)) { \ - s390_brc (code, cond, displace); \ - } else { \ - s390_jcl (code, cond, displace); \ - } \ - } else { \ - mono_add_patch_info (cfg, code - cfg->native_code, \ - MONO_PATCH_INFO_BB, ins->inst_true_bb); \ - s390_jcl (code, cond, 0); \ - } \ -} \ +if (ins->inst_true_bb->native_offset) { \ + int displace; \ + displace = ((cfg->native_code + \ + ins->inst_true_bb->native_offset) - code) / 2; \ + if (s390_is_imm16(displace)) { \ + s390_brc (code, cond, displace); \ + } else { \ + s390_jcl (code, cond, displace); \ + } \ +} else { \ + mono_add_patch_info (cfg, code - cfg->native_code, \ + MONO_PATCH_INFO_BB, ins->inst_true_bb); \ + s390_jcl (code, cond, 0); \ +} \ } #define EMIT_UNCOND_BRANCH(ins) \ { \ -if (ins->flags & MONO_INST_BRLABEL) { \ - if (ins->inst_i0->inst_c0) { \ - int displace; \ - displace = ((cfg->native_code + ins->inst_i0->inst_c0) - code) / 2; \ - if (s390_is_uimm16(displace)) { \ - s390_brc (code, S390_CC_UN, displace); \ - } else { \ - s390_jcl (code, S390_CC_UN, displace); \ - } \ - } else { \ - mono_add_patch_info (cfg, code - cfg->native_code, \ - MONO_PATCH_INFO_LABEL, ins->inst_i0); \ - s390_jcl (code, S390_CC_UN, 0); \ - } \ -} else { \ - if (ins->inst_target_bb->native_offset) { \ - int displace; \ - displace = ((cfg->native_code + \ - ins->inst_target_bb->native_offset) - code) / 2; \ - if (s390_is_uimm16(displace)) { \ - s390_brc (code, S390_CC_UN, displace); \ - } else { \ - s390_jcl (code, S390_CC_UN, displace); \ - } \ - } else { \ - mono_add_patch_info (cfg, code - cfg->native_code, \ - MONO_PATCH_INFO_BB, ins->inst_target_bb); \ - s390_jcl (code, S390_CC_UN, 0); \ - } \ -} \ +if (ins->inst_target_bb->native_offset) { \ + int displace; \ + displace = ((cfg->native_code + \ + ins->inst_target_bb->native_offset) - code) / 2; \ + if (s390_is_imm16(displace)) { \ + s390_brc (code, S390_CC_UN, displace); \ + } else { \ + s390_jcl (code, S390_CC_UN, displace); \ + } \ +} else { \ + mono_add_patch_info (cfg, code - cfg->native_code, \ + MONO_PATCH_INFO_BB, ins->inst_target_bb); \ + s390_jcl (code, S390_CC_UN, 0); \ +} \ } #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) \ @@ -117,6 +82,16 @@ if (ins->flags & MONO_INST_BRLABEL) { \ s390_lr (code, ins->dreg, ins->sreg1); \ } +#define CHECK_SRCDST_COM_F \ + if (ins->dreg == ins->sreg2) { \ + src2 = ins->sreg1; \ + } else { \ + src2 = ins->sreg2; \ + if (ins->dreg != ins->sreg1) { \ + s390_ldr (code, ins->dreg, ins->sreg1); \ + } \ + } + #define CHECK_SRCDST_NCOM_F \ if (ins->dreg == ins->sreg2) { \ src2 = s390_f15; \ @@ -128,23 +103,112 @@ if (ins->flags & MONO_INST_BRLABEL) { \ s390_ldr (code, ins->dreg, ins->sreg1); \ } +#define MONO_EMIT_NEW_MOVE(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) { \ + inst->dreg = dest; \ + inst->inst_offset = offset; \ + inst->sreg1 = src; \ + inst->inst_imm = imm; \ + } 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_VTR(cfg, size, dr, sr, so) do { \ + int reg = mono_alloc_preg (cfg); \ + switch (size) { \ + case 0: \ + MONO_EMIT_NEW_ICONST(cfg, reg, 0); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ + break; \ + case 1: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \ + reg, sr, so); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ + break; \ + case 2: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \ + reg, sr, so); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ + break; \ + case 4: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOAD_MEMBASE, \ + reg, sr, so); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ + break; \ + case 8: \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOAD_MEMBASE, \ + reg, sr, so); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ + reg = mono_alloc_preg (cfg); \ + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOAD_MEMBASE, \ + reg, sr, so + sizeof (guint32)); \ + mono_call_inst_add_outarg_reg(cfg, call, reg, dr + 1, FALSE); \ + break; \ + } \ +} while (0) + +#define MONO_OUTPUT_VTS(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: \ + case 8: \ + MONO_EMIT_NEW_MOVE (cfg, dr, dx, sr, so, size); \ + break; \ + } \ +} while (0) + #undef DEBUG #define DEBUG(a) if (cfg->verbose_level > 1) a #define MAX_EXC 16 -/*----------------------------------------*/ -/* use s390_r2-s390_r5 as temp registers */ -/*----------------------------------------*/ -#define S390_CALLER_REGS (0x10fc) -#define reg_is_freeable(r) (S390_CALLER_REGS & 1 << (r)) - -/*----------------------------------------*/ -/* use s390_f1/s390_f3-s390_f15 as temps */ -/*----------------------------------------*/ -#define S390_CALLER_FREGS (0xfffa) -#define freg_is_freeable(r) ((r) >= 1 && (r) <= 14) - #define S390_TRACE_STACK_SIZE (5*sizeof(gint32)+3*sizeof(gdouble)) #define MAX (a, b) ((a) > (b) ? (a) : (b)) @@ -164,8 +228,9 @@ if (ins->flags & MONO_INST_BRLABEL) { \ #include #include "mini-s390.h" -#include "inssel.h" #include "cpu-s390.h" +#include "jit-icalls.h" +#include "ir-emit.h" /*========================= End of Includes ========================*/ @@ -177,6 +242,9 @@ typedef struct { guint stack_size, local_size, code_size, + parm_size, + offset, + offStruct, retStruct; } size_data; @@ -189,16 +257,10 @@ enum { SAVE_STRUCT, SAVE_ONE, SAVE_TWO, - SAVE_FP + SAVE_R4, + SAVE_R8 }; -typedef struct { - int born_in; - int killed_in; - int last_use; - int prev_use; -} RegTrack; - typedef struct InstList InstList; struct InstList { @@ -207,29 +269,33 @@ 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 on callee's stack */ + gint32 offparm; /* offset from callee's stack */ guint16 vtsize; /* in param area */ guint8 reg; - guint8 regtype; /* See RegType* */ + ArgStorage regtype; /* See RegType* */ guint32 size; /* Size of structure used by RegTypeStructByVal */ } ArgInfo; typedef struct { int nargs; + int lastgr; guint32 stack_usage; guint32 struct_ret; ArgInfo ret; ArgInfo sigCookie; + size_data sz; ArgInfo args [1]; } CallInfo; @@ -244,33 +310,20 @@ typedef struct { /* P r o t o t y p e s */ /*------------------------------------------------------------------*/ -static guint32 * emit_memcpy (guint8 *, int, int, int, int, int); static void indent (int); -static guint8 * backUpStackPtr(MonoCompile *, guint8 *); +static guint8 * backUpStackPtr(MonoCompile *, guint8 *, gint); static void decodeParm (MonoType *, void *, int); static void enter_method (MonoMethod *, RegParm *, char *); static void leave_method (MonoMethod *, ...); static gboolean is_regsize_var (MonoType *); static inline void add_general (guint *, size_data *, ArgInfo *, gboolean); +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 int mono_spillvar_offset (MonoCompile *, int); -static int mono_spillvar_offset_float (MonoCompile *, int); -static void print_ins (int, MonoInst *); -static void print_regtrack (RegTrack *, int); -static InstList * inst_list_prepend (MonoMemPool *, InstList *, MonoInst *); -static int get_register_force_spilling (MonoCompile *, InstList *, MonoInst *, int); -static int get_register_spilling (MonoCompile *, InstList *, MonoInst *, guint32, int); -static int get_float_register_spilling (MonoCompile *, InstList *, MonoInst *, guint32, int); -static MonoInst * create_copy_ins (MonoCompile *, int, int, MonoInst *); -static MonoInst * create_copy_ins_float (MonoCompile *, int, int, MonoInst *); -static MonoInst * create_spilled_store (MonoCompile *, int, int, int, MonoInst *); -static MonoInst * create_spilled_store_float (MonoCompile *, int, int, int, MonoInst *); -static void insert_before_ins (MonoInst *, InstList *, MonoInst *); -static int alloc_int_reg (MonoCompile *, InstList *, MonoInst *, int, guint32); +static CallInfo * get_call_info (MonoCompile *, MonoMemPool *, MonoMethodSignature *, gboolean); static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean); -static unsigned char * mono_emit_stack_alloc (guchar *, MonoInst *); +gpointer mono_arch_get_lmf_addr (void); +static guint8 * emit_load_volatile_registers(guint8 *, MonoCompile *); +static void emit_sig_cookie (MonoCompile *, MonoCallInst *, CallInfo *); /*========================= End of Prototypes ======================*/ @@ -282,14 +335,15 @@ int mono_exc_esp_offset = 0; static int indent_level = 0; -static const char*const * ins_spec = s390; - 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; + +gboolean lmf_addr_key_inited = FALSE; + #if 0 extern __thread MonoDomain *tls_appdomain; @@ -317,59 +371,37 @@ mono_arch_regname (int reg) { "s390_r10", "s390_r11", "s390_r12", "s390_r13", "s390_r14", "s390_r15" }; + if (reg >= 0 && reg < 16) return rnames [reg]; - return "unknown"; + else + return "unknown"; } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - emit_memcpy */ -/* */ -/* Function - Emit code to move from memory-to-memory based on */ -/* the size of the variable. r0 is overwritten. */ +/* Name - mono_arch_fregname */ /* */ +/* Function - Returns the name of the register specified by */ +/* the input parameter. */ +/* */ /*------------------------------------------------------------------*/ -static guint32* -emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset) -{ - switch (size) { - case 4 : - s390_l (code, s390_r0, 0, sreg, soffset); - s390_st (code, s390_r0, 0, dreg, doffset); - break; - - case 3 : - s390_icm (code, s390_r0, 14, sreg, soffset); - s390_stcm (code, s390_r0, 14, dreg, doffset); - break; - - case 2 : - s390_lh (code, s390_r0, 0, sreg, soffset); - s390_sth (code, s390_r0, 0, dreg, doffset); - break; - - case 1 : - s390_ic (code, s390_r0, 0, sreg, soffset); - s390_stc (code, s390_r0, 0, dreg, doffset); - break; - - default : - while (size > 0) { - int len; +const char* +mono_arch_fregname (int reg) { + static const char * rnames[] = { + "s390_f0", "s390_f1", "s390_f2", "s390_f3", "s390_f4", + "s390_f5", "s390_f6", "s390_f7", "s390_f8", "s390_f9", + "s390_f10", "s390_f11", "s390_f12", "s390_f13", "s390_f14", + "s390_f15" + }; - if (size > 256) - len = 256; - else - len = size; - s390_mvc (code, len, dreg, doffset, sreg, soffset); - size -= len; - } - } - return code; + if (reg >= 0 && reg < 16) + return rnames [reg]; + else + return "unknown"; } /*========================= End of Function ========================*/ @@ -418,7 +450,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; @@ -475,18 +507,18 @@ retFitsInReg(guint32 size) /*------------------------------------------------------------------*/ static inline guint8 * -backUpStackPtr(MonoCompile *cfg, guint8 *code) +backUpStackPtr(MonoCompile *cfg, guint8 *code, gint framePtr) { int stackSize = cfg->stack_usage; if (s390_is_uimm16 (cfg->stack_usage)) { - s390_ahi (code, STK_BASE, cfg->stack_usage); + s390_ahi (code, framePtr, cfg->stack_usage); } else { while (stackSize > 32767) { - s390_ahi (code, STK_BASE, 32767); + s390_ahi (code, framePtr, 32767); stackSize -= 32767; } - s390_ahi (code, STK_BASE, stackSize); + s390_ahi (code, framePtr, stackSize); } return (code); } @@ -543,10 +575,10 @@ enum_parmtype: printf ("[UINTPTR:%p], ", *((int **) curParm)); break; case MONO_TYPE_BOOLEAN : - printf ("[BOOL:%p], ", *((int *) curParm)); + printf ("[BOOL:%d], ", *((int *) curParm)); break; case MONO_TYPE_CHAR : - printf ("[CHAR:%p], ", *((int *) curParm)); + printf ("[CHAR:%c], ", *((int *) curParm)); break; case MONO_TYPE_I1 : printf ("[INT1:%d], ", *((int *) curParm)); @@ -586,15 +618,16 @@ enum_parmtype: if ((obj) && (obj->vtable)) { printf("[CLASS/OBJ:"); class = obj->vtable->klass; - if (class == mono_defaults.string_class) { - printf("[STRING:%p:%s]", - *obj, mono_string_to_utf8 (obj)); - } else if (class == mono_defaults.int32_class) { - printf("[INT32:%p:%d]", - obj, *(gint32 *)((char *)obj + sizeof (MonoObject))); - } else - printf("[%s.%s:%p]", - class->name_space, class->name, obj); + printf("%p [%p] ",obj,curParm); +// if (class == mono_defaults.string_class) { +// printf("[STRING:%p:%s]", +// *obj, mono_string_to_utf8 (obj)); +// } else if (class == mono_defaults.int32_class) { +// printf("[INT32:%p:%d]", +// obj, *(gint32 *)((char *)obj + sizeof (MonoObject))); +// } else +// printf("[%s.%s:%p]", +// class->name_space, class->name, obj); printf("], "); } else { printf("[OBJECT:null], "); @@ -617,7 +650,7 @@ enum_parmtype: printf("[INT8:%lld], ", *((gint64 *) (curParm))); break; case MONO_TYPE_R4 : - printf("[FLOAT4:%f], ", *((float *) (curParm))); + printf("[FLOAT4:%g], ", *((double *) (curParm))); break; case MONO_TYPE_R8 : printf("[FLOAT8:%g], ", *((double *) (curParm))); @@ -627,7 +660,7 @@ enum_parmtype: MonoMarshalType *info; if (type->data.klass->enumtype) { - simpleType = type->data.klass->enum_basetype->type; + simpleType = mono_class_enum_basetype (type->data.klass)->type; printf("{VALUETYPE} - "); goto enum_parmtype; } @@ -637,7 +670,7 @@ enum_parmtype: if ((info->native_size == sizeof(float)) && (info->num_fields == 1) && (info->fields[0].field->type->type == MONO_TYPE_R4)) { - printf("[FLOAT4:%f], ", *((float *) (curParm))); + printf("[FLOAT4:%f], ", *((float *) (curParm))); break; } @@ -670,6 +703,8 @@ enum_parmtype: /*========================= End of Function ========================*/ +//static int lc = 0; + /*------------------------------------------------------------------*/ /* */ /* Name - enter_method */ @@ -683,15 +718,12 @@ static void enter_method (MonoMethod *method, RegParm *rParm, char *sp) { int i, oParm = 0, iParm = 0; - MonoClass *class; MonoObject *obj; - MonoJitArgumentInfo *arg_info; MonoMethodSignature *sig; char *fname; guint32 ip; CallInfo *cinfo; ArgInfo *ainfo; - size_data sz; void *curParm; fname = mono_method_full_name (method, TRUE); @@ -700,17 +732,17 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp) g_free (fname); ip = (*(guint32 *) (sp+S390_RET_ADDR_OFFSET)) & 0x7fffffff; - printf (") ip: %p sp: %p - ", ip, sp); + printf (") ip: %p sp: %p - ", (gpointer) ip, sp); if (rParm == NULL) return; 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 ("[VALUERET:%p], ", rParm->gr[0]); + printf ("[STRUCTRET:%p], ", (gpointer) rParm->gr[0]); iParm = 1; } @@ -725,14 +757,15 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp) printf ("this:[NULL], "); } else { if (obj) { - class = obj->vtable->klass; - if (class == mono_defaults.string_class) { - printf ("this:[STRING:%p:%s], ", - obj, mono_string_to_utf8 ((MonoString *)obj)); - } else { - printf ("this:%p[%s.%s], ", - obj, class->name_space, class->name); - } +// class = obj->vtable->klass; +// if (class == mono_defaults.string_class) { +// printf ("this:[STRING:%p:%s], ", +// obj, mono_string_to_utf8 ((MonoString *)obj)); +// } else { +// printf ("this:%p[%s.%s], ", +// obj, class->name_space, class->name); +// } +printf("this:%p, ",obj); } else printf ("this:NULL, "); } @@ -740,7 +773,7 @@ enter_method (MonoMethod *method, RegParm *rParm, char *sp) } for (i = 0; i < sig->param_count; ++i) { - ainfo = cinfo->args + (i + oParm); + ainfo = &cinfo->args[i + oParm]; switch (ainfo->regtype) { case RegTypeGeneral : decodeParm(sig->params[i], &(rParm->gr[ainfo->reg-2]), ainfo->size); @@ -861,13 +894,13 @@ handle_enum: break; } case MONO_TYPE_I: { - int *val = va_arg (ap, int*); + int val = va_arg (ap, int); printf ("[INT:%d]", val); printf("]"); break; } case MONO_TYPE_U: { - int *val = va_arg (ap, int*); + int val = va_arg (ap, int); printf ("[UINT:%d]", val); printf("]"); break; @@ -886,16 +919,16 @@ handle_enum: case MONO_TYPE_OBJECT: { MonoObject *o = va_arg (ap, MonoObject *); - if ((o) && (o->vtable)) { - if (o->vtable->klass == mono_defaults.boolean_class) { - printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject))); - } else if (o->vtable->klass == mono_defaults.int32_class) { - printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject)))); - } else if (o->vtable->klass == mono_defaults.int64_class) { - printf ("[INT64:%p:%lld]", o, *((gint64 *)((char *)o + sizeof (MonoObject)))); - } else - printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o); - } else +// if ((o) && (o->vtable)) { +// if (o->vtable->klass == mono_defaults.boolean_class) { +// printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject))); +// } else if (o->vtable->klass == mono_defaults.int32_class) { +// printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject)))); +// } else if (o->vtable->klass == mono_defaults.int64_class) { +// printf ("[INT64:%p:%lld]", o, *((gint64 *)((char *)o + sizeof (MonoObject)))); +// } else +// printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o); +// } else printf ("[OBJECT:%p]", o); break; @@ -919,8 +952,9 @@ handle_enum: break; } case MONO_TYPE_R4: { - double f = va_arg (ap, double); - printf ("[FLOAT4:%f]\n", (float) f); + double f; + f = va_arg (ap, double); + printf ("[FLOAT4:%g]\n", f); break; } case MONO_TYPE_R8: { @@ -931,7 +965,7 @@ handle_enum: case MONO_TYPE_VALUETYPE: { MonoMarshalType *info; if (type->data.klass->enumtype) { - type = type->data.klass->enum_basetype; + type = mono_class_enum_basetype (type->data.klass); goto handle_enum; } else { guint8 *p = va_arg (ap, gpointer); @@ -943,7 +977,7 @@ handle_enum: (info->num_fields == 1) && (info->fields[0].field->type->type == MONO_TYPE_R4)) { double f = va_arg (ap, double); - printf("[FLOAT4:%f]\n", (float) f); + printf("[FLOAT4:%g]\n", (double) f); break; } @@ -956,21 +990,39 @@ handle_enum: } size = mono_type_size (type, &align); - printf ("["); - for (j = 0; p && j < size; j++) - printf ("%02x,", p [j]); - printf ("]"); - } + switch (size) { + case 1: + case 2: + case 4: + case 8: + printf ("["); + for (j = 0; p && j < size; j++) + printf ("%02x,", p [j]); + printf ("]\n"); + break; + default: + printf ("[VALUERET]\n"); + } + } break; } case MONO_TYPE_TYPEDBYREF: { guint8 *p = va_arg (ap, gpointer); int j, size, align; size = mono_type_size (type, &align); - printf ("["); - for (j = 0; p && j < size; j++) - printf ("%02x,", p [j]); - printf ("]"); + switch (size) { + case 1: + case 2: + case 4: + case 8: + printf ("["); + for (j = 0; p && j < size; j++) + printf ("%02x,", p [j]); + printf ("]\n"); + break; + default: + printf ("[TYPEDBYREF]\n"); + } } break; default: @@ -979,7 +1031,7 @@ handle_enum: } ip = ((gint32) __builtin_return_address (0)) & 0x7fffffff; - printf (" ip: %p\n", ip); + printf (" ip: %p\n", (gpointer) ip); } /*========================= End of Function ========================*/ @@ -1007,6 +1059,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 */ @@ -1047,6 +1116,8 @@ is_regsize_var (MonoType *t) { case MONO_TYPE_U4: case MONO_TYPE_I: case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: return TRUE; case MONO_TYPE_OBJECT: case MONO_TYPE_STRING: @@ -1056,7 +1127,7 @@ is_regsize_var (MonoType *t) { return FALSE; case MONO_TYPE_VALUETYPE: if (t->data.klass->enumtype) - return is_regsize_var (t->data.klass->enum_basetype); + return is_regsize_var (mono_class_enum_basetype (t->data.klass)); return FALSE; } return FALSE; @@ -1083,10 +1154,11 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) MonoMethodVar *vmv = MONO_VARINFO (cfg, i); /* unused vars */ - if (vmv->range.first_use.abs_pos > vmv->range.last_use.abs_pos) + if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos) continue; - if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) + if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || + (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG)) continue; /* we can only allocate 32 bit values */ @@ -1117,12 +1189,14 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) MonoMethodHeader *header; int i, top = 13; - header = mono_method_get_header (cfg->method); + header = cfg->header; 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)); } @@ -1146,6 +1220,21 @@ mono_arch_flush_icache (guint8 *code, gint size) /*========================= End of Function ========================*/ +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_is_inst_imm */ +/* */ +/*------------------------------------------------------------------*/ + +gboolean +mono_arch_is_inst_imm (gint64 imm) +{ + /* The lowering pass will take care of it */ + return TRUE; +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - add_general */ @@ -1158,6 +1247,8 @@ mono_arch_flush_icache (guint8 *code, gint size) static void inline add_general (guint *gr, size_data *sz, ArgInfo *ainfo, gboolean simple) { + int disp; + if (simple) { if (*gr > S390_LAST_ARG_REG) { sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); @@ -1165,6 +1256,8 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo, gboolean simple) ainfo->reg = STK_BASE; ainfo->regtype = RegTypeBase; sz->stack_size += sizeof(int); + sz->local_size += sizeof(int); + sz->offStruct += sizeof(int); sz->code_size += 12; } else { ainfo->reg = *gr; @@ -1172,11 +1265,15 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo, gboolean simple) } } else { if (*gr > S390_LAST_ARG_REG - 1) { + disp = sz->stack_size; sz->stack_size = S390_ALIGN(sz->stack_size, S390_STACK_ALIGNMENT); + disp = sz->stack_size - disp; ainfo->offset = sz->stack_size; ainfo->reg = STK_BASE; ainfo->regtype = RegTypeBase; sz->stack_size += sizeof(long long); + sz->local_size += (sizeof(long long) + disp); + sz->offStruct += (sizeof(long long) + disp); sz->code_size += 10; } else { ainfo->reg = *gr; @@ -1189,6 +1286,40 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo, gboolean simple) /*========================= End of Function ========================*/ +/*------------------------------------------------------------------*/ +/* */ +/* Name - add_stackParm */ +/* */ +/* Function - Determine code and stack size incremements for a */ +/* parameter. */ +/* */ +/*------------------------------------------------------------------*/ + +static void inline +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; + 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->offparm = sz->offset; + sz->offset = S390_ALIGN(sz->offset+size, sizeof(long)); + ainfo->size = size; + ainfo->regtype = RegTypeStructByAddr; + ainfo->vtsize = size; + sz->parm_size += size; +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - add_float */ @@ -1213,6 +1344,8 @@ add_float (guint *fr, size_data *sz, ArgInfo *ainfo) ainfo->regtype = RegTypeBase; sz->code_size += 4; sz->stack_size += ainfo->size; + sz->local_size += ainfo->size; + sz->offStruct += ainfo->size; } } @@ -1220,7 +1353,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 */ @@ -1230,21 +1363,32 @@ 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; + nParm = 0; cinfo->struct_ret = 0; + sz = &cinfo->sz; + sz->offset = 0; + sz->offStruct = S390_MINIMAL_STACK_SIZE; sz->retStruct = 0; sz->stack_size = S390_MINIMAL_STACK_SIZE; sz->code_size = 0; + sz->parm_size = 0; sz->local_size = 0; /*----------------------------------------------------------*/ @@ -1253,7 +1397,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: @@ -1286,10 +1432,17 @@ enum_retvalue: cinfo->ret.reg = s390_r2; sz->code_size += 4; break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (ret_type)) { + cinfo->ret.reg = s390_r2; + sz->code_size += 4; + break; + } + /* Fall through */ case MONO_TYPE_VALUETYPE: { MonoClass *klass = mono_class_from_mono_type (sig->ret); - if (sig->ret->data.klass->enumtype) { - simpletype = sig->ret->data.klass->enum_basetype->type; + if (klass->enumtype) { + simpletype = mono_class_enum_basetype (klass)->type; goto enum_retvalue; } if (sig->pinvoke) @@ -1301,8 +1454,6 @@ enum_retvalue: cinfo->struct_ret = 1; cinfo->ret.size = size; cinfo->ret.vtsize = size; - cinfo->ret.offset = sz->stack_size; - sz->stack_size += S390_ALIGN(size, align); gr++; break; } @@ -1312,14 +1463,12 @@ enum_retvalue: cinfo->struct_ret = 1; cinfo->ret.size = size; cinfo->ret.vtsize = size; - cinfo->ret.offset = sz->stack_size; - sz->stack_size += S390_ALIGN(size, align); gr++; break; case MONO_TYPE_VOID: break; default: - g_error ("Can't handle as return value 0x%x", sig->ret->type); + g_error ("mini-s390: cannot handle as return value 0x%x (0x%x)", sig->ret->type,simpletype); } if (sig->hasthis) { @@ -1335,6 +1484,8 @@ enum_retvalue: /*----------------------------------------------------------*/ for (i = 0; i < sig->param_count; ++i) { + MonoType *ptype; + /*--------------------------------------------------*/ /* Handle vararg type calls. All args are put on */ /* the stack. */ @@ -1351,7 +1502,10 @@ enum_retvalue: nParm++; 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; switch (simpletype) { case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: @@ -1402,6 +1556,14 @@ enum_retvalue: add_float (&fr, sz, cinfo->args+nParm); nParm++; break; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (ptype)) { + cinfo->args[nParm].size = sizeof(gpointer); + add_general (&gr, sz, cinfo->args+nParm, TRUE); + nParm++; + break; + } + /* Fall through */ case MONO_TYPE_VALUETYPE: { MonoMarshalType *info; MonoClass *klass = mono_class_from_mono_type (sig->params [i]); @@ -1417,6 +1579,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; } @@ -1425,12 +1588,12 @@ 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; } cinfo->args[nParm].vtsize = 0; cinfo->args[nParm].size = 0; - cinfo->args[nParm].offparm = sz->local_size; switch (size) { /*----------------------------------*/ @@ -1453,17 +1616,10 @@ enum_retvalue: cinfo->args[nParm].size = sizeof(long long); cinfo->args[nParm].regtype = RegTypeStructByVal; nParm++; - sz->local_size += sizeof(long); + sz->local_size += sizeof(long long); break; default: - add_general(&gr, sz, cinfo->args+nParm, TRUE); - cinfo->args[nParm].size = sizeof(int); - cinfo->args[nParm].regtype = RegTypeStructByAddr; - cinfo->args[nParm].vtsize = size; - sz->code_size += 40; - sz->local_size += size; - if (cinfo->args[nParm].reg == STK_BASE) - sz->local_size += sizeof(gpointer); + add_stackParm(&gr, sz, cinfo->args+nParm, size); nParm++; } } @@ -1473,7 +1629,6 @@ enum_retvalue: cinfo->args[nParm].vtsize = 0; cinfo->args[nParm].size = 0; - cinfo->args[nParm].offparm = sz->local_size; switch (size) { /*----------------------------------*/ @@ -1496,17 +1651,10 @@ enum_retvalue: cinfo->args[nParm].size = sizeof(long long); cinfo->args[nParm].regtype = RegTypeStructByVal; nParm++; - sz->local_size += sizeof(long); + sz->local_size += sizeof(long long); break; default: - add_general(&gr, sz, cinfo->args+nParm, TRUE); - cinfo->args[nParm].size = sizeof(int); - cinfo->args[nParm].regtype = RegTypeStructByAddr; - cinfo->args[nParm].vtsize = size; - sz->code_size += 40; - sz->local_size += size; - if (cinfo->args[nParm].reg == STK_BASE) - sz->local_size += sizeof(gpointer); + add_stackParm(&gr, sz, cinfo->args+nParm, size); nParm++; } } @@ -1516,8 +1664,39 @@ enum_retvalue: } } - cinfo->stack_usage = S390_ALIGN(sz->stack_size+sz->local_size, - S390_STACK_ALIGNMENT); + /*----------------------------------------------------------*/ + /* If we are passing a structure back then if it won't be */ + /* in a register(s) then we make room at the end of the */ + /* parameters that may have been placed on the stack */ + /*----------------------------------------------------------*/ + if (cinfo->struct_ret) { + cinfo->ret.offset = sz->stack_size; + switch (cinfo->ret.size) { + case 0: + case 1: + case 2: + case 4: + case 8: + break; + default: + sz->stack_size += S390_ALIGN(cinfo->ret.size, align); + } + } + + /*----------------------------------------------------------*/ + /* Handle the case where there are no implicit arguments */ + /*----------------------------------------------------------*/ + if ((sig->call_convention == MONO_CALL_VARARG) && + (sig->param_count == sig->sentinelpos)) { + gr = S390_LAST_ARG_REG + 1; + add_general (&gr, sz, &cinfo->sigCookie, TRUE); + } + + cinfo->lastgr = gr; + sz->stack_size = sz->stack_size + sz->local_size + sz->parm_size + + sz->offset; + sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); + return (cinfo); } @@ -1542,12 +1721,17 @@ 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; - header = mono_method_get_header (cfg->method); + header = cfg->header; + + cfg->flags |= MONO_CFG_HAS_SPILLUP; + + sig = mono_method_signature (cfg->method); + + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); /*---------------------------------------------------------*/ /* We use the frame register also for any method that has */ @@ -1564,17 +1748,16 @@ 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; - } else { + if (!cinfo->struct_ret) { switch (mono_type_get_underlying_type (sig->ret)->type) { case MONO_TYPE_VOID: break; @@ -1595,19 +1778,20 @@ 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) && - (!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; @@ -1626,43 +1810,68 @@ 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 : - inst->opcode = OP_S390_LOADARG; - inst->inst_basereg = frame_reg; - size = abs(cinfo->args[iParm].vtsize); - offset = S390_ALIGN(offset, size); - inst->inst_offset = offset; + case RegTypeStructByAddr : { + MonoInst *indir; + + size = sizeof (gpointer); + + if (cinfo->args [iParm].reg == STK_BASE) { + 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; + inst->inst_offset = cinfo->args [iParm].offset; + } else { + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = frame_reg; + inst->inst_offset = S390_ALIGN(offset, sizeof (gpointer)); + } + + /* Add a level of indirection */ + MONO_INST_NEW (cfg, indir, 0); + *indir = *inst; + inst->opcode = OP_VTARG_ADDR; + inst->inst_left = indir; + } break; case RegTypeStructByVal : - 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->opcode = OP_REGOFFSET; + inst->inst_basereg = frame_reg; + inst->inst_offset = S390_ALIGN (offset, size); 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(long) - : sizeof(long 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 < 4 - ? 4 - cinfo->args[iParm].size - : 0); - inst->inst_offset = cinfo->args[iParm].offset + - size; - inst->unused = 0; - size = sizeof(long); - } + 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 < 4 + ? 4 - 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(long) + : sizeof(long long)); + offset = S390_ALIGN(offset, size); + inst->inst_offset = offset; + } } if ((sig->call_convention == MONO_CALL_VARARG) && (cinfo->args[iParm].regtype != RegTypeGeneral) && @@ -1682,11 +1891,11 @@ mono_arch_allocate_vars (MonoCompile *cfg) continue; /*--------------------------------------------------*/ - /* inst->unused indicates native sized value types, */ + /* inst->backend.is_pinvoke indicates native sized value types, */ /* this is used by the pinvoke wrappers when they */ /* call functions returning structure */ /*--------------------------------------------------*/ - if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype)) + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype)) size = mono_class_native_size (mono_class_from_mono_type(inst->inst_vtype), &align); else size = mono_type_size (inst->inst_vtype, &align); @@ -1696,14 +1905,15 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; offset += size; - DEBUG (g_print("allocating local %d to %d\n", iVar, inst->inst_offset)); + DEBUG (g_print("allocating local %d to %ld\n", iVar, inst->inst_offset)); } /*------------------------------------------------------*/ /* Allow space for the trace method stack area if needed*/ /*------------------------------------------------------*/ - if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg)) + if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) { offset += S390_TRACE_STACK_SIZE; + } /*------------------------------------------------------*/ /* Reserve space to save LMF and caller saved registers */ @@ -1716,154 +1926,367 @@ mono_arch_allocate_vars (MonoCompile *cfg) /*------------------------------------------------------*/ cfg->stack_offset = S390_ALIGN(offset, S390_STACK_ALIGNMENT); + /* Fix up offsets for arguments whose value is in the parent frame */ + for (iParm = sArg; iParm < eArg; ++iParm) { + inst = cfg->args [iParm]; + + if (inst->opcode == OP_S390_STKARG) { + inst->opcode = OP_REGOFFSET; + inst->inst_offset += cfg->stack_offset; + } + } } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_call_opcode */ +/* Name - mono_arch_create_vars */ /* */ -/* Function - Take the arguments and generate the arch-specific */ -/* instructions to properly call the function. This */ -/* includes pushing, moving argments to the correct */ -/* etc. */ -/* */ -/* Note - FIXME: We need an alignment solution for */ -/* enter_method and mono_arch_call_opcode, currently */ -/* alignment in mono_arch_call_opcode is computed */ -/* without arch_get_argument_info. */ -/* */ /*------------------------------------------------------------------*/ -MonoCallInst* -mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, - MonoCallInst *call, int is_virtual) { - MonoInst *arg, *in; +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 ========================*/ + +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_cookie (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; - size_data sz; + ArgInfo *ainfo = NULL; + int stackSize; 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 = cinfo->stack_usage; - lParamArea = MAX((cinfo->stack_usage - S390_MINIMAL_STACK_SIZE), 0); - cfg->param_area = MAX (((signed) cfg->param_area), lParamArea); + 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) - call->used_iregs |= 1 << cinfo->ret.reg; + 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 ((sig->call_convention == MONO_CALL_VARARG) && - (i == sig->sentinelpos)) { - MonoInst *sigArg; - - cfg->disable_aot = TRUE; - MONO_INST_NEW (cfg, sigArg, OP_ICONST); - sigArg->inst_p0 = call->signature; + 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); - MONO_INST_NEW (cfg, arg, OP_OUTARG); - arg->inst_imm = cinfo->sigCookie.offset; - arg->inst_left = sigArg; + in = call->args [i]; - arg->next = call->out_args; - call->out_args = arg; + if ((sig->call_convention == MONO_CALL_VARARG) && + (i == sig->sentinelpos)) { + emit_sig_cookie (cfg, call, cinfo); } - if (is_virtual && i == 0) { - /* the argument will be attached to the call instrucion */ - in = call->args [i]; - call->used_iregs |= 1 << ainfo->reg; - } else { - MONO_INST_NEW (cfg, arg, OP_OUTARG); - in = call->args [i]; - arg->cil_code = in->cil_code; - arg->inst_left = in; - arg->type = in->type; - /* prepend, we'll need to reverse them later */ - arg->next = call->out_args; - call->out_args = arg; - if (ainfo->regtype == RegTypeGeneral) { - arg->unused = ainfo->reg; - call->used_iregs |= 1 << ainfo->reg; - if (arg->type == STACK_I8) - call->used_iregs |= 1 << (ainfo->reg + 1); - } else if (ainfo->regtype == RegTypeStructByAddr) { - call->used_iregs |= 1 << ainfo->reg; - arg->sreg1 = ainfo->reg; - arg->opcode = OP_OUTARG_VT; - arg->unused = -ainfo->vtsize; - arg->inst_imm = ainfo->offset; - arg->sreg2 = ainfo->offparm + S390_MINIMAL_STACK_SIZE; - } else if (ainfo->regtype == RegTypeStructByVal) { - if (ainfo->reg != STK_BASE) { - switch (ainfo->size) { - case 0: - case 1: - case 2: - case 4: - call->used_iregs |= 1 << ainfo->reg; - break; - case 8: - call->used_iregs |= 1 << ainfo->reg; - call->used_iregs |= 1 << (ainfo->reg+1); - break; - default: - call->used_iregs |= 1 << ainfo->reg; - } - } - arg->sreg1 = ainfo->reg; - arg->opcode = OP_OUTARG_VT; - arg->unused = ainfo->size; - arg->inst_imm = ainfo->offset; - arg->sreg2 = ainfo->offparm + S390_MINIMAL_STACK_SIZE; - } else if (ainfo->regtype == RegTypeBase) { - arg->opcode = OP_OUTARG; - arg->unused = ainfo->reg | (ainfo->size << 8); - arg->inst_imm = ainfo->offset; - call->used_fregs |= 1 << ainfo->reg; - } else if (ainfo->regtype == RegTypeFP) { - arg->unused = ainfo->reg; - call->used_fregs |= 1 << ainfo->reg; - if (ainfo->size == 4) { - MonoInst *conv; - arg->opcode = OP_OUTARG_R4; - MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4); - conv->inst_left = arg->inst_left; - arg->inst_left = conv; - } - else - arg->opcode = OP_OUTARG_R8; + switch (ainfo->regtype) { + case RegTypeGeneral: + if (!t->byref && (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8)) { + MONO_INST_NEW (cfg, ins, OP_MOVE); + ins->dreg = mono_alloc_ireg (cfg); + ins->sreg1 = in->dreg + 2; + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE); + MONO_INST_NEW (cfg, ins, OP_MOVE); + ins->dreg = mono_alloc_ireg (cfg); + ins->sreg1 = in->dreg + 1; + MONO_ADD_INS (cfg->cbb, ins); + mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE); } else { - g_assert_not_reached (); + add_outarg_reg2 (cfg, call, ainfo->regtype, ainfo->reg, in); } - } - } - /* - * Reverse the call->out_args list. - */ - { - MonoInst *prev = NULL, *list = call->out_args, *next; - while (list) { - next = list->next; - list->next = prev; - prev = list; - list = next; - } - call->out_args = prev; + 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); + if (ainfo->reg == STK_BASE) { + /* The address is passed on the stack */ + MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG); + ins->inst_destbasereg = STK_BASE; + ins->inst_offset = ainfo->offset; + ins->sreg1 = treg; + MONO_ADD_INS (cfg->cbb, ins); + } else { + 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, + 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 if (!t->byref && (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8)) { + MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG); + ins->inst_destbasereg = STK_BASE; + ins->inst_offset = ainfo->offset + MINI_LS_WORD_OFFSET; + ins->sreg1 = in->dreg + 1; + MONO_ADD_INS (cfg->cbb, ins); + + MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG); + ins->inst_destbasereg = STK_BASE; + ins->inst_offset = ainfo->offset + MINI_MS_WORD_OFFSET; + ins->sreg1 = in->dreg + 2; + MONO_ADD_INS (cfg->cbb, ins); + } else { + MONO_INST_NEW (cfg, ins, OP_STORE_MEMBASE_REG); + ins->inst_destbasereg = STK_BASE; + ins->inst_offset = ainfo->offset; + ins->sreg1 = in->dreg; + 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_cookie (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_VTR (cfg, size, ainfo->reg, src->dreg, 0); + } else { + MONO_OUTPUT_VTS (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_MOVE (cfg, STK_BASE, ainfo->offparm, + src->dreg, 0, size); } +} - g_free (cinfo); - return call; +/*------------------------------------------------------------------*/ +/* */ +/* 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; + } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) { + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, s390_r3, val->dreg + 1); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, s390_r2, val->dreg + 2); + return; + } + } + + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg); } /*========================= End of Function ========================*/ @@ -1900,33 +2323,45 @@ void* mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) { - guchar *code = p; + guchar *code = p; int parmOffset, - fpOffset; + fpOffset, + baseReg; parmOffset = cfg->stack_usage - S390_TRACE_STACK_SIZE; if (cfg->method->save_lmf) parmOffset -= sizeof(MonoLMF); fpOffset = parmOffset + (5*sizeof(gint32)); + if (fpOffset > 4096) { + s390_lr (code, s390_r12, STK_BASE); + baseReg = s390_r12; + while (fpOffset > 4096) { + s390_ahi (code, baseReg, 4096); + fpOffset -= 4096; + parmOffset -= 4096; + } + } else { + baseReg = STK_BASE; + } - s390_stm (code, s390_r2, s390_r6, STK_BASE, parmOffset); - s390_std (code, s390_f0, 0, STK_BASE, fpOffset); - s390_std (code, s390_f1, 0, STK_BASE, fpOffset+sizeof(gdouble)); - s390_std (code, s390_f2, 0, STK_BASE, fpOffset+2*sizeof(gdouble)); + s390_stm (code, s390_r2, s390_r6, baseReg, parmOffset); + s390_std (code, s390_f0, 0, baseReg, fpOffset); + s390_std (code, s390_f1, 0, baseReg, fpOffset+sizeof(gdouble)); + s390_std (code, s390_f2, 0, baseReg, fpOffset+2*sizeof(gdouble)); s390_basr (code, s390_r13, 0); s390_j (code, 6); s390_word (code, cfg->method); s390_word (code, func); s390_l (code, s390_r2, 0, s390_r13, 4); - s390_la (code, s390_r3, 0, STK_BASE, parmOffset); + s390_la (code, s390_r3, 0, baseReg, parmOffset); s390_lr (code, s390_r4, STK_BASE); s390_ahi (code, s390_r4, cfg->stack_usage); s390_l (code, s390_r1, 0, s390_r13, 8); s390_basr (code, s390_r14, s390_r1); - s390_ld (code, s390_f2, 0, STK_BASE, fpOffset+2*sizeof(gdouble)); - s390_ld (code, s390_f1, 0, STK_BASE, fpOffset+sizeof(gdouble)); - s390_ld (code, s390_f0, 0, STK_BASE, fpOffset); - s390_lm (code, s390_r2, s390_r6, STK_BASE, parmOffset); + s390_ld (code, s390_f2, 0, baseReg, fpOffset+2*sizeof(gdouble)); + s390_ld (code, s390_f1, 0, baseReg, fpOffset+sizeof(gdouble)); + s390_ld (code, s390_f0, 0, baseReg, fpOffset); + s390_lm (code, s390_r2, s390_r6, baseReg, parmOffset); return code; } @@ -1943,7 +2378,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, /*------------------------------------------------------------------*/ void* -mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) +mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers) { guchar *code = p; int save_mode = SAVE_NONE, @@ -1969,12 +2404,14 @@ handle_enum: save_mode = SAVE_TWO; break; case MONO_TYPE_R4: + save_mode = SAVE_R4; + break; case MONO_TYPE_R8: - save_mode = SAVE_FP; + save_mode = SAVE_R8; break; case MONO_TYPE_VALUETYPE: if (mono_method_signature (method)->ret->data.klass->enumtype) { - rtype = mono_method_signature (method)->ret->data.klass->enum_basetype->type; + rtype = mono_class_enum_basetype (mono_method_signature (method)->ret->data.klass)->type; goto handle_enum; } save_mode = SAVE_STRUCT; @@ -1998,14 +2435,15 @@ handle_enum: s390_lr (code, s390_r3, s390_r2); } break; - case SAVE_FP: + case SAVE_R4: s390_std (code, s390_f0, 0, cfg->frame_reg, saveOffset); if (enable_arguments) { - /* FIXME: what reg? */ - s390_ldr (code, s390_f2, s390_f0); - s390_lm (code, s390_r3, s390_r4, cfg->frame_reg, saveOffset); + s390_ldebr (code, s390_f0, s390_f0); } break; + case SAVE_R8: + s390_std (code, s390_f0, 0, cfg->frame_reg, saveOffset); + break; case SAVE_STRUCT: s390_st (code, s390_r2, 0, cfg->frame_reg, saveOffset); if (enable_arguments) { @@ -2033,7 +2471,8 @@ handle_enum: case SAVE_ONE: s390_l (code, s390_r2, 0, cfg->frame_reg, saveOffset); break; - case SAVE_FP: + case SAVE_R4: + case SAVE_R8: s390_ld (code, s390_f0, 0, cfg->frame_reg, saveOffset); break; case SAVE_STRUCT: @@ -2041,1096 +2480,62 @@ handle_enum: break; case SAVE_NONE: default: - break; - } - - return code; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - peephole_pass */ -/* */ -/* Function - Form a peephole pass at the code looking for */ -/* simple optimizations. */ -/* */ -/*------------------------------------------------------------------*/ - -static void -peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb) -{ - MonoInst *ins, *last_ins = NULL; - ins = bb->code; - - while (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 { - //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); - ins->opcode = OP_MOVE; - ins->sreg1 = last_ins->sreg1; - } - - /* - * 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; - } - - //g_assert_not_reached (); - -#if 0 - /* - * OP_STORE_MEMBASE_IMM imm, offset(basereg) - * OP_LOAD_MEMBASE offset(basereg), reg - * --> - * OP_STORE_MEMBASE_IMM imm, offset(basereg) - * OP_ICONST reg, imm - */ - } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM - || last_ins->opcode == OP_STORE_MEMBASE_IMM) && - ins->inst_basereg == last_ins->inst_destbasereg && - ins->inst_offset == last_ins->inst_offset) { - //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); - ins->opcode = OP_ICONST; - ins->inst_c0 = last_ins->inst_imm; - g_assert_not_reached (); // check this rule -#endif - } - 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) { - if (ins->dreg == last_ins->sreg1) { - last_ins->next = ins->next; - ins = ins->next; - continue; - } else { - //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++); - ins->opcode = OP_MOVE; - 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) { - 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; - } - } - 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; - } - break; - } - last_ins = ins; - ins = ins->next; - } - bb->last_ins = last_ins; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_spillvar_offset */ -/* */ -/* Function - Returns the offset used by spillvar. It allocates */ -/* a new spill variable if necessary. */ -/* */ -/*------------------------------------------------------------------*/ - -static int -mono_spillvar_offset (MonoCompile *cfg, int spillvar) -{ - MonoSpillInfo **si, *info; - int i = 0; - - si = &cfg->spill_info; - - while (i <= spillvar) { - - if (!*si) { - *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo)); - info->next = NULL; - info->offset = cfg->stack_offset; - cfg->stack_offset += sizeof (gpointer); - } - - if (i == spillvar) - return (*si)->offset; - - i++; - si = &(*si)->next; - } - - g_assert_not_reached (); - return 0; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_spillvar_offset_float */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -static int -mono_spillvar_offset_float (MonoCompile *cfg, int spillvar) -{ - MonoSpillInfo **si, *info; - int i = 0; - - si = &cfg->spill_info_float; - - while (i <= spillvar) { - - if (!*si) { - *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo)); - info->next = NULL; - cfg->stack_offset = S390_ALIGN(cfg->stack_offset, S390_STACK_ALIGNMENT); - info->offset = cfg->stack_offset; - cfg->stack_offset += sizeof (double); - } - - if (i == spillvar) - return (*si)->offset; - - i++; - si = &(*si)->next; - } - - g_assert_not_reached (); - return 0; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - print_ins */ -/* */ -/* Function - Decode and print the instruction for tracing. */ -/* */ -/*------------------------------------------------------------------*/ - -static void -print_ins (int i, MonoInst *ins) -{ - const char *spec = ins_spec [ins->opcode]; - g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode)); - if (spec [MONO_INST_DEST]) { - if (ins->dreg >= MONO_MAX_IREGS) - g_print (" R%d <-", ins->dreg); - else - g_print (" %s <-", mono_arch_regname (ins->dreg)); - } - if (spec [MONO_INST_SRC1]) { - if (ins->sreg1 >= MONO_MAX_IREGS) - g_print (" R%d", ins->sreg1); - else - g_print (" %s", mono_arch_regname (ins->sreg1)); - } - if (spec [MONO_INST_SRC2]) { - if (ins->sreg2 >= MONO_MAX_IREGS) - g_print (" R%d", ins->sreg2); - else - g_print (" %s", mono_arch_regname (ins->sreg2)); - } - if (spec [MONO_INST_CLOB]) - g_print (" clobbers: %c", spec [MONO_INST_CLOB]); - g_print ("\n"); -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - print_regtrack. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -static void -print_regtrack (RegTrack *t, int num) -{ - int i; - char buf [32]; - const char *r; - - for (i = 0; i < num; ++i) { - if (!t [i].born_in) - continue; - if (i >= MONO_MAX_IREGS) { - g_snprintf (buf, sizeof(buf), "R%d", i); - r = buf; - } else - r = mono_arch_regname (i); - g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use); - } -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - inst_list_prepend */ -/* */ -/* Function - Prepend an instruction to the list. */ -/* */ -/*------------------------------------------------------------------*/ - -static inline InstList* -inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data) -{ - InstList *item = mono_mempool_alloc (pool, sizeof (InstList)); - item->data = data; - item->prev = NULL; - item->next = list; - if (list) - list->prev = item; - return item; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - get_register_force_spilling */ -/* */ -/* Function - Force the spilling of the variable in the */ -/* symbolic register 'reg'. */ -/* */ -/*------------------------------------------------------------------*/ - -static int -get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg) -{ - MonoInst *load; - int i, sel, spill; - - sel = cfg->rs->iassign [reg]; - i = reg; - spill = ++cfg->spill_count; - cfg->rs->iassign [i] = -spill - 1; - mono_regstate_free_int (cfg->rs, sel); - /*----------------------------------------------------------*/ - /* we need to create a spill var and insert a load to sel */ - /* after the current instruction */ - /*----------------------------------------------------------*/ - MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE); - load->dreg = sel; - load->inst_basereg = cfg->frame_reg; - load->inst_offset = mono_spillvar_offset (cfg, spill); - if (item->prev) { - while (ins->next != item->prev->data) - ins = ins->next; - } - load->next = ins->next; - ins->next = load; - DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", - spill, load->inst_offset, i, mono_arch_regname (sel))); - i = mono_regstate_alloc_int (cfg->rs, 1 << sel); - g_assert (i == sel); - - return sel; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - get_register_spilling */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -static int -get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg) -{ - MonoInst *load; - int i, sel, spill; - - DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2)); - /* exclude the registers in the current instruction */ - if (reg != ins->sreg1 && - (reg_is_freeable (ins->sreg1) || - (ins->sreg1 >= MONO_MAX_IREGS && - cfg->rs->iassign [ins->sreg1] >= 0))) { - if (ins->sreg1 >= MONO_MAX_IREGS) - regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]); - else - regmask &= ~ (1 << ins->sreg1); - DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1))); - } - if (reg != ins->sreg2 && - (reg_is_freeable (ins->sreg2) || - (ins->sreg2 >= MONO_MAX_IREGS && - cfg->rs->iassign [ins->sreg2] >= 0))) { - if (ins->sreg2 >= MONO_MAX_IREGS) - regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]); - else - regmask &= ~ (1 << ins->sreg2); - DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2)); - } - if (reg != ins->dreg && reg_is_freeable (ins->dreg)) { - regmask &= ~ (1 << ins->dreg); - DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg))); - } - - DEBUG (g_print ("available regmask: 0x%08x\n", regmask)); - g_assert (regmask); /* need at least a register we can free */ - sel = -1; - /* we should track prev_use and spill the register that's farther */ - for (i = 0; i < MONO_MAX_IREGS; ++i) { - if (regmask & (1 << i)) { - sel = i; - DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel])); - break; - } - } - i = cfg->rs->isymbolic [sel]; - spill = ++cfg->spill_count; - cfg->rs->iassign [i] = -spill - 1; - mono_regstate_free_int (cfg->rs, sel); - /* we need to create a spill var and insert a load to sel after the current instruction */ - MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE); - load->dreg = sel; - load->inst_basereg = cfg->frame_reg; - load->inst_offset = mono_spillvar_offset (cfg, spill); - if (item->prev) { - while (ins->next != item->prev->data) - ins = ins->next; - } - load->next = ins->next; - ins->next = load; - DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel))); - i = mono_regstate_alloc_int (cfg->rs, 1 << sel); - g_assert (i == sel); - - return sel; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - get_float_register_spilling */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -static int -get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg) -{ - MonoInst *load; - int i, sel, spill; - - DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2)); - /* exclude the registers in the current instruction */ - if (reg != ins->sreg1 && - (freg_is_freeable (ins->sreg1) || - (ins->sreg1 >= MONO_MAX_FREGS && - cfg->rs->fassign [ins->sreg1] >= 0))) { - if (ins->sreg1 >= MONO_MAX_FREGS) - regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]); - else - regmask &= ~ (1 << ins->sreg1); - DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1))); - } - if (reg != ins->sreg2 && - (freg_is_freeable (ins->sreg2) || - (ins->sreg2 >= MONO_MAX_FREGS && - cfg->rs->fassign [ins->sreg2] >= 0))) { - if (ins->sreg2 >= MONO_MAX_FREGS) - regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]); - else - regmask &= ~ (1 << ins->sreg2); - DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2)); - } - if (reg != ins->dreg && freg_is_freeable (ins->dreg)) { - regmask &= ~ (1 << ins->dreg); - DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg))); - } - - DEBUG (g_print ("available regmask: 0x%08x\n", regmask)); - g_assert (regmask); /* need at least a register we can free */ - sel = -1; - /* we should track prev_use and spill the register that's farther */ - for (i = 0; i < MONO_MAX_FREGS; ++i) { - if (regmask & (1 << i)) { - sel = i; - DEBUG (g_print ("selected register %s has assignment %d\n", - mono_arch_regname (sel), cfg->rs->fassign [sel])); - break; - } - } - i = cfg->rs->fsymbolic [sel]; - spill = ++cfg->spill_count; - cfg->rs->fassign [i] = -spill - 1; - mono_regstate_free_float(cfg->rs, sel); - /* we need to create a spill var and insert a load to sel after the current instruction */ - MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE); - load->dreg = sel; - load->inst_basereg = cfg->frame_reg; - load->inst_offset = mono_spillvar_offset_float (cfg, spill); - if (item->prev) { - while (ins->next != item->prev->data) - ins = ins->next; - } - load->next = ins->next; - ins->next = load; - DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel))); - i = mono_regstate_alloc_float (cfg->rs, 1 << sel); - g_assert (i == sel); - - return sel; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - create_copy_ins */ -/* */ -/* Function - Create an instruction to copy from reg to reg. */ -/* */ -/*------------------------------------------------------------------*/ - -static MonoInst* -create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins) -{ - MonoInst *copy; - MONO_INST_NEW (cfg, copy, OP_MOVE); - copy->dreg = dest; - copy->sreg1 = src; - if (ins) { - copy->next = ins->next; - ins->next = copy; - } - DEBUG (g_print ("\tforced copy from %s to %s\n", - mono_arch_regname (src), mono_arch_regname (dest))); - return copy; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - create_copy_ins_float */ -/* */ -/* Function - Create an instruction to copy from float reg to */ -/* float reg. */ -/* */ -/*------------------------------------------------------------------*/ - -static MonoInst* -create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins) -{ - MonoInst *copy; - MONO_INST_NEW (cfg, copy, OP_FMOVE); - copy->dreg = dest; - copy->sreg1 = src; - if (ins) { - copy->next = ins->next; - ins->next = copy; - } - DEBUG (g_print ("\tforced copy from %s to %s\n", - mono_arch_regname (src), mono_arch_regname (dest))); - return copy; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - create_spilled_store */ -/* */ -/* Function - Spill register to storage. */ -/* */ -/*------------------------------------------------------------------*/ - -static MonoInst* -create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins) -{ - MonoInst *store; - MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG); - store->sreg1 = reg; - store->inst_destbasereg = cfg->frame_reg; - store->inst_offset = mono_spillvar_offset (cfg, spill); - if (ins) { - store->next = ins->next; - ins->next = store; + break; } - DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", - spill, store->inst_offset, prev_reg, mono_arch_regname (reg))); - return store; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - create_spilled_store_float */ -/* */ -/* Function - Spill floating point register to storage. */ -/* */ -/*------------------------------------------------------------------*/ -static MonoInst* -create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins) -{ - MonoInst *store; - MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG); - store->sreg1 = reg; - store->inst_destbasereg = cfg->frame_reg; - store->inst_offset = mono_spillvar_offset_float (cfg, spill); - if (ins) { - store->next = ins->next; - ins->next = store; - } - DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", - spill, store->inst_offset, prev_reg, mono_arch_regname (reg))); - return store; + return code; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - insert_before_ins */ -/* */ -/* Function - Insert an instruction before another. */ -/* */ -/*------------------------------------------------------------------*/ - -static void -insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert) +void +mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *prev; - g_assert (item->next); - prev = item->next->data; - - while (prev->next != ins) - prev = prev->next; - to_insert->next = ins; - prev->next = to_insert; - /* - * needed otherwise in the next instruction we can add an ins to the - * end and that would get past this instruction. - */ - item->data = to_insert; } -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ -/* Name - alloc_int_reg */ +/* Name - mono_arch_peephole_pass */ /* */ -/* Function - Allocate a general register. */ +/* Function - Form a peephole pass at the code looking for */ +/* simple optimizations. */ /* */ /*------------------------------------------------------------------*/ -static int -alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask) +void +mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) { - int val = cfg->rs->iassign [sym_reg]; - DEBUG (g_print ("Allocating a general register for %d (%d) with mask %08x\n",val,sym_reg,allow_mask)); - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (cfg->rs, allow_mask); - if (val < 0) - val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg); - cfg->rs->iassign [sym_reg] = val; - /* add option to store before the instruction for src registers */ - if (spill) - create_spilled_store (cfg, spill, val, sym_reg, ins); + MonoInst *ins, *n; + + MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) { + mono_peephole_ins (bb, ins); } - DEBUG (g_print ("Allocated %d for %d\n",val,sym_reg)); - cfg->rs->isymbolic [val] = sym_reg; - return val; } /*========================= 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_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) { - MonoInst *ins; - MonoRegState *rs = cfg->rs; - int i, val; - RegTrack *reginfo, *reginfof; - RegTrack *reginfo1, *reginfo2, *reginfod; - InstList *tmp, *reversed = NULL; - const char *spec; - guint32 src1_mask, src2_mask, dest_mask; - guint32 cur_iregs, cur_fregs; - - if (!bb->code) - return; - rs->next_vireg = bb->max_ireg; - rs->next_vfreg = bb->max_freg; - mono_regstate_assign (rs); - reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg); - reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg); - rs->ifree_mask = S390_CALLER_REGS; - rs->ffree_mask = S390_CALLER_FREGS; - - ins = bb->code; - i = 1; - DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num)); - /* forward pass on the instructions to collect register liveness info */ - while (ins) { - spec = ins_spec [ins->opcode]; - DEBUG (print_ins (i, ins)); -// if (spec [MONO_INST_CLOB] == 'c') { -// MonoCallInst * call = (MonoCallInst*)ins; -// int j; -// } - if (spec [MONO_INST_SRC1]) { - if (spec [MONO_INST_SRC1] == 'f') - reginfo1 = reginfof; - else - reginfo1 = reginfo; - reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use; - reginfo1 [ins->sreg1].last_use = i; - } else { - ins->sreg1 = -1; - } - if (spec [MONO_INST_SRC2]) { - if (spec [MONO_INST_SRC2] == 'f') - reginfo2 = reginfof; - else - reginfo2 = reginfo; - reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use; - reginfo2 [ins->sreg2].last_use = i; - } else { - ins->sreg2 = -1; - } - if (spec [MONO_INST_DEST]) { - if (spec [MONO_INST_DEST] == 'f') - reginfod = reginfof; - else - reginfod = reginfo; - if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */ - reginfod [ins->dreg].killed_in = i; - reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use; - reginfod [ins->dreg].last_use = i; - if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i) - reginfod [ins->dreg].born_in = i; - if (spec [MONO_INST_DEST] == 'l') { - /* result in R2/R3, the virtual register is allocated sequentially */ - reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use; - reginfod [ins->dreg + 1].last_use = i; - if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i) - reginfod [ins->dreg + 1].born_in = i; - } - } else { - ins->dreg = -1; - } - reversed = inst_list_prepend (cfg->mempool, reversed, ins); - ++i; - ins = ins->next; - } - - cur_iregs = S390_CALLER_REGS; - cur_fregs = S390_CALLER_FREGS; - - DEBUG (print_regtrack (reginfo, rs->next_vireg)); - DEBUG (print_regtrack (reginfof, rs->next_vfreg)); - tmp = reversed; - while (tmp) { - int prev_dreg, prev_sreg1, prev_sreg2; - --i; - ins = tmp->data; - spec = ins_spec [ins->opcode]; - DEBUG (g_print ("processing:")); - DEBUG (print_ins (i, ins)); - /* make the register available for allocation: FIXME add fp reg */ - if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) { - cur_iregs |= 1 << ins->dreg; - DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg)); - } else if (ins->opcode == OP_SETFREG) { - cur_fregs |= 1 << ins->dreg; - DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg)); - } else if (spec [MONO_INST_CLOB] == 'c') { - MonoCallInst *cinst = (MonoCallInst*)ins; - DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", - cinst->used_iregs, cur_iregs)); - DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", - cinst->used_fregs, cur_fregs)); - cur_iregs &= ~cinst->used_iregs; - cur_fregs &= ~cinst->used_fregs; - DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs)); - DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs)); - /*------------------------------------------------------------*/ - /* registers used by the calling convention are excluded from */ - /* allocation: they will be selectively enabled when they are */ - /* assigned by the special SETREG opcodes. */ - /*------------------------------------------------------------*/ - } - dest_mask = src1_mask = src2_mask = cur_iregs; - /*------------------------------------------------------*/ - /* update for use with FP regs... */ - /*------------------------------------------------------*/ - if (spec [MONO_INST_DEST] == 'f') { - dest_mask = cur_fregs; - if (ins->dreg >= MONO_MAX_FREGS) { - val = rs->fassign [ins->dreg]; - prev_dreg = ins->dreg; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_float (rs, dest_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg); - rs->fassign [ins->dreg] = val; - if (spill) - create_spilled_store_float (cfg, spill, val, prev_dreg, ins); - } - DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", - mono_arch_regname (val), ins->dreg)); - rs->fsymbolic [val] = prev_dreg; - ins->dreg = val; - if (spec [MONO_INST_CLOB] == 'c' && ins->dreg != s390_f0) { - /* this instruction only outputs to s390_f0, need to copy */ - create_copy_ins_float (cfg, ins->dreg, s390_f0, ins); - } - } else { - prev_dreg = -1; - } - if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) { - DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in)); - mono_regstate_free_float (rs, ins->dreg); - } - } else if (ins->dreg >= MONO_MAX_IREGS) { - val = rs->iassign [ins->dreg]; - prev_dreg = ins->dreg; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (rs, dest_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg); - rs->iassign [ins->dreg] = val; - if (spill) - create_spilled_store (cfg, spill, val, prev_dreg, ins); - } - DEBUG (g_print ("\tassigned dreg %s to dest R%d (prev: R%d)\n", - mono_arch_regname (val), ins->dreg, prev_dreg)); - rs->isymbolic [val] = prev_dreg; - ins->dreg = val; - if (spec [MONO_INST_DEST] == 'l') { - int hreg = prev_dreg + 1; - val = rs->iassign [hreg]; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (rs, dest_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg); - rs->iassign [hreg] = val; - if (spill) - create_spilled_store (cfg, spill, val, hreg, ins); - } - DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg)); - rs->isymbolic [val] = hreg; - /* FIXME:? ins->dreg = val; */ - if (ins->dreg == s390_r3) { - if (val != s390_r2) - create_copy_ins (cfg, val, s390_r2, ins); - } else if (ins->dreg == s390_r2) { - if (val == s390_r3) { - /* swap */ - create_copy_ins (cfg, s390_r3, s390_r0, ins); - create_copy_ins (cfg, s390_r2, s390_r3, ins); - create_copy_ins (cfg, s390_r0, s390_r2, ins); - } else { - /* two forced copies */ - create_copy_ins (cfg, ins->dreg, s390_r3, ins); - create_copy_ins (cfg, val, s390_r2, ins); - } - } else { - if (val == s390_r2) { - create_copy_ins (cfg, ins->dreg, s390_r2, ins); - } else { - /* two forced copies */ - create_copy_ins (cfg, val, s390_r2, ins); - create_copy_ins (cfg, ins->dreg, s390_r3, ins); - } - } - if (reg_is_freeable (val) && - hreg >= 0 && - (reginfo [hreg].born_in >= i && - !(cur_iregs & (1 << val)))) { - DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg)); - mono_regstate_free_int (rs, val); - } - } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != s390_r2 && spec [MONO_INST_CLOB] != 'd') { - /* this instruction only outputs to s390_r2, need to copy */ - create_copy_ins (cfg, ins->dreg, s390_r2, ins); - } - } else { - prev_dreg = -1; - } - if (spec [MONO_INST_DEST] == 'f' && - freg_is_freeable (ins->dreg) && - prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i)) { - DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in)); - mono_regstate_free_float (rs, ins->dreg); - } else if (spec [MONO_INST_DEST] != 'f' && - reg_is_freeable (ins->dreg) && - prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) { - DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in)); - mono_regstate_free_int (rs, ins->dreg); - } - if (spec [MONO_INST_SRC1] == 'f') { - src1_mask = cur_fregs; - if (ins->sreg1 >= MONO_MAX_FREGS) { - val = rs->fassign [ins->sreg1]; - prev_sreg1 = ins->sreg1; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_float (rs, src1_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1); - rs->fassign [ins->sreg1] = val; - DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1)); - if (spill) { - MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL); - insert_before_ins (ins, tmp, store); - } - } - rs->fsymbolic [val] = prev_sreg1; - ins->sreg1 = val; - } else { - prev_sreg1 = -1; - } - } else if (ins->sreg1 >= MONO_MAX_IREGS) { - val = rs->iassign [ins->sreg1]; - prev_sreg1 = ins->sreg1; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (rs, src1_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, - src1_mask, - ins->sreg1); - rs->iassign [ins->sreg1] = val; - DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", - mono_arch_regname (val), ins->sreg1)); - if (spill) { - MonoInst *store; - store = create_spilled_store (cfg, spill, val, - prev_sreg1, NULL); - insert_before_ins (ins, tmp, store); - } - } - rs->isymbolic [val] = prev_sreg1; - ins->sreg1 = val; - } else { - prev_sreg1 = -1; - } - /*----------------------------------------------*/ - /* handle clobbering of sreg1 */ - /*----------------------------------------------*/ - if ((spec [MONO_INST_CLOB] == '1' || - spec [MONO_INST_CLOB] == 's') && - ins->dreg != ins->sreg1) { - MonoInst *copy; - copy = create_copy_ins (cfg, ins->dreg, ins->sreg1, NULL); - DEBUG (g_print ("\tneed to copy sreg1 %s to dreg %s\n", - mono_arch_regname (ins->sreg1), - mono_arch_regname (ins->dreg))); - if (ins->sreg2 == -1 || spec [MONO_INST_CLOB] == 's') { - /* note: the copy is inserted before the current instruction! */ - insert_before_ins (ins, tmp, copy); - /* we set sreg1 to dest as well */ - prev_sreg1 = ins->sreg1 = ins->dreg; - } else { - /* inserted after the operation */ - copy->next = ins->next; - ins->next = copy; - } - } - - if (spec [MONO_INST_SRC2] == 'f') { - src2_mask = cur_fregs; - if (ins->sreg2 >= MONO_MAX_FREGS) { - val = rs->fassign [ins->sreg2]; - prev_sreg2 = ins->sreg2; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_float (rs, src2_mask); - if (val < 0) - val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2); - rs->fassign [ins->sreg2] = val; - DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2)); - if (spill) - create_spilled_store_float (cfg, spill, val, prev_sreg2, ins); - } - rs->fsymbolic [val] = prev_sreg2; - ins->sreg2 = val; - } else { - prev_sreg2 = -1; - } - } else if (ins->sreg2 >= MONO_MAX_IREGS) { - val = rs->iassign [ins->sreg2]; - prev_sreg2 = ins->sreg2; - if (val < 0) { - int spill = 0; - if (val < -1) { - /* the register gets spilled after this inst */ - spill = -val -1; - } - val = mono_regstate_alloc_int (rs, src2_mask); - if (val < 0) - val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2); - rs->iassign [ins->sreg2] = val; - DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2)); - if (spill) - create_spilled_store (cfg, spill, val, prev_sreg2, ins); - } - rs->isymbolic [val] = prev_sreg2; - ins->sreg2 = val; - } else { - prev_sreg2 = -1; - } + MonoInst *ins, *next; - if (spec [MONO_INST_CLOB] == 'c') { - int j, s; - guint32 clob_mask = S390_CALLER_REGS; - for (j = 0; j < MONO_MAX_IREGS; ++j) { - s = 1 << j; - if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) { - //g_warning ("register %s busy at call site\n", mono_arch_regname (j)); - } - } + 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_LOCALLOC_IMM: + mono_decompose_op_imm (cfg, bb, ins); + break; + default: + break; } - tmp = tmp->next; } + + bb->max_vreg = cfg->next_vreg; } /*========================= End of Function ========================*/ @@ -3162,16 +2567,18 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, break; } } else { + short *o[1]; s390_basr (code, s390_r13, 0); s390_j (code, 10); - s390_llong (code, 0x41e0000000000000); - s390_llong (code, 0x41f0000000000000); + s390_llong (code, 0x41e0000000000000LL); + s390_llong (code, 0x41f0000000000000LL); s390_ldr (code, s390_f15, sreg); - s390_cdb (code, s390_f15, 0, s390_r13, 0); - s390_jl (code, 10); - s390_sdb (code, s390_f15, 0, s390_r13, 8); + s390_cdb (code, s390_f15, 0, s390_r13, 4); + s390_jl (code, 0); CODEPTR(code, o[0]); + s390_sdb (code, s390_f15, 0, s390_r13, 12); s390_cfdbr (code, dreg, 7, s390_f15); s390_j (code, 4); + PTRSLOT(code, o[0]); s390_cfdbr (code, dreg, 5, sreg); switch (size) { case 1: @@ -3190,22 +2597,6 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_emit_stack_alloc */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ - -static unsigned char* -mono_emit_stack_alloc (guchar *code, MonoInst* tree) -{ - return code; -} - -/*========================= End of Function ========================*/ - /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_output_basic_block */ @@ -3226,9 +2617,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) 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) @@ -3247,11 +2635,10 @@ 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_spec [ins->opcode])[MONO_INST_LEN]; + max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; if (offset > (cfg->code_size - max_len - 16)) { cfg->code_size *= 2; @@ -3290,7 +2677,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_STORE_MEMBASE_IMM: case OP_STOREI4_MEMBASE_IMM: { - if (s390_is_uimm16(ins->inst_imm)) { + if (s390_is_imm16(ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); } else { s390_basr (code, s390_r13, 0); @@ -3346,16 +2733,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_LDIND_I: - case CEE_LDIND_I4: - case CEE_LDIND_U4: { - s390_basr (code, s390_r13, 0); - s390_j (code, 4); - s390_word (code, ins->inst_p0); - s390_l (code, s390_r13, 0, s390_r13, 4); - s390_l (code, ins->dreg, 0, s390_r13, 0); - } - break; case OP_LOADU4_MEM: g_assert_not_reached (); break; @@ -3365,7 +2742,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (s390_is_uimm12(ins->inst_offset)) s390_l (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); else { - if (s390_is_uimm16(ins->inst_offset)) { + if (s390_is_imm16(ins->inst_offset)) { s390_lhi (code, s390_r13, ins->inst_offset); s390_l (code, ins->dreg, s390_r13, ins->inst_basereg, 0); } else { @@ -3440,32 +2817,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lr (code, ins->dreg, s390_r0); } break; - case CEE_CONV_I1: { - s390_lhi (code, s390_r0, 0x80); - if (ins->dreg != ins->sreg1) { + + case OP_ICONV_TO_I1: { + 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); + s390_sll (code, ins->dreg, 0, 24); + s390_sra (code, ins->dreg, 0, 24); } break; - case CEE_CONV_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); + case OP_ICONV_TO_I2: { + if (ins->dreg != ins->sreg1) + s390_lr (code, ins->dreg, ins->sreg1); + s390_sll (code, ins->dreg, 0, 16); + s390_sra (code, ins->dreg, 0, 16); } break; - case CEE_CONV_U1: { + case OP_ICONV_TO_U1: { s390_lhi (code, s390_r0, 0xff); if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); @@ -3473,7 +2840,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_nr (code, ins->dreg, s390_r0); } break; - case CEE_CONV_U2: { + 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); @@ -3483,29 +2850,51 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_nr (code, ins->dreg, s390_r0); } break; - case OP_COMPARE: { - if ((ins->next) && - ((ins->next->opcode >= CEE_BNE_UN) && - (ins->next->opcode <= CEE_BLT_UN)) || - ((ins->next->opcode >= OP_COND_EXC_NE_UN) && - (ins->next->opcode <= OP_COND_EXC_LT_UN)) || - ((ins->next->opcode == OP_CLT_UN) || - (ins->next->opcode == OP_CGT_UN))) + case OP_COMPARE: + case OP_ICOMPARE: { + gboolean un = FALSE; + MonoInst *next = ins->next; + + if ((next) && + (((next->opcode >= OP_IBNE_UN) && + (next->opcode <= OP_IBLT_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)))) + un = TRUE; + + if (un) s390_clr (code, ins->sreg1, ins->sreg2); else s390_cr (code, ins->sreg1, ins->sreg2); } break; - case OP_COMPARE_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + case OP_COMPARE_IMM: + case OP_ICOMPARE_IMM: { + gboolean un = FALSE; + MonoInst *next = ins->next; + + if ((next) && + (((next->opcode >= OP_IBNE_UN) && + (next->opcode <= OP_IBLT_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)))) + un = TRUE; + + if (s390_is_imm16 (ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); - if ((ins->next) && - ((ins->next->opcode >= CEE_BNE_UN) && - (ins->next->opcode <= CEE_BLT_UN)) || - ((ins->next->opcode >= OP_COND_EXC_NE_UN) && - (ins->next->opcode <= OP_COND_EXC_LT_UN)) || - ((ins->next->opcode == OP_CLT_UN) || - (ins->next->opcode == OP_CGT_UN))) + if (un) s390_clr (code, ins->sreg1, s390_r0); else s390_cr (code, ins->sreg1, s390_r0); @@ -3514,44 +2903,59 @@ 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) && - ((ins->next->opcode >= CEE_BNE_UN) && - (ins->next->opcode <= CEE_BLT_UN)) || - ((ins->next->opcode >= OP_COND_EXC_NE_UN) && - (ins->next->opcode <= OP_COND_EXC_LT_UN)) || - ((ins->next->opcode == OP_CLT_UN) && - (ins->next->opcode == OP_CGT_UN))) + if (un) s390_cl (code, ins->sreg1, 0, s390_r13, 4); else s390_c (code, ins->sreg1, 0, s390_r13, 4); } } break; - case OP_X86_TEST_NULL: { - s390_ltr (code, ins->sreg1, ins->sreg1); + case OP_BREAK: { + mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, mono_break); + s390_brasl (code, s390_r14, 0); } break; - case CEE_BREAK: { - s390_break (code); - } - break; - case OP_ADDCC: { + case OP_ADDCC: + case OP_IADDCC: { CHECK_SRCDST_COM; s390_alr (code, ins->dreg, src2); } break; - case CEE_ADD: { + case OP_IADD: { CHECK_SRCDST_COM; s390_ar (code, ins->dreg, src2); } break; - case OP_ADC: { + case OP_ADC: + case OP_IADC: { CHECK_SRCDST_COM; s390_alcr (code, ins->dreg, src2); } break; - case OP_ADDCC_IMM: - case OP_ADD_IMM: { + case OP_ADD_IMM: + case OP_IADD_IMM: { + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } + if ((ins->next) && + (ins->next->opcode == OP_ADC_IMM)) { + s390_basr (code, s390_r13, 0); + s390_j (code, 4); + s390_word (code, ins->inst_imm); + s390_a (code, ins->dreg, 0, s390_r13, 4); + } else { + if (s390_is_imm16 (ins->inst_imm)) { + s390_ahi (code, ins->dreg, ins->inst_imm); + } else { + s390_basr (code, s390_r13, 0); + s390_j (code, 4); + s390_word (code, ins->inst_imm); + s390_a (code, ins->dreg, 0, s390_r13, 4); + } + } + } + break; + case OP_ADDCC_IMM: { if ((ins->next) && (ins->next->opcode == OP_ADC_IMM)) { s390_basr (code, s390_r13, 0); @@ -3562,11 +2966,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } s390_al (code, ins->dreg, 0, s390_r13, 4); } else { - if (s390_is_uimm16 (ins->inst_imm)) { + if (s390_is_imm16 (ins->inst_imm)) { if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } - s390_ahi (code, ins->dreg, ins->inst_imm); + s390_lhi (code, s390_r0, ins->inst_imm); + s390_alcr (code, ins->dreg, s390_r0); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); @@ -3574,13 +2979,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } - s390_a (code, ins->dreg, 0, s390_r13, 4); + s390_al (code, ins->dreg, 0, s390_r13, 4); } } } break; case OP_ADC_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + if (s390_is_imm16 (ins->inst_imm)) { if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } @@ -3595,18 +3000,53 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_ADD_OVF: { + case OP_IADD_OVF: + case OP_S390_IADD_OVF: { CHECK_SRCDST_COM; s390_ar (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); } break; - case CEE_ADD_OVF_UN: { + case OP_IADD_OVF_UN: + case OP_S390_IADD_OVF_UN: { CHECK_SRCDST_COM; s390_alr (code, ins->dreg, src2); EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException"); } break; + case OP_LADD: + case OP_S390_LADD: { + s390_alr (code, s390_r0, ins->sreg1); + s390_jnc (code, 4); + s390_ahi (code, s390_r1, 1); + s390_ar (code, s390_r1, ins->sreg2); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; + case OP_LADD_OVF: + case OP_S390_LADD_OVF: { + short int *o[1]; + s390_alr (code, s390_r0, ins->sreg1); + s390_jnc (code, 0); CODEPTR(code, o[0]); + s390_ahi (code, s390_r1, 1); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + PTRSLOT (code, o[0]); + s390_ar (code, s390_r1, ins->sreg2); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; + case OP_LADD_OVF_UN: + case OP_S390_LADD_OVF_UN: { + s390_alr (code, s390_r0, ins->sreg1); + s390_alcr (code, s390_r1, ins->sreg2); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException"); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; case OP_ADD_OVF_CARRY: { CHECK_SRCDST_COM; s390_lhi (code, s390_r0, 0); @@ -3624,27 +3064,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_SYSTEM_EXCEPTION (S390_CC_CY, "OverflowException"); } break; - case OP_SUBCC: { + case OP_SUBCC: + case OP_ISUBCC: { CHECK_SRCDST_NCOM; s390_slr (code, ins->dreg, src2); } break; - case CEE_SUB: { + case OP_ISUB: { CHECK_SRCDST_NCOM; s390_sr (code, ins->dreg, src2); } break; - case OP_SBB: { + case OP_SBB: + case OP_ISBB: { CHECK_SRCDST_NCOM; s390_slbr (code, ins->dreg, src2); } break; case OP_SUBCC_IMM: { - if (s390_is_uimm16 (-ins->inst_imm)) { + if (s390_is_imm16 (-ins->inst_imm)) { if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } - s390_ahi (code, ins->dreg, -ins->inst_imm); + s390_lhi (code, s390_r0, ins->inst_imm); + s390_slr (code, ins->dreg, s390_r0); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); @@ -3656,8 +3099,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_SUB_IMM: { - if (s390_is_uimm16 (-ins->inst_imm)) { + case OP_SUB_IMM: + case OP_ISUB_IMM: { + if (s390_is_imm16 (-ins->inst_imm)) { if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } @@ -3677,7 +3121,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } - if (s390_is_uimm16 (-ins->inst_imm)) { + if (s390_is_imm16 (-ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); s390_slbr (code, ins->dreg, s390_r0); } else { @@ -3688,18 +3132,55 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } 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"); } 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"); } break; + case OP_LSUB: + case OP_S390_LSUB: { + s390_lr (code, s390_r14, ins->sreg2); + s390_slr (code, s390_r0, ins->sreg1); + s390_jnl (code, 4); + s390_ahi (code, s390_r14, 1); + s390_sr (code, s390_r1, s390_r14); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; + case OP_LSUB_OVF: + case OP_S390_LSUB_OVF: { + short int *o[1]; + s390_lr (code, s390_r14, ins->sreg2); + s390_slr (code, s390_r0, ins->sreg1); + s390_jnl (code, 0); CODEPTR(code, o[0]); + s390_ahi (code, s390_r14, 1); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + PTRSLOT (code, o[0]); + s390_sr (code, s390_r1, s390_r14); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_OV, "OverflowException"); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; + case OP_LSUB_OVF_UN: + case OP_S390_LSUB_OVF_UN: { + s390_slr (code, s390_r0, ins->sreg1); + s390_slbr (code, s390_r1, ins->sreg2); + EMIT_COND_SYSTEM_EXCEPTION (S390_CC_LT, "OverflowException"); + s390_lr (code, ins->dreg, s390_r0); + s390_lr (code, ins->dreg+1, s390_r1); + } + break; case OP_SUB_OVF_CARRY: { CHECK_SRCDST_NCOM; s390_lhi (code, s390_r0, 0); @@ -3717,7 +3198,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) EMIT_COND_SYSTEM_EXCEPTION (S390_CC_NC, "OverflowException"); } break; - case CEE_AND: { + case OP_IAND: { if (ins->sreg1 == ins->dreg) { s390_nr (code, ins->dreg, ins->sreg2); } @@ -3732,8 +3213,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_AND_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + case OP_AND_IMM: + case OP_IAND_IMM: { + if (s390_is_imm16 (ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); @@ -3750,66 +3232,34 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_DIV: { + case OP_IDIV: { s390_lr (code, s390_r0, ins->sreg1); s390_srda (code, s390_r0, 0, 32); s390_dr (code, s390_r0, ins->sreg2); s390_lr (code, ins->dreg, s390_r1); } break; - case CEE_DIV_UN: { + case OP_IDIV_UN: { s390_lr (code, s390_r0, ins->sreg1); s390_srdl (code, s390_r0, 0, 32); s390_dlr (code, s390_r0, ins->sreg2); s390_lr (code, ins->dreg, s390_r1); } break; - case OP_DIV_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { - s390_lhi (code, s390_r13, ins->inst_imm); - s390_lr (code, s390_r0, ins->sreg1); - } else { - s390_basr (code, s390_r13, 0); - s390_j (code, 4); - s390_word (code, ins->inst_imm); - s390_lr (code, s390_r0, ins->sreg1); - s390_l (code, s390_r13, 0, s390_r13, 4); - } - s390_srda (code, s390_r0, 0, 32); - s390_dr (code, s390_r0, s390_r13); - s390_lr (code, ins->dreg, s390_r1); - } - break; - case CEE_REM: { + case OP_IREM: { s390_lr (code, s390_r0, ins->sreg1); s390_srda (code, s390_r0, 0, 32); s390_dr (code, s390_r0, ins->sreg2); s390_lr (code, ins->dreg, s390_r0); break; - case CEE_REM_UN: + case OP_IREM_UN: s390_lr (code, s390_r0, ins->sreg1); s390_srdl (code, s390_r0, 0, 32); s390_dlr (code, s390_r0, ins->sreg2); s390_lr (code, ins->dreg, s390_r0); } break; - case OP_REM_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { - s390_lhi (code, s390_r13, ins->inst_imm); - s390_lr (code, s390_r0, ins->sreg1); - } else { - s390_basr (code, s390_r13, 0); - s390_j (code, 4); - s390_word (code, ins->inst_imm); - s390_lr (code, s390_r0, ins->sreg1); - s390_l (code, s390_r13, 0, s390_r13, 4); - } - s390_srda (code, s390_r0, 0, 32); - s390_dr (code, s390_r0, s390_r13); - s390_lr (code, ins->dreg, s390_r0); - } - break; - case CEE_OR: { + case OP_IOR: { if (ins->sreg1 == ins->dreg) { s390_or (code, ins->dreg, ins->sreg2); } @@ -3824,8 +3274,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_OR_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + case OP_OR_IMM: + case OP_IOR_IMM: { + if (s390_is_imm16 (ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); @@ -3842,7 +3293,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_XOR: { + case OP_IXOR: { if (ins->sreg1 == ins->dreg) { s390_xr (code, ins->dreg, ins->sreg2); } @@ -3857,8 +3308,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_XOR_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + case OP_XOR_IMM: + case OP_IXOR_IMM: { + if (s390_is_imm16 (ins->inst_imm)) { s390_lhi (code, s390_r0, ins->inst_imm); if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); @@ -3875,43 +3327,46 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case CEE_SHL: { + case OP_ISHL: { CHECK_SRCDST_NCOM; s390_sll (code, ins->dreg, src2, 0); } break; - case OP_SHL_IMM: { + case OP_SHL_IMM: + case OP_ISHL_IMM: { if (ins->sreg1 != ins->dreg) { s390_lr (code, ins->dreg, ins->sreg1); } s390_sll (code, ins->dreg, 0, (ins->inst_imm & 0x1f)); } break; - case CEE_SHR: { + case OP_ISHR: { CHECK_SRCDST_NCOM; s390_sra (code, ins->dreg, src2, 0); } break; - case OP_SHR_IMM: { + case OP_SHR_IMM: + case OP_ISHR_IMM: { if (ins->sreg1 != ins->dreg) { s390_lr (code, ins->dreg, ins->sreg1); } s390_sra (code, ins->dreg, 0, (ins->inst_imm & 0x1f)); } break; - case OP_SHR_UN_IMM: { + case OP_SHR_UN_IMM: + case OP_ISHR_UN_IMM: { if (ins->sreg1 != ins->dreg) { s390_lr (code, ins->dreg, ins->sreg1); } s390_srl (code, ins->dreg, 0, (ins->inst_imm & 0x1f)); } break; - case CEE_SHR_UN: { + case OP_ISHR_UN: { CHECK_SRCDST_NCOM; s390_srl (code, ins->dreg, src2, 0); } break; - case CEE_NOT: { + case OP_INOT: { if (ins->sreg1 != ins->dreg) { s390_lr (code, ins->dreg, ins->sreg1); } @@ -3919,11 +3374,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_xr (code, ins->dreg, s390_r0); } break; - case CEE_NEG: { + case OP_INEG: { + s390_lcr (code, ins->dreg, ins->sreg1); + } + break; + case OP_S390_LNEG: { + /* From gcc code */ + g_assert (ins->dreg + 1 != ins->sreg1); + s390_lcr (code, ins->dreg + 1, ins->sreg2); s390_lcr (code, ins->dreg, ins->sreg1); + s390_je (code, 3); + s390_bctr (code, ins->dreg + 1, 0); } break; - case CEE_MUL: { + case OP_IMUL: { if (ins->sreg1 == ins->dreg) { s390_msr (code, ins->dreg, ins->sreg2); } @@ -3938,22 +3402,26 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } break; - case OP_MUL_IMM: { - if (s390_is_uimm16 (ins->inst_imm)) { + case OP_MUL_IMM: + case OP_IMUL_IMM: { + if (s390_is_imm16 (ins->inst_imm)) { s390_lhi (code, s390_r13, ins->inst_imm); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); s390_word (code, ins->inst_imm); - if (ins->dreg != ins->sreg1) { - s390_lr (code, ins->dreg, ins->sreg1); - } +// if (ins->dreg != ins->sreg1) { +// s390_lr (code, ins->dreg, ins->sreg1); +// } s390_l (code, s390_r13, 0, s390_r13, 4); } + if (ins->dreg != ins->sreg1) { + s390_lr (code, ins->dreg, ins->sreg1); + } s390_msr (code, ins->dreg, s390_r13); } break; - case CEE_MUL_OVF: { + case OP_IMUL_OVF: { short int *o[2]; s390_ltr (code, s390_r1, ins->sreg1); s390_jz (code, 0); CODEPTR(code, o[0]); @@ -3972,7 +3440,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lr (code, ins->dreg, s390_r1); } break; - case CEE_MUL_OVF_UN: { + case OP_IMUL_OVF_UN: { s390_lhi (code, s390_r0, 0); s390_lr (code, s390_r1, ins->sreg1); s390_mlr (code, s390_r0, ins->sreg2); @@ -3996,9 +3464,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_st (code, s390_r1, 0, ins->dreg, 4); } break; - case OP_ICONST: - case OP_SETREGIMM: { - if (s390_is_uimm16(ins->inst_c0)) { + case OP_ICONST: { + if (s390_is_imm16(ins->inst_c0)) { s390_lhi (code, ins->dreg, ins->inst_c0); } else { s390_basr (code, s390_r13, 0); @@ -4017,10 +3484,18 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_l (code,ins->dreg, 0, s390_r13, 4); } break; - case CEE_CONV_I4: - case CEE_CONV_U4: - case OP_MOVE: - case OP_SETREG: { + 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, 4); + s390_word (code, 0); + s390_l (code, ins->dreg, 0, s390_r13, 4); + } + break; + case OP_ICONV_TO_I4: + case OP_ICONV_TO_U4: + case OP_MOVE: { if (ins->dreg != ins->sreg1) { s390_lr (code, ins->dreg, ins->sreg1); } @@ -4038,7 +3513,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lr (code, s390_r3, saved); break; } - case OP_SETFREG: case OP_FMOVE: { if (ins->dreg != ins->sreg1) { s390_ldr (code, ins->dreg, ins->sreg1); @@ -4050,7 +3524,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_TLS_GET: { - if (s390_is_uimm16 (ins->inst_offset)) { + if (s390_is_imm16 (ins->inst_offset)) { s390_lhi (code, s390_r13, ins->inst_offset); } else { s390_bras (code, s390_r13, 0); @@ -4063,33 +3537,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_FCONV_TO_R4: { + // FIXME: + if (ins->dreg != ins->sreg1) { + s390_ldr (code, ins->dreg, ins->sreg1); + } + /* + NOT_IMPLEMENTED; if ((ins->next) && - (ins->next->opcode != OP_STORER4_MEMBASE_REG)) + (ins->next->opcode != OP_FMOVE) && + (ins->next->opcode != OP_STORER4_MEMBASE_REG)) s390_ledbr (code, ins->dreg, ins->sreg1); + */ } break; - case CEE_JMP: { - int iParm, fParm, pOffset; + case OP_JMP: { if (cfg->method->save_lmf) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); if (cfg->flags & MONO_CFG_HAS_TAIL) { - pOffset = S390_PARM_SAVE_OFFSET; - s390_l (code, s390_r13, 0, STK_BASE, 0); - for (iParm = s390_r2; - iParm <= s390_r5; - iParm++, pOffset+sizeof(gint32)) { - if (cfg->used_int_regs & (1 << iParm)) - s390_l (code, iParm, 0, s390_r13, pOffset); - } - pOffset = S390_FLOAT_SAVE_OFFSET; - for (fParm = 0; - fParm < 4; - fParm++, pOffset+sizeof(double)) - s390_ld (code, fParm, 0, s390_r13, pOffset); + code = emit_load_volatile_registers(code, cfg); } - code = backUpStackPtr(cfg, code); + code = backUpStackPtr(cfg, code, STK_BASE); s390_l (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET); mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, @@ -4105,7 +3574,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_ARGLIST: { int offset = cfg->sig_cookie + cfg->stack_usage; - if (s390_is_uimm16 (offset)) + if (s390_is_imm16 (offset)) s390_lhi (code, s390_r0, offset); else { s390_basr (code, s390_r13, 0); @@ -4132,8 +3601,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: { call = (MonoCallInst*)ins; if (ins->flags & MONO_INST_HAS_METHOD) mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method); @@ -4152,34 +3622,47 @@ 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_lr (code, s390_r1, ins->sreg1); s390_basr (code, s390_r14, s390_r1); } break; - case OP_FCALL_MEMBASE: { - call = (MonoCallInst*)ins; - s390_l (code, s390_r1, 0, ins->sreg1, ins->inst_offset); - s390_basr (code, s390_r14, s390_r1); - if (call->signature->ret->type == MONO_TYPE_R4) - s390_ldebr (code, s390_f0, s390_f0); - } - break; case OP_LCALL_MEMBASE: case OP_VCALL_MEMBASE: + case OP_VCALL2_MEMBASE: case OP_VOIDCALL_MEMBASE: + case OP_FCALL_MEMBASE: case OP_CALL_MEMBASE: { - s390_l (code, s390_r1, 0, ins->sreg1, ins->inst_offset); + call = (MonoCallInst*)ins; + if (s390_is_uimm12(ins->inst_offset)) + s390_l (code, s390_r1, 0, ins->inst_basereg, ins->inst_offset); + else { + if (s390_is_imm16(ins->inst_offset)) { + s390_lhi (code, s390_r13, ins->inst_offset); + s390_l (code, s390_r1, s390_r13, ins->inst_basereg, 0); + } else { + s390_basr (code, s390_r13, 0); + s390_j (code, 4); + s390_word (code, ins->inst_offset); + s390_l (code, s390_r13, 0, s390_r13, 4); + s390_l (code, s390_r1, s390_r13, ins->inst_basereg, 0); + } + } s390_basr (code, s390_r14, s390_r1); + if (ins->opcode == OP_FCALL_MEMBASE && call->signature->ret->type == MONO_TYPE_R4) + s390_ldebr (code, s390_f0, s390_f0); } break; - case OP_OUTARG: - g_assert_not_reached (); - break; case OP_LOCALLOC: { - int alloca_skip = S390_MINIMAL_STACK_SIZE + cfg->param_area + - S390_STACK_ALIGNMENT - 1; + /*------------------------------------------*/ + /* To allocate space on the stack we have */ + /* to allow room for parameters passed in */ + /* calls, the backchain pointer and round */ + /* it to our stack alignment requirements */ + /*------------------------------------------*/ + int alloca_skip = S390_MINIMAL_STACK_SIZE + cfg->param_area; int area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT); s390_lr (code, s390_r1, ins->sreg1); if (ins->flags & MONO_INST_INIT) @@ -4187,9 +3670,28 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_ahi (code, s390_r1, 14); s390_srl (code, s390_r1, 0, 3); s390_sll (code, s390_r1, 0, 3); + if (cfg->method->save_lmf) { + /*----------------------------------*/ + /* we have to adjust lmf ebp value */ + /*----------------------------------*/ + int lmfOffset = cfg->stack_usage - sizeof(MonoLMF); + + s390_lr (code, s390_r13, cfg->frame_reg); + if (s390_is_uimm16(lmfOffset)) + s390_ahi (code, s390_r13, lmfOffset); + else { + s390_basr (code, s390_r14, 0); + s390_j (code, 4); + s390_word (code, lmfOffset); + s390_a (code, s390_r13, 0, s390_r14, 4); + } + s390_lr (code, s390_r14, STK_BASE); + s390_sr (code, s390_r14, s390_r1); + s390_st (code, s390_r14, 0, s390_r13, + G_STRUCT_OFFSET(MonoLMF, ebp)); + } s390_l (code, s390_r13, 0, STK_BASE, 0); - s390_lcr (code, s390_r1, s390_r1); - s390_la (code, STK_BASE, STK_BASE, s390_r1, 0); + s390_sr (code, STK_BASE, s390_r1); s390_st (code, s390_r13, 0, STK_BASE, 0); s390_la (code, ins->dreg, 0, STK_BASE, area_offset); s390_srl (code, ins->dreg, 0, 3); @@ -4205,11 +3707,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_lr (code, s390_r2, ins->sreg1); mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_arch_throw_exception"); @@ -4224,48 +3722,51 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_START_HANDLER: { - if (s390_is_uimm12 (ins->inst_left->inst_offset)) { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); + if (s390_is_uimm12 (spvar->inst_offset)) { s390_st (code, s390_r14, 0, - ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + spvar->inst_basereg, + spvar->inst_offset); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); - s390_word (code, ins->inst_left->inst_offset); + s390_word (code, spvar->inst_offset); s390_l (code, s390_r13, 0, s390_r13, 4); s390_st (code, s390_r14, s390_r13, - ins->inst_left->inst_basereg, 0); + spvar->inst_basereg, 0); } } break; case OP_ENDFILTER: { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); if (ins->sreg1 != s390_r2) s390_lr (code, s390_r2, ins->sreg1); - if (s390_is_uimm12 (ins->inst_left->inst_offset)) { - s390_l (code, s390_r14, 0, ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + if (s390_is_uimm12 (spvar->inst_offset)) { + s390_l (code, s390_r14, 0, spvar->inst_basereg, + spvar->inst_offset); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); - s390_word (code, ins->inst_left->inst_offset); + s390_word (code, spvar->inst_offset); s390_l (code, s390_r13, 0, s390_r13, 4); s390_l (code, s390_r14, s390_r13, - ins->inst_left->inst_basereg, 0); + spvar->inst_basereg, 0); } s390_br (code, s390_r14); } break; - case CEE_ENDFINALLY: { - if (s390_is_uimm12 (ins->inst_left->inst_offset)) { - s390_l (code, s390_r14, 0, ins->inst_left->inst_basereg, - ins->inst_left->inst_offset); + case OP_ENDFINALLY: { + MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region); + if (s390_is_uimm12 (spvar->inst_offset)) { + s390_l (code, s390_r14, 0, spvar->inst_basereg, + spvar->inst_offset); } else { s390_basr (code, s390_r13, 0); s390_j (code, 4); - s390_word (code, ins->inst_left->inst_offset); + s390_word (code, spvar->inst_offset); s390_l (code, s390_r13, 0, s390_r13, 4); s390_l (code, s390_r14, s390_r13, - ins->inst_left->inst_basereg, 0); + spvar->inst_basereg, 0); } s390_br (code, s390_r14); } @@ -4274,103 +3775,131 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb); s390_brasl (code, s390_r14, 0); + mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb); } break; case OP_LABEL: { ins->inst_c0 = code - cfg->native_code; } break; - case CEE_BR: + case OP_RELAXED_NOP: + 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: { s390_br (code, ins->sreg1); } break; - case OP_CEQ: { + case OP_CEQ: + case OP_ICEQ: { s390_lhi (code, ins->dreg, 1); s390_jz (code, 4); s390_lhi (code, ins->dreg, 0); } break; - case OP_CLT: { + case OP_CLT: + case OP_ICLT: { s390_lhi (code, ins->dreg, 1); s390_jl (code, 4); s390_lhi (code, ins->dreg, 0); } break; - case OP_CLT_UN: { + case OP_CLT_UN: + case OP_ICLT_UN: { s390_lhi (code, ins->dreg, 1); s390_jlo (code, 4); s390_lhi (code, ins->dreg, 0); } break; - case OP_CGT: { + case OP_CGT: + case OP_ICGT: { s390_lhi (code, ins->dreg, 1); s390_jh (code, 4); s390_lhi (code, ins->dreg, 0); } break; - case OP_CGT_UN: { + case OP_CGT_UN: + case OP_ICGT_UN: { s390_lhi (code, ins->dreg, 1); s390_jho (code, 4); s390_lhi (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_IBEQ: EMIT_COND_BRANCH (ins, S390_CC_EQ); break; - case CEE_BNE_UN: + case OP_IBNE_UN: EMIT_COND_BRANCH (ins, S390_CC_NE); break; - case CEE_BLT: - case CEE_BLT_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_IBGT: + case OP_IBGT_UN: EMIT_COND_BRANCH (ins, S390_CC_GT); break; - case CEE_BGE: - case CEE_BGE_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_IBLE: + case OP_IBLE_UN: EMIT_COND_BRANCH (ins, S390_CC_LE); break; @@ -4449,7 +3978,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } 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); @@ -4460,11 +3989,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_adb (code, ins->dreg, 0, s390_r13, 4); } break; - case CEE_CONV_R4: { + case OP_ICONV_TO_R4: { s390_cdfbr (code, ins->dreg, ins->sreg1); } break; - case CEE_CONV_R8: { + case OP_ICONV_TO_R8: { s390_cdfbr (code, ins->dreg, ins->sreg1); } break; @@ -4497,7 +4026,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert_not_reached (); /* Implemented as helper calls */ break; - case OP_LCONV_TO_OVF_I: { + case OP_LCONV_TO_OVF_I: + case OP_LCONV_TO_OVF_I4_2: { /* Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000 */ short int *o[5]; s390_ltr (code, ins->sreg1, ins->sreg1); @@ -4507,8 +4037,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lhi (code, s390_r13, -1); s390_cr (code, ins->sreg2, s390_r13); s390_jnz (code, 0); CODEPTR(code, o[2]); - if (ins->dreg != ins->sreg1) - s390_lr (code, ins->dreg, ins->sreg1); s390_j (code, 0); CODEPTR(code, o[3]); PTRSLOT(code, o[0]); s390_ltr (code, ins->sreg2, ins->sreg2); @@ -4520,41 +4048,27 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_brasl (code, s390_r14, 0); PTRSLOT(code, o[3]); PTRSLOT(code, o[4]); + if (ins->dreg != ins->sreg1) + s390_lr (code, ins->dreg, ins->sreg1); } break; case OP_SQRT: { s390_sqdbr (code, ins->dreg, ins->sreg1); } break; - case OP_FADD: { - if (ins->dreg == ins->sreg1) - s390_adbr (code, ins->dreg, ins->sreg2); - else { - if (ins->dreg == ins->sreg2) - s390_adbr (code, ins->dreg, ins->sreg1); - else { - s390_ldr (code, ins->dreg, ins->sreg1); - s390_adbr (code, ins->dreg, ins->sreg2); - } - } - } - break; + case OP_FADD: { + CHECK_SRCDST_COM_F; + s390_adbr (code, ins->dreg, src2); + } + break; case OP_FSUB: { CHECK_SRCDST_NCOM_F; s390_sdbr (code, ins->dreg, src2); } break; case OP_FMUL: { - if (ins->dreg == ins->sreg1) - s390_mdbr (code, ins->dreg, ins->sreg2); - else { - if (ins->dreg == ins->sreg2) - s390_mdbr (code, ins->dreg, ins->sreg1); - else { - s390_ldr (code, ins->dreg, ins->sreg1); - s390_mdbr (code, ins->dreg, ins->sreg2); - } - } + CHECK_SRCDST_COM_F; + s390_mdbr (code, ins->dreg, src2); } break; case OP_FDIV: { @@ -4568,7 +4082,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FREM: { CHECK_SRCDST_NCOM_F; - s390_didbr (code, ins->dreg, ins->sreg2, 5, s390_f15); + s390_didbr (code, ins->dreg, src2, 5, s390_f15); } break; case OP_FCOMPARE: { @@ -4610,37 +4124,57 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lhi (code, ins->dreg, 0); } break; - case OP_FBEQ: - EMIT_COND_BRANCH (ins, S390_CC_EQ|S390_CC_OV); + case OP_FBEQ: { + short *o; + s390_jo (code, 0); CODEPTR(code, o); + EMIT_COND_BRANCH (ins, S390_CC_EQ); + PTRSLOT(code, o); + } break; case OP_FBNE_UN: EMIT_COND_BRANCH (ins, S390_CC_NE|S390_CC_OV); break; - case OP_FBLT: + case OP_FBLT: { + short *o; + s390_jo (code, 0); CODEPTR(code, o); EMIT_COND_BRANCH (ins, S390_CC_LT); + PTRSLOT(code, o); + } break; case OP_FBLT_UN: EMIT_COND_BRANCH (ins, S390_CC_LT|S390_CC_OV); break; - case OP_FBGT: + case OP_FBGT: { + short *o; + s390_jo (code, 0); CODEPTR(code, o); EMIT_COND_BRANCH (ins, S390_CC_GT); + PTRSLOT(code, o); + } break; case OP_FBGT_UN: EMIT_COND_BRANCH (ins, S390_CC_GT|S390_CC_OV); break; - case OP_FBGE: + case OP_FBGE: { + short *o; + s390_jo (code, 0); CODEPTR(code, o); EMIT_COND_BRANCH (ins, S390_CC_GE); + PTRSLOT(code, o); + } break; case OP_FBGE_UN: EMIT_COND_BRANCH (ins, S390_CC_GE|S390_CC_OV); break; - case OP_FBLE: + case OP_FBLE: { + short *o; + s390_jo (code, 0); CODEPTR(code, o); EMIT_COND_BRANCH (ins, S390_CC_LE); + PTRSLOT(code, o); + } break; 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); @@ -4652,39 +4186,44 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_S390_MOVE: { - if (ins->unused > 0) { - if (ins->unused <= 256) { - s390_mvc (code, ins->unused, ins->dreg, + if (ins->backend.size > 0) { + if (ins->backend.size <= 256) { + s390_mvc (code, ins->backend.size, ins->dreg, ins->inst_offset, ins->sreg1, ins->inst_imm); } else { - s390_lr (code, s390_r0, ins->dreg); - if (s390_is_uimm16 (ins->inst_offset)) { + s390_lr (code, s390_r0, ins->dreg); + if (s390_is_imm16 (ins->inst_offset)) { s390_ahi (code, s390_r0, ins->inst_offset); } else { s390_basr (code, s390_r13, 0); - s390_j (code, 4); - s390_word (code, ins->inst_offset); + s390_j (code, 6); + s390_long (code, ins->inst_offset); s390_a (code, s390_r0, 0, s390_r13, 4); } - s390_lr (code, s390_r14, s390_r12); - s390_lr (code, s390_r12, ins->sreg1); - if (s390_is_uimm16 (ins->inst_imm)) { + s390_lr (code, s390_r12, ins->sreg1); + if (s390_is_imm16 (ins->inst_imm)) { s390_ahi (code, s390_r12, ins->inst_imm); } else { s390_basr (code, s390_r13, 0); - s390_j (code, 4); - s390_word (code, ins->inst_imm); + s390_j (code, 6); + s390_long (code, ins->inst_imm); s390_a (code, s390_r12, 0, s390_r13, 4); } - s390_lr (code, s390_r1, ins->sreg1); + if (s390_is_imm16 (ins->backend.size)) { + s390x_lhi (code, s390_r1, ins->backend.size); + } else { + s390_basr (code, s390_r13, 0); + s390_j (code, 6); + s390_long (code, ins->backend.size); + s390_l (code, s390_r1, 0, s390_r13, 4); + } + s390_lr (code, s390_r1, ins->backend.size); s390_lr (code, s390_r13, s390_r1); s390_mvcle(code, s390_r0, s390_r12, 0, 0); s390_jo (code, -2); - s390_lr (code, s390_r12, s390_r14); } } } - break; case OP_ATOMIC_ADD_I4: { s390_lr (code, s390_r1, ins->sreg2); s390_l (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset); @@ -4708,6 +4247,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_cs (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); s390_jnz (code, -4); s390_lr (code, ins->dreg, s390_r0); + } + break; + case OP_S390_BKCHAIN: { + s390_lr (code, ins->dreg, ins->sreg1); + if (s390_is_imm16 (cfg->stack_offset)) { + s390_ahi (code, ins->dreg, cfg->stack_offset); + } else { + s390_basr (code, s390_r13, 0); + s390_j (code, 6); + s390_word (code, cfg->stack_offset); + s390_a (code, ins->dreg, 0, s390_r13, 4); + } + } + case OP_MEMORY_BARRIER: { } break; default: @@ -4725,8 +4278,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) last_ins = ins; last_offset = offset; - - ins = ins->next; } cfg->code_len = code - cfg->native_code; @@ -4745,8 +4296,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) void mono_arch_register_lowlevel_calls (void) { - mono_register_jit_icall (enter_method, "mono_enter_method", NULL, TRUE); - mono_register_jit_icall (leave_method, "mono_leave_method", NULL, TRUE); + mono_register_jit_icall (mono_arch_get_lmf_addr, "mono_arch_get_lmf_addr", NULL, TRUE); } /*========================= End of Function ========================*/ @@ -4763,7 +4313,7 @@ mono_arch_register_lowlevel_calls (void) void mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, - guint8 *code, MonoJumpInfo *ji, gboolean run_cctors) + guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors) { MonoJumpInfo *patch_info; @@ -4807,8 +4357,119 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, target = S390_RELATIVE(target, ip); ip += 2; } - s390_patch (ip, target); + s390_patch (ip, (guint32) target); + } +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - emit_load_volatile_registers */ +/* */ +/* Function - Create the instruction sequence for loading the */ +/* parameter registers for use with the 'tail' op. */ +/* */ +/* The register loading operations performed here */ +/* are the mirror of the store operations performed */ +/* in mono_arch_emit_prolog and need to be kept in */ +/* synchronization with it. */ +/* */ +/*------------------------------------------------------------------*/ + +guint8 * +emit_load_volatile_registers (guint8 * code, MonoCompile *cfg) +{ + MonoMethod *method = cfg->method; + MonoMethodSignature *sig; + MonoInst *inst; + int pos, i; + CallInfo *cinfo; + + sig = mono_method_signature (method); + pos = 0; + + cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke); + + if (cinfo->struct_ret) { + ArgInfo *ainfo = &cinfo->ret; + inst = cfg->vret_addr; + s390_l (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->args [pos]; + + if (inst->opcode == OP_REGVAR) { + if (ainfo->regtype == RegTypeGeneral) + s390_lr (code, ainfo->reg, inst->dreg); + else if (ainfo->regtype == RegTypeFP) { + if (inst->dreg != ainfo->reg) { + if (ainfo->size == 4) { + s390_ldebr (code, ainfo->reg, inst->dreg); + } else { + s390_ldr (code, ainfo->reg, inst->dreg); + } + } + } + else if (ainfo->regtype == RegTypeBase) { + } else + g_assert_not_reached (); + } else { + if (ainfo->regtype == RegTypeGeneral) { + if (!((ainfo->reg >= 2) && (ainfo->reg <= 6))) + g_assert_not_reached(); + switch (ainfo->size) { + case 1: + s390_ic (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + break; + case 2: + s390_lh (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + break; + case 8: + s390_lm (code, ainfo->reg, ainfo->reg + 1, + inst->inst_basereg, inst->inst_offset); + break; + default: + s390_l (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + } + } else if (ainfo->regtype == RegTypeBase) { + } else if (ainfo->regtype == RegTypeFP) { + if (ainfo->size == 8) + s390_ld (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + else if (ainfo->size == 4) + s390_le (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + else + g_assert_not_reached (); + } else if (ainfo->regtype == RegTypeStructByVal) { + if (ainfo->reg != STK_BASE) { + switch (ainfo->size) { + case 1: + s390_ic (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + break; + case 2: + s390_lh (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + break; + case 4: + s390_l (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + break; + case 8: + s390_lm (code, ainfo->reg, ainfo->reg+1, inst->inst_basereg, inst->inst_offset); + break; + } + } + } else if (ainfo->regtype == RegTypeStructByAddr) { + if (ainfo->reg != STK_BASE) { + s390_l (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); + } + } else + g_assert_not_reached (); + } + pos++; } + + return code; } /*========================= End of Function ========================*/ @@ -4832,24 +4493,19 @@ 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; \ if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) tracing = 1; - cfg->code_size = 512; + cfg->code_size = 1024; cfg->native_code = code = g_malloc (cfg->code_size); - if (cfg->flags & MONO_CFG_HAS_TAIL) { - s390_stm (code, s390_r2, s390_r14, STK_BASE, S390_PARM_SAVE_OFFSET); - for (pos = 0; pos < 4; pos++) - s390_std (code, pos, 0, STK_BASE, - S390_FLOAT_SAVE_OFFSET+pos*sizeof(double)); - } else { - s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - } + s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + + if (cfg->arch.bkchain_reg != -1) + s390_lr (code, cfg->arch.bkchain_reg, STK_BASE); if (cfg->flags & MONO_CFG_HAS_ALLOCA) { cfg->used_int_regs |= 1 << 11; @@ -4886,29 +4542,30 @@ mono_arch_emit_prolog (MonoCompile *cfg) if (cfg->prof_options & MONO_PROFILE_COVERAGE) max_offset += 6; - while (ins) { - max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN]; - ins = ins->next; - } + MONO_BB_FOR_EACH_INS (bb, ins) + max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; } /* 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->unused = ainfo->vtsize; + inst = cfg->vret_addr; + inst->backend.size = ainfo->vtsize; s390_st (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) s390_lr (code, inst->dreg, ainfo->reg); @@ -4990,20 +4647,8 @@ mono_arch_emit_prolog (MonoCompile *cfg) break; } } else if (ainfo->regtype == RegTypeStructByAddr) { - if (ainfo->reg == STK_BASE) { - s390_lr (code, s390_r13, ainfo->reg); - s390_ahi (code, s390_r13, alloc_size); - s390_l (code, s390_r13, 0, s390_r13, - ainfo->offparm + S390_MINIMAL_STACK_SIZE); - code = emit_memcpy (code, abs(ainfo->vtsize), - inst->inst_basereg, - inst->inst_offset, s390_r13, 0); - } else { - code = emit_memcpy (code, abs(ainfo->vtsize), - inst->inst_basereg, - inst->inst_offset, - ainfo->reg, 0); - } + if (ainfo->reg != STK_BASE) + s390_st (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); } else g_assert_not_reached (); } @@ -5011,30 +4656,35 @@ mono_arch_emit_prolog (MonoCompile *cfg) } if (method->save_lmf) { + /*---------------------------------------------------------------*/ + /* we build the MonoLMF structure on the stack - see mini-s390.h */ + /*---------------------------------------------------------------*/ + lmfOffset = alloc_size - sizeof(MonoLMF); + + s390_lr (code, s390_r13, cfg->frame_reg); + if (s390_is_uimm16(lmfOffset)) + s390_ahi (code, s390_r13, lmfOffset); + else { + s390_basr (code, s390_r14, 0); + s390_j (code, 4); + s390_word (code, lmfOffset); + s390_a (code, s390_r13, 0, s390_r14, 4); + } + /*---------------------------------------------------------------*/ /* Preserve the parameter registers while we fix up the lmf */ /*---------------------------------------------------------------*/ - s390_lr (code, s390_r7, s390_r2); - s390_lr (code, s390_r8, s390_r3); - s390_lr (code, s390_r9, s390_r4); - s390_lr (code, s390_r10, s390_r5); + s390_stm (code, s390_r2, s390_r6, s390_r13, + G_STRUCT_OFFSET(MonoLMF, pregs[0])); - mono_add_patch_info (cfg, code - cfg->native_code, - MONO_PATCH_INFO_INTERNAL_METHOD, - (gpointer)"mono_get_lmf_addr"); /*---------------------------------------------------------------*/ /* On return from this call r2 have the address of the &lmf */ /*---------------------------------------------------------------*/ + mono_add_patch_info (cfg, code - cfg->native_code, + MONO_PATCH_INFO_INTERNAL_METHOD, + (gpointer)"mono_get_lmf_addr"); s390_brasl (code, s390_r14, 0); - /*---------------------------------------------------------------*/ - /* we build the MonoLMF structure on the stack - see mini-s390.h */ - /*---------------------------------------------------------------*/ - lmfOffset = alloc_size - sizeof(MonoLMF); - - s390_lr (code, s390_r13, cfg->frame_reg); - s390_ahi (code, s390_r13, lmfOffset); - /*---------------------------------------------------------------*/ /* Set lmf.lmf_addr = jit_tls->lmf */ /*---------------------------------------------------------------*/ @@ -5070,8 +4720,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) /*---------------------------------------------------------------*/ /* save the current IP */ /*---------------------------------------------------------------*/ - s390_lr (code, s390_r1, cfg->frame_reg); - s390_st (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); + s390_st (code, STK_BASE, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, ebp)); s390_basr (code, s390_r1, 0); s390_la (code, s390_r1, 0, s390_r1, 0); s390_st (code, s390_r1, 0, s390_r13, G_STRUCT_OFFSET(MonoLMF, eip)); @@ -5089,17 +4738,16 @@ mono_arch_emit_prolog (MonoCompile *cfg) /*---------------------------------------------------------------*/ /* Restore the parameter registers now that we've set up the lmf */ /*---------------------------------------------------------------*/ - s390_lr (code, s390_r2, s390_r7); - s390_lr (code, s390_r3, s390_r8); - s390_lr (code, s390_r4, s390_r9); - s390_lr (code, s390_r5, s390_r10); + s390_lm (code, s390_r2, s390_r6, s390_r13, + G_STRUCT_OFFSET(MonoLMF, pregs[0])); } if (tracing) - code = mono_arch_instrument_prolog (cfg, enter_method, code, TRUE); + code = mono_arch_instrument_prolog(cfg, enter_method, code, TRUE); cfg->code_len = code - cfg->native_code; - g_free (cinfo); + + g_assert (cfg->code_len < cfg->code_size); return code; } @@ -5117,7 +4765,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) void mono_arch_emit_epilog (MonoCompile *cfg) { - MonoJumpInfo *patch_info; MonoMethod *method = cfg->method; int tracing = 0; guint8 *code; @@ -5149,9 +4796,9 @@ mono_arch_emit_epilog (MonoCompile *cfg) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); if (cfg->flags & MONO_CFG_HAS_ALLOCA) - s390_l (code, STK_BASE, 0, STK_BASE, 0); + s390_l (code, STK_BASE, 0, STK_BASE, 0); else - code = backUpStackPtr(cfg, code); + code = backUpStackPtr(cfg, code, STK_BASE); s390_lm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); s390_br (code, s390_r14); @@ -5182,8 +4829,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) iExc; guint32 code_size; MonoClass *exc_classes [MAX_EXC]; - guint8 *exc_throw_start [MAX_EXC], - *exc_throw_end [MAX_EXC]; + guint8 *exc_throw_start [MAX_EXC]; for (patch_info = cfg->patch_info; patch_info; @@ -5215,7 +4861,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) /*-----------------------------------------------------*/ /* Patch the branch in epilog to come here */ /*-----------------------------------------------------*/ - s390_patch (ip + 2, S390_RELATIVE(code,ip)); + s390_patch (ip + 2, (guint32) (S390_RELATIVE(code,ip))); exc_class = mono_class_from_name (mono_defaults.corlib, "System", @@ -5228,7 +4874,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg) break; if (iExc < nThrows) { - s390_jcl (code, S390_CC_UN, exc_throw_start [iExc]); + s390_jcl (code, S390_CC_UN, (guint32) exc_throw_start [iExc]); patch_info->type = MONO_PATCH_INFO_NONE; } else { @@ -5246,7 +4892,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, (gsize)S390_RELATIVE((patch_info->ip.i + cfg->native_code + 8), code)); s390_l (code, s390_r2, 0, s390_r13, 4); /*---------------------------------------------*/ @@ -5284,13 +4930,6 @@ mono_arch_emit_exceptions (MonoCompile *cfg) void mono_arch_setup_jit_tls_data (MonoJitTlsData *tls) { -#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK - pthread_t self = pthread_self(); - pthread_attr_t attr; - void *stAddr = NULL; - size_t stSize = 0; - struct sigaltstack sa; -#endif if (!tls_offset_inited) { tls_offset_inited = TRUE; @@ -5315,33 +4954,11 @@ mono_arch_setup_jit_tls_data (MonoJitTlsData *tls) #endif } -#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK - - /*----------------------------------------------------------*/ - /* Determine stack boundaries */ - /*----------------------------------------------------------*/ - if (!mono_running_on_valgrind ()) { -#ifdef HAVE_PTHREAD_GETATTR_NP - pthread_getattr_np( self, &attr ); -#elif HAVE_PTHREAD_ATTR_GET_NP - pthread_attr_get_np( self, &attr ); -#endif - pthread_attr_getstack( &attr, &stAddr, &stSize ); + if (!lmf_addr_key_inited) { + lmf_addr_key_inited = TRUE; + pthread_key_create (&lmf_addr_key, NULL); } - - - /*----------------------------------------------------------*/ - /* Setup an alternate signal stack */ - /*----------------------------------------------------------*/ - tls->stack_size = stSize; - tls->signal_stack = g_malloc (SIGNAL_STACK_SIZE); - tls->signal_stack_size = SIGNAL_STACK_SIZE; - - sa.ss_sp = tls->signal_stack; - sa.ss_size = SIGNAL_STACK_SIZE; - sa.ss_flags = SS_ONSTACK; - sigaltstack (&sa, NULL); -#endif + pthread_setspecific (lmf_addr_key, &tls->lmf); } @@ -5358,55 +4975,48 @@ mono_arch_setup_jit_tls_data (MonoJitTlsData *tls) void mono_arch_free_jit_tls_data (MonoJitTlsData *tls) { -#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK - struct sigaltstack sa; +} - sa.ss_sp = tls->signal_stack; - sa.ss_size = SIGNAL_STACK_SIZE; - sa.ss_flags = SS_DISABLE; - sigaltstack (&sa, NULL); +/*========================= End of Function ========================*/ - if (tls->signal_stack) - g_free (tls->signal_stack); -#endif +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_emit_inst_for_method */ +/* */ +/*------------------------------------------------------------------*/ +MonoInst* +mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) +{ + return NULL; } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_emit_this_vret_args */ +/* Name - mono_arch_decompose_opts */ /* */ -/* Function - */ -/* */ /*------------------------------------------------------------------*/ void -mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg) +mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) { - int this_dreg = s390_r2; - - if (vt_reg != -1) - this_dreg = s390_r3; - - /* add the this argument */ - if (this_reg != -1) { - MonoInst *this; - MONO_INST_NEW (cfg, this, OP_SETREG); - this->type = this_type; - this->sreg1 = this_reg; - this->dreg = this_dreg; - mono_bblock_add_inst (cfg->cbb, this); - } - - if (vt_reg != -1) { - MonoInst *vtarg; - MONO_INST_NEW (cfg, vtarg, OP_SETREG); - vtarg->type = STACK_MP; - vtarg->sreg1 = vt_reg; - vtarg->dreg = s390_r2; - mono_bblock_add_inst (cfg->cbb, vtarg); + 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; + default: + break; } } @@ -5414,63 +5024,83 @@ mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_re /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_get_inst_for_method */ +/* Name - mono_arch_decompose_long_opts */ /* */ -/* Function - Check for opcodes we can handle directly in */ -/* hardware. */ -/* */ /*------------------------------------------------------------------*/ -MonoInst* -mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, - MonoMethodSignature *fsig, MonoInst **args) +void +mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins) { - MonoInst *ins = NULL; - - if (cmethod->klass == mono_defaults.math_class) { - if (strcmp (cmethod->name, "Sqrt") == 0) { - MONO_INST_NEW (cfg, ins, OP_SQRT); - ins->inst_i0 = args [0]; - } - } 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 && - fsig->params [0]->type == MONO_TYPE_I4) { - MonoInst *ins_iconst; - - MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4); - 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 && - fsig->params [0]->type == MONO_TYPE_I4) { - MonoInst *ins_iconst; - - MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_NEW_I4); - 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, "Exchange") == 0 && - fsig->params [0]->type == MONO_TYPE_I4) { - MONO_INST_NEW (cfg, ins, OP_ATOMIC_EXCHANGE_I4); - - ins->inst_i0 = args [0]; - ins->inst_i1 = args [1]; - } else if (strcmp (cmethod->name, "Add") == 0 && - fsig->params [0]->type == MONO_TYPE_I4) { - MONO_INST_NEW (cfg, ins, OP_ATOMIC_ADD_I4); - - ins->inst_i0 = args [0]; - ins->inst_i1 = args [1]; + // The generic code seems to work for OP_LSUB fine on s390, why is a different + // implementation needed ? gcc also seems to use the different implementation. + // FIXME: What about the other OP_L opcodes below ? + + switch (ins->opcode) { + case OP_LADD_OVF: + case OP_LADD_OVF_UN: + case OP_LSUB_OVF: + case OP_LSUB_OVF_UN: { + int opcode = 0; + + switch (ins->opcode) { + case OP_LADD: + opcode = OP_S390_LADD; + break; + case OP_LADD_OVF: + opcode = OP_S390_LADD_OVF; + break; + case OP_LADD_OVF_UN: + opcode = OP_S390_LADD_OVF_UN; + break; + case OP_LSUB: + opcode = OP_S390_LSUB; + break; + case OP_LSUB_OVF: + opcode = OP_S390_LSUB_OVF; + break; + case OP_LSUB_OVF_UN: + opcode = OP_S390_LSUB_OVF_UN; + break; + default: + g_assert_not_reached (); } + + /* These hard regs make ssa crazy */ + cfg->disable_ssa = TRUE; + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, s390_r0, ins->sreg1 + 1); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, s390_r1, ins->sreg1 + 2); + MONO_EMIT_NEW_BIALU (cfg, opcode, ins->dreg, ins->sreg2 + 1, ins->sreg2 + 2); + NULLIFY_INS (ins); + break; + } + case OP_LADD_IMM: { + int dreg = mono_alloc_dreg (cfg, STACK_I8); + MONO_EMIT_NEW_I8CONST (cfg, dreg, ins->inst_l); + MONO_EMIT_NEW_BIALU (cfg, OP_LADD, ins->dreg, ins->sreg1, dreg); + NULLIFY_INS (ins); + break; + } + case OP_LSUB_IMM: { + int dreg = mono_alloc_dreg (cfg, STACK_I8); + MONO_EMIT_NEW_I8CONST (cfg, dreg, ins->inst_l); + MONO_EMIT_NEW_BIALU (cfg, OP_LSUB, ins->dreg, ins->sreg1, dreg); + NULLIFY_INS (ins); + break; + } + case OP_LNEG: { + MONO_EMIT_NEW_BIALU (cfg, OP_S390_LNEG, ins->dreg, ins->sreg1 + 1, ins->sreg1 + 2); + NULLIFY_INS (ins); + break; + } + case OP_ISUB_OVF: + ins->opcode = OP_S390_ISUB_OVF; + break; + case OP_ISUB_OVF_UN: + ins->opcode = OP_S390_ISUB_OVF_UN; + break; + default: + break; } - return ins; } /*========================= End of Function ========================*/ @@ -5493,34 +5123,41 @@ mono_arch_print_tree (MonoInst *tree, int arity) switch (tree->opcode) { case OP_S390_LOADARG: + case OP_S390_ARGREG: case OP_S390_ARGPTR: - printf ("[0x%x(%s)]", tree->inst_offset, + printf ("[0x%lx(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg)); done = 1; break; case OP_S390_STKARG: - printf ("[0x%x(previous_frame)]", + printf ("[0x%lx(previous_frame)]", tree->inst_offset); done = 1; break; case OP_S390_MOVE: - printf ("[0x%x(%d,%s),0x%x(%s)]", - tree->inst_offset, tree->unused, - tree->dreg, tree->inst_imm, - tree->sreg1); + printf ("[0x%lx(%d,%s),0x%lx(%s)]", + tree->inst_offset, tree->backend.size, + mono_arch_regname(tree->dreg), tree->inst_imm, + mono_arch_regname(tree->sreg1)); done = 1; break; case OP_S390_SETF4RET: - printf ("[f%d,f%d]", - mono_arch_regname (tree->dreg), - mono_arch_regname (tree->sreg1)); + printf ("[%s,%s]", + mono_arch_fregname (tree->dreg), + mono_arch_fregname (tree->sreg1)); done = 1; break; case OP_TLS_GET: - printf ("[0x%x(0x%x,%s)]", tree->inst_offset, + printf ("[0x%lx(0x%lx,%s)]", tree->inst_offset, tree->inst_imm, mono_arch_regname (tree->sreg1)); done = 1; + break; + case OP_S390_BKCHAIN: + printf ("[previous_frame(%s)]", + mono_arch_regname (tree->sreg1)); + done = 1; + break; default: done = 0; } @@ -5578,7 +5215,7 @@ mono_arch_get_domain_intrinsic (MonoCompile* cfg) /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_get_thread_intrinsic */ +/* Name - mono_arch_flush_register_windows */ /* */ /* Function - */ /* */ @@ -5586,24 +5223,16 @@ mono_arch_get_domain_intrinsic (MonoCompile* cfg) /* */ /*------------------------------------------------------------------*/ -MonoInst * -mono_arch_get_thread_intrinsic (MonoCompile* cfg) +void +mono_arch_flush_register_windows (void) { - MonoInst *ins; - - if (thread_tls_offset == -1) - return NULL; - - MONO_INST_NEW (cfg, ins, OP_TLS_GET); - ins->inst_offset = thread_tls_offset; - return (ins); } /*========================= End of Function ========================*/ /*------------------------------------------------------------------*/ /* */ -/* Name - mono_arch_flush_register_windows */ +/* Name - mono_arch_get_lmf_addr */ /* */ /* Function - */ /* */ @@ -5611,9 +5240,49 @@ mono_arch_get_thread_intrinsic (MonoCompile* cfg) /* */ /*------------------------------------------------------------------*/ -void -mono_arch_flush_register_windows (void) +gpointer +mono_arch_get_lmf_addr (void) +{ + return pthread_getspecific (lmf_addr_key); +} + + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_get_patch_offset */ +/* */ +/* Function - Dummy entry point until s390x supports aot. */ +/* */ +/* Returns - Offset for patch. */ +/* */ +/*------------------------------------------------------------------*/ + +guint32 +mono_arch_get_patch_offset (guint8 *code) +{ + return 0; +} + +/*========================= End of Function ========================*/ + +/*------------------------------------------------------------------*/ +/* */ +/* Name - mono_arch_context_get_int_reg. */ +/* */ +/* Function - Dummy entry point until s390x supports aot. */ +/* */ +/* Returns - Pointer to intreg. */ +/* */ +/*------------------------------------------------------------------*/ + +gpointer +mono_arch_context_get_int_reg (MonoContext *ctx, int reg) { + /* FIXME: implement */ + g_assert_not_reached (); + return NULL; } /*========================= End of Function ========================*/