2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 #include <sys/sysctl.h>
26 alloc_ireg (MonoCompile *cfg)
28 return cfg->next_vreg ++;
32 alloc_lreg (MonoCompile *cfg)
34 #if SIZEOF_VOID_P == 8
35 return cfg->next_vreg ++;
37 /* Use a pair of consecutive vregs */
38 guint32 res = cfg->next_vreg;
47 alloc_freg (MonoCompile *cfg)
49 #ifdef MONO_ARCH_SOFT_FLOAT
50 /* Allocate an lvreg so float ops can be decomposed into long ops */
51 return alloc_lreg (cfg);
53 /* Allocate these from the same pool as the int regs */
54 return cfg->next_vreg ++;
59 alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
66 return alloc_ireg (cfg);
68 return alloc_freg (cfg);
70 return alloc_lreg (cfg);
72 return alloc_ireg (cfg);
74 g_assert_not_reached ();
78 #ifdef MONO_ARCH_SOFT_FLOAT
79 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
81 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
84 #define NEW_VARLOADA(cfg,dest,var,vartype) do { \
85 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
86 (dest)->inst_p0 = (var); \
87 (var)->flags |= MONO_INST_INDIRECT; \
88 (dest)->type = STACK_MP; \
89 (dest)->klass = (var)->klass; \
90 (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
91 if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
94 #define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
96 #define FORCE_INDIR_CALL 1
107 /* This mutex protects architecture specific caches */
108 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
109 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
110 static CRITICAL_SECTION mini_arch_mutex;
112 int mono_exc_esp_offset = 0;
113 static int tls_mode = TLS_MODE_DETECT;
114 static int lmf_pthread_key = -1;
115 static int monothread_key = -1;
116 static int monodomain_key = -1;
119 offsets_from_pthread_key (guint32 key, int *offset2)
123 *offset2 = idx2 * sizeof (gpointer);
124 return 284 + idx1 * sizeof (gpointer);
127 #define emit_linuxthreads_tls(code,dreg,key) do {\
129 off1 = offsets_from_pthread_key ((key), &off2); \
130 ppc_lwz ((code), (dreg), off1, ppc_r2); \
131 ppc_lwz ((code), (dreg), off2, (dreg)); \
134 #define emit_darwing5_tls(code,dreg,key) do {\
135 int off1 = 0x48 + key * sizeof (gpointer); \
136 ppc_mfspr ((code), (dreg), 104); \
137 ppc_lwz ((code), (dreg), off1, (dreg)); \
140 /* FIXME: ensure the sc call preserves all but r3 */
141 #define emit_darwing4_tls(code,dreg,key) do {\
142 int off1 = 0x48 + key * sizeof (gpointer); \
143 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
144 ppc_li ((code), ppc_r0, 0x7FF2); \
146 ppc_lwz ((code), (dreg), off1, ppc_r3); \
147 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
150 #define emit_tls_access(code,dreg,key) do { \
151 switch (tls_mode) { \
152 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
153 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
154 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
155 default: g_assert_not_reached (); \
160 mono_arch_regname (int reg) {
161 static const char rnames[][4] = {
162 "r0", "sp", "r2", "r3", "r4",
163 "r5", "r6", "r7", "r8", "r9",
164 "r10", "r11", "r12", "r13", "r14",
165 "r15", "r16", "r17", "r18", "r19",
166 "r20", "r21", "r22", "r23", "r24",
167 "r25", "r26", "r27", "r28", "r29",
170 if (reg >= 0 && reg < 32)
176 mono_arch_fregname (int reg) {
177 static const char rnames[][4] = {
178 "f0", "f1", "f2", "f3", "f4",
179 "f5", "f6", "f7", "f8", "f9",
180 "f10", "f11", "f12", "f13", "f14",
181 "f15", "f16", "f17", "f18", "f19",
182 "f20", "f21", "f22", "f23", "f24",
183 "f25", "f26", "f27", "f28", "f29",
186 if (reg >= 0 && reg < 32)
191 /* this function overwrites r0, r11, r12 */
193 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
195 /* unrolled, use the counter in big */
196 if (size > sizeof (gpointer) * 5) {
197 int shifted = size >> 2;
198 guint8 *copy_loop_start, *copy_loop_jump;
200 ppc_load (code, ppc_r0, shifted);
201 ppc_mtctr (code, ppc_r0);
202 g_assert (sreg == ppc_r11);
203 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
204 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
205 copy_loop_start = code;
206 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
207 ppc_stwu (code, ppc_r0, 4, ppc_r12);
208 copy_loop_jump = code;
209 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
210 ppc_patch (copy_loop_jump, copy_loop_start);
212 doffset = soffset = 0;
216 ppc_lwz (code, ppc_r0, soffset, sreg);
217 ppc_stw (code, ppc_r0, doffset, dreg);
223 ppc_lhz (code, ppc_r0, soffset, sreg);
224 ppc_sth (code, ppc_r0, doffset, dreg);
230 ppc_lbz (code, ppc_r0, soffset, sreg);
231 ppc_stb (code, ppc_r0, doffset, dreg);
240 * mono_arch_get_argument_info:
241 * @csig: a method signature
242 * @param_count: the number of parameters to consider
243 * @arg_info: an array to store the result infos
245 * Gathers information on parameters such as size, alignment and
246 * padding. arg_info should be large enought to hold param_count + 1 entries.
248 * Returns the size of the activation frame.
251 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
253 int k, frame_size = 0;
254 int size, align, pad;
257 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
258 frame_size += sizeof (gpointer);
262 arg_info [0].offset = offset;
265 frame_size += sizeof (gpointer);
269 arg_info [0].size = frame_size;
271 for (k = 0; k < param_count; k++) {
274 size = mono_type_native_stack_size (csig->params [k], &align);
276 size = mini_type_stack_size (NULL, csig->params [k], &align);
278 /* ignore alignment for now */
281 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
282 arg_info [k].pad = pad;
284 arg_info [k + 1].pad = 0;
285 arg_info [k + 1].size = size;
287 arg_info [k + 1].offset = offset;
291 align = MONO_ARCH_FRAME_ALIGNMENT;
292 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
293 arg_info [k].pad = pad;
299 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
303 guint32* code = (guint32*)code_ptr;
307 /* This is the 'blrl' instruction */
310 /* Sanity check: instruction must be 'blrl' */
311 if (*code != 0x4e800021)
314 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
315 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
319 /* OK, we're now at the 'blrl' instruction. Now walk backwards
320 till we get to a 'mtlr rA' */
322 if((*code & 0x7c0803a6) == 0x7c0803a6) {
324 /* Here we are: we reached the 'mtlr rA'.
325 Extract the register from the instruction */
326 reg = (*code & 0x03e00000) >> 21;
328 /* ok, this is a lwz reg, offset (vtreg)
329 * it is emitted with:
330 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
332 soff = (*code & 0xffff);
334 reg = (*code >> 16) & 0x1f;
335 g_assert (reg != ppc_r1);
336 /*g_print ("patching reg is %d\n", reg);*/
338 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
339 /* saved in the MonoLMF structure */
340 o = (gpointer)lmf->iregs [reg - 13];
347 *displacement = offset;
352 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
356 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
359 return (gpointer*)((char*)vt + displacement);
362 #define MAX_ARCH_DELEGATE_PARAMS 7
365 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
367 guint8 *code, *start;
369 /* FIXME: Support more cases */
370 if (MONO_TYPE_ISSTRUCT (sig->ret))
374 static guint8* cached = NULL;
375 mono_mini_arch_lock ();
377 mono_mini_arch_unlock ();
381 start = code = mono_global_codeman_reserve (16);
383 /* Replace the this argument with the target */
384 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
385 ppc_mtctr (code, ppc_r0);
386 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
387 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
389 g_assert ((code - start) <= 16);
391 mono_arch_flush_icache (start, 16);
393 mono_mini_arch_unlock ();
396 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
399 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
401 for (i = 0; i < sig->param_count; ++i)
402 if (!mono_is_regsize_var (sig->params [i]))
405 mono_mini_arch_lock ();
406 code = cache [sig->param_count];
408 mono_mini_arch_unlock ();
412 size = 12 + sig->param_count * 4;
413 start = code = mono_global_codeman_reserve (size);
415 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 ppc_mtctr (code, ppc_r0);
417 /* slide down the arguments */
418 for (i = 0; i < sig->param_count; ++i) {
419 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
421 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
423 g_assert ((code - start) <= size);
425 mono_arch_flush_icache (start, size);
426 cache [sig->param_count] = start;
427 mono_mini_arch_unlock ();
434 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
436 /* FIXME: handle returning a struct */
437 if (MONO_TYPE_ISSTRUCT (sig->ret))
438 return (gpointer)regs [ppc_r4];
439 return (gpointer)regs [ppc_r3];
443 * Initialize the cpu to execute managed code.
446 mono_arch_cpu_init (void)
451 * Initialize architecture specific code.
454 mono_arch_init (void)
456 InitializeCriticalSection (&mini_arch_mutex);
460 * Cleanup architecture specific code.
463 mono_arch_cleanup (void)
465 DeleteCriticalSection (&mini_arch_mutex);
469 * This function returns the optimizations supported on this cpu.
472 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
476 /* no ppc-specific optimizations yet */
482 is_regsize_var (MonoType *t) {
485 t = mono_type_get_underlying_type (t);
492 case MONO_TYPE_FNPTR:
494 case MONO_TYPE_OBJECT:
495 case MONO_TYPE_STRING:
496 case MONO_TYPE_CLASS:
497 case MONO_TYPE_SZARRAY:
498 case MONO_TYPE_ARRAY:
500 case MONO_TYPE_GENERICINST:
501 if (!mono_type_generic_inst_is_valuetype (t))
504 case MONO_TYPE_VALUETYPE:
511 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
516 for (i = 0; i < cfg->num_varinfo; i++) {
517 MonoInst *ins = cfg->varinfo [i];
518 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
521 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
524 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
527 /* we can only allocate 32 bit values */
528 if (is_regsize_var (ins->inst_vtype)) {
529 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
530 g_assert (i == vmv->idx);
531 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
539 mono_arch_get_global_int_regs (MonoCompile *cfg)
543 if (cfg->frame_reg != ppc_sp)
545 /* ppc_r13 is used by the system on PPC EABI */
546 for (i = 14; i < top; ++i)
547 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
553 * mono_arch_regalloc_cost:
555 * Return the cost, in number of memory references, of the action of
556 * allocating the variable VMV into a register during global register
560 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
572 mono_arch_flush_icache (guint8 *code, gint size)
574 guint8 *p, *endp, *start;
575 static int cachelinesize = 0;
576 static int cachelineinc = 16;
578 if (!cachelinesize) {
582 mib [1] = HW_CACHELINE;
583 len = sizeof (cachelinesize);
584 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
588 cachelineinc = cachelinesize;
589 /*g_print ("setting cl size to %d\n", cachelinesize);*/
591 #elif defined(__linux__)
592 /* sadly this will work only with 2.6 kernels... */
593 FILE* f = fopen ("/proc/self/auxv", "rb");
596 while (fread (&vec, sizeof (vec), 1, f) == 1) {
597 if (vec.type == 19) {
598 cachelinesize = vec.value;
607 #warning Need a way to get cache line size
613 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
614 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
616 for (p = start; p < endp; p += cachelineinc) {
617 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
620 for (p = start; p < endp; p += cachelineinc) {
621 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
626 for (p = start; p < endp; p += cachelineinc) {
627 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
634 mono_arch_flush_register_windows (void)
639 #define ALWAYS_ON_STACK(s) s
640 #define FP_ALSO_IN_REG(s) s
642 #define ALWAYS_ON_STACK(s)
643 #define FP_ALSO_IN_REG(s)
644 #define ALIGN_DOUBLES
657 guint32 vtsize; /* in param area */
659 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
660 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
675 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
678 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
679 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
680 ainfo->reg = ppc_sp; /* in the caller */
681 ainfo->regtype = RegTypeBase;
684 ALWAYS_ON_STACK (*stack_size += 4);
688 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
690 //*stack_size += (*stack_size % 8);
692 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
693 ainfo->reg = ppc_sp; /* in the caller */
694 ainfo->regtype = RegTypeBase;
701 ALWAYS_ON_STACK (*stack_size += 8);
711 has_only_a_r48_field (MonoClass *klass)
715 gboolean have_field = FALSE;
717 while ((f = mono_class_get_fields (klass, &iter))) {
718 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
721 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
732 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
735 int n = sig->hasthis + sig->param_count;
737 guint32 stack_size = 0;
738 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
740 fr = PPC_FIRST_FPARG_REG;
741 gr = PPC_FIRST_ARG_REG;
743 /* FIXME: handle returning a struct */
744 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
745 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
746 cinfo->struct_ret = PPC_FIRST_ARG_REG;
751 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
754 DEBUG(printf("params: %d\n", sig->param_count));
755 for (i = 0; i < sig->param_count; ++i) {
756 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
757 /* Prevent implicit arguments and sig_cookie from
758 being passed in registers */
759 gr = PPC_LAST_ARG_REG + 1;
760 /* FIXME: don't we have to set fr, too? */
761 /* Emit the signature cookie just before the implicit arguments */
762 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
764 DEBUG(printf("param %d: ", i));
765 if (sig->params [i]->byref) {
766 DEBUG(printf("byref\n"));
767 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
771 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
772 switch (simpletype) {
773 case MONO_TYPE_BOOLEAN:
776 cinfo->args [n].size = 1;
777 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
783 cinfo->args [n].size = 2;
784 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
789 cinfo->args [n].size = 4;
790 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
796 case MONO_TYPE_FNPTR:
797 case MONO_TYPE_CLASS:
798 case MONO_TYPE_OBJECT:
799 case MONO_TYPE_STRING:
800 case MONO_TYPE_SZARRAY:
801 case MONO_TYPE_ARRAY:
802 cinfo->args [n].size = sizeof (gpointer);
803 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
806 case MONO_TYPE_GENERICINST:
807 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
808 cinfo->args [n].size = sizeof (gpointer);
809 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
814 case MONO_TYPE_VALUETYPE: {
817 klass = mono_class_from_mono_type (sig->params [i]);
819 size = mono_class_native_size (klass, NULL);
821 size = mono_class_value_size (klass, NULL);
823 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
824 cinfo->args [n].size = size;
826 /* It was 7, now it is 8 in LinuxPPC */
827 if (fr <= PPC_LAST_FPARG_REG) {
828 cinfo->args [n].regtype = RegTypeFP;
829 cinfo->args [n].reg = fr;
831 FP_ALSO_IN_REG (gr ++);
833 FP_ALSO_IN_REG (gr ++);
834 ALWAYS_ON_STACK (stack_size += size);
836 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
837 cinfo->args [n].regtype = RegTypeBase;
838 cinfo->args [n].reg = ppc_sp; /* in the caller*/
845 DEBUG(printf ("load %d bytes struct\n",
846 mono_class_native_size (sig->params [i]->data.klass, NULL)));
847 #if PPC_PASS_STRUCTS_BY_VALUE
849 int align_size = size;
851 int rest = PPC_LAST_ARG_REG - gr + 1;
853 align_size += (sizeof (gpointer) - 1);
854 align_size &= ~(sizeof (gpointer) - 1);
855 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
856 n_in_regs = rest >= nwords? nwords: rest;
857 cinfo->args [n].regtype = RegTypeStructByVal;
858 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
859 cinfo->args [n].size = 0;
860 cinfo->args [n].vtsize = nwords;
862 cinfo->args [n].size = n_in_regs;
863 cinfo->args [n].vtsize = nwords - n_in_regs;
864 cinfo->args [n].reg = gr;
867 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
868 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
869 stack_size += nwords * sizeof (gpointer);
872 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
873 cinfo->args [n].regtype = RegTypeStructByAddr;
874 cinfo->args [n].vtsize = size;
879 case MONO_TYPE_TYPEDBYREF: {
880 int size = sizeof (MonoTypedRef);
881 /* keep in sync or merge with the valuetype case */
882 #if PPC_PASS_STRUCTS_BY_VALUE
884 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
885 cinfo->args [n].regtype = RegTypeStructByVal;
886 if (gr <= PPC_LAST_ARG_REG) {
887 int rest = PPC_LAST_ARG_REG - gr + 1;
888 int n_in_regs = rest >= nwords? nwords: rest;
889 cinfo->args [n].size = n_in_regs;
890 cinfo->args [n].vtsize = nwords - n_in_regs;
891 cinfo->args [n].reg = gr;
894 cinfo->args [n].size = 0;
895 cinfo->args [n].vtsize = nwords;
897 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
898 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
899 stack_size += nwords * sizeof (gpointer);
902 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
903 cinfo->args [n].regtype = RegTypeStructByAddr;
904 cinfo->args [n].vtsize = size;
911 cinfo->args [n].size = 8;
912 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
916 cinfo->args [n].size = 4;
918 /* It was 7, now it is 8 in LinuxPPC */
919 if (fr <= PPC_LAST_FPARG_REG) {
920 cinfo->args [n].regtype = RegTypeFP;
921 cinfo->args [n].reg = fr;
923 FP_ALSO_IN_REG (gr ++);
924 ALWAYS_ON_STACK (stack_size += 4);
926 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
927 cinfo->args [n].regtype = RegTypeBase;
928 cinfo->args [n].reg = ppc_sp; /* in the caller*/
934 cinfo->args [n].size = 8;
935 /* It was 7, now it is 8 in LinuxPPC */
936 if (fr <= PPC_LAST_FPARG_REG) {
937 cinfo->args [n].regtype = RegTypeFP;
938 cinfo->args [n].reg = fr;
940 FP_ALSO_IN_REG (gr += 2);
941 ALWAYS_ON_STACK (stack_size += 8);
943 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
944 cinfo->args [n].regtype = RegTypeBase;
945 cinfo->args [n].reg = ppc_sp; /* in the caller*/
951 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
955 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
956 /* Prevent implicit arguments and sig_cookie from
957 being passed in registers */
958 gr = PPC_LAST_ARG_REG + 1;
959 /* Emit the signature cookie just before the implicit arguments */
960 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
964 simpletype = mono_type_get_underlying_type (sig->ret)->type;
965 switch (simpletype) {
966 case MONO_TYPE_BOOLEAN:
977 case MONO_TYPE_FNPTR:
978 case MONO_TYPE_CLASS:
979 case MONO_TYPE_OBJECT:
980 case MONO_TYPE_SZARRAY:
981 case MONO_TYPE_ARRAY:
982 case MONO_TYPE_STRING:
983 cinfo->ret.reg = ppc_r3;
987 cinfo->ret.reg = ppc_r3;
991 cinfo->ret.reg = ppc_f1;
992 cinfo->ret.regtype = RegTypeFP;
994 case MONO_TYPE_GENERICINST:
995 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
996 cinfo->ret.reg = ppc_r3;
1000 case MONO_TYPE_VALUETYPE:
1002 case MONO_TYPE_TYPEDBYREF:
1003 case MONO_TYPE_VOID:
1006 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1010 /* align stack size to 16 */
1011 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1012 stack_size = (stack_size + 15) & ~15;
1014 cinfo->stack_usage = stack_size;
1020 * Set var information according to the calling convention. ppc version.
1021 * The locals var stuff should most likely be split in another method.
1024 mono_arch_allocate_vars (MonoCompile *m)
1026 MonoMethodSignature *sig;
1027 MonoMethodHeader *header;
1029 int i, offset, size, align, curinst;
1030 int frame_reg = ppc_sp;
1032 m->flags |= MONO_CFG_HAS_SPILLUP;
1034 /* allow room for the vararg method args: void* and long/double */
1035 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1036 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1037 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1038 * call convs needs to be handled this way.
1040 if (m->flags & MONO_CFG_HAS_VARARGS)
1041 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1042 /* gtk-sharp and other broken code will dllimport vararg functions even with
1043 * non-varargs signatures. Since there is little hope people will get this right
1044 * we assume they won't.
1046 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1047 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1049 header = mono_method_get_header (m->method);
1052 * We use the frame register also for any method that has
1053 * exception clauses. This way, when the handlers are called,
1054 * the code will reference local variables using the frame reg instead of
1055 * the stack pointer: if we had to restore the stack pointer, we'd
1056 * corrupt the method frames that are already on the stack (since
1057 * filters get called before stack unwinding happens) when the filter
1058 * code would call any method (this also applies to finally etc.).
1060 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1061 frame_reg = ppc_r31;
1062 m->frame_reg = frame_reg;
1063 if (frame_reg != ppc_sp) {
1064 m->used_int_regs |= 1 << frame_reg;
1067 sig = mono_method_signature (m->method);
1071 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1072 m->ret->opcode = OP_REGVAR;
1073 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1075 /* FIXME: handle long values? */
1076 switch (mono_type_get_underlying_type (sig->ret)->type) {
1077 case MONO_TYPE_VOID:
1081 m->ret->opcode = OP_REGVAR;
1082 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1085 m->ret->opcode = OP_REGVAR;
1086 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1090 /* local vars are at a positive offset from the stack pointer */
1092 * also note that if the function uses alloca, we use ppc_r31
1093 * to point at the local variables.
1095 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1096 /* align the offset to 16 bytes: not sure this is needed here */
1098 //offset &= ~(16 - 1);
1100 /* add parameter area size for called functions */
1101 offset += m->param_area;
1103 offset &= ~(16 - 1);
1105 /* allow room to save the return value */
1106 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1109 /* the MonoLMF structure is stored just below the stack pointer */
1112 /* this stuff should not be needed on ppc and the new jit,
1113 * because a call on ppc to the handlers doesn't change the
1114 * stack pointer and the jist doesn't manipulate the stack pointer
1115 * for operations involving valuetypes.
1117 /* reserve space to store the esp */
1118 offset += sizeof (gpointer);
1120 /* this is a global constant */
1121 mono_exc_esp_offset = offset;
1123 if (sig->call_convention == MONO_CALL_VARARG) {
1124 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1127 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1128 offset += sizeof(gpointer) - 1;
1129 offset &= ~(sizeof(gpointer) - 1);
1132 m->vret_addr->opcode = OP_REGOFFSET;
1133 m->vret_addr->inst_basereg = frame_reg;
1134 m->vret_addr->inst_offset = offset;
1136 if (G_UNLIKELY (m->verbose_level > 1)) {
1137 printf ("vret_addr =");
1138 mono_print_ins (m->vret_addr);
1142 inst->inst_offset = offset;
1143 inst->opcode = OP_REGOFFSET;
1144 inst->inst_basereg = frame_reg;
1147 offset += sizeof(gpointer);
1148 if (sig->call_convention == MONO_CALL_VARARG)
1149 m->sig_cookie += sizeof (gpointer);
1152 curinst = m->locals_start;
1153 for (i = curinst; i < m->num_varinfo; ++i) {
1154 inst = m->varinfo [i];
1155 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1158 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1159 * pinvoke wrappers when they call functions returning structure */
1160 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1161 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1163 size = mono_type_size (inst->inst_vtype, &align);
1165 offset += align - 1;
1166 offset &= ~(align - 1);
1167 inst->inst_offset = offset;
1168 inst->opcode = OP_REGOFFSET;
1169 inst->inst_basereg = frame_reg;
1171 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1176 inst = m->args [curinst];
1177 if (inst->opcode != OP_REGVAR) {
1178 inst->opcode = OP_REGOFFSET;
1179 inst->inst_basereg = frame_reg;
1180 offset += sizeof (gpointer) - 1;
1181 offset &= ~(sizeof (gpointer) - 1);
1182 inst->inst_offset = offset;
1183 offset += sizeof (gpointer);
1184 if (sig->call_convention == MONO_CALL_VARARG)
1185 m->sig_cookie += sizeof (gpointer);
1190 for (i = 0; i < sig->param_count; ++i) {
1191 inst = m->args [curinst];
1192 if (inst->opcode != OP_REGVAR) {
1193 inst->opcode = OP_REGOFFSET;
1194 inst->inst_basereg = frame_reg;
1196 size = mono_type_native_stack_size (sig->params [i], &align);
1197 inst->backend.is_pinvoke = 1;
1199 size = mono_type_size (sig->params [i], &align);
1201 offset += align - 1;
1202 offset &= ~(align - 1);
1203 inst->inst_offset = offset;
1205 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1206 m->sig_cookie += size;
1211 /* align the offset to 16 bytes */
1213 offset &= ~(16 - 1);
1216 m->stack_offset = offset;
1218 if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1219 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1221 m->sig_cookie = cinfo->sig_cookie.offset;
1228 mono_arch_create_vars (MonoCompile *cfg)
1230 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1232 if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1233 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1237 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1238 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1242 * take the arguments and generate the arch-specific
1243 * instructions to properly call the function in call.
1244 * This includes pushing, moving arguments to the right register
1246 * Issue: who does the spilling if needed, and when?
1249 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1251 MonoMethodSignature *sig;
1256 sig = call->signature;
1257 n = sig->param_count + sig->hasthis;
1259 cinfo = calculate_sizes (sig, sig->pinvoke);
1260 if (cinfo->struct_ret)
1261 call->used_iregs |= 1 << cinfo->struct_ret;
1263 for (i = 0; i < n; ++i) {
1264 ainfo = cinfo->args + i;
1265 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1267 cfg->disable_aot = TRUE;
1269 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1270 sig_arg->inst_p0 = call->signature;
1272 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1273 arg->inst_imm = cinfo->sig_cookie.offset;
1274 arg->inst_left = sig_arg;
1275 arg->inst_call = call;
1276 /* prepend, so they get reversed */
1277 arg->next = call->out_args;
1278 call->out_args = arg;
1280 if (is_virtual && i == 0) {
1281 /* the argument will be attached to the call instrucion */
1282 in = call->args [i];
1283 call->used_iregs |= 1 << ainfo->reg;
1285 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1286 in = call->args [i];
1287 arg->cil_code = in->cil_code;
1288 arg->inst_left = in;
1289 arg->inst_call = call;
1290 arg->type = in->type;
1291 /* prepend, so they get reversed */
1292 arg->next = call->out_args;
1293 call->out_args = arg;
1294 if (ainfo->regtype == RegTypeGeneral) {
1295 arg->backend.reg3 = ainfo->reg;
1296 call->used_iregs |= 1 << ainfo->reg;
1297 if (arg->type == STACK_I8)
1298 call->used_iregs |= 1 << (ainfo->reg + 1);
1299 } else if (ainfo->regtype == RegTypeStructByAddr) {
1300 if (ainfo->offset) {
1301 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1302 arg->opcode = OP_OUTARG_MEMBASE;
1303 ai->reg = ainfo->reg;
1304 ai->size = sizeof (gpointer);
1305 ai->offset = ainfo->offset;
1306 arg->backend.data = ai;
1308 arg->backend.reg3 = ainfo->reg;
1309 call->used_iregs |= 1 << ainfo->reg;
1311 } else if (ainfo->regtype == RegTypeStructByVal) {
1313 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1314 /* mark the used regs */
1315 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1316 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1318 arg->opcode = OP_OUTARG_VT;
1319 ai->reg = ainfo->reg;
1320 ai->size = ainfo->size;
1321 ai->vtsize = ainfo->vtsize;
1322 ai->offset = ainfo->offset;
1323 arg->backend.data = ai;
1324 } else if (ainfo->regtype == RegTypeBase) {
1325 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1326 arg->opcode = OP_OUTARG_MEMBASE;
1327 ai->reg = ainfo->reg;
1328 ai->size = ainfo->size;
1329 ai->offset = ainfo->offset;
1330 arg->backend.data = ai;
1331 } else if (ainfo->regtype == RegTypeFP) {
1332 arg->opcode = OP_OUTARG_R8;
1333 arg->backend.reg3 = ainfo->reg;
1334 call->used_fregs |= 1 << ainfo->reg;
1335 if (ainfo->size == 4) {
1336 arg->opcode = OP_OUTARG_R8;
1337 /* we reduce the precision */
1339 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1340 conv->inst_left = arg->inst_left;
1341 arg->inst_left = conv;*/
1344 g_assert_not_reached ();
1349 * Reverse the call->out_args list.
1352 MonoInst *prev = NULL, *list = call->out_args, *next;
1359 call->out_args = prev;
1362 call->stack_usage = cinfo->stack_usage;
1363 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1364 cfg->flags |= MONO_CFG_HAS_CALLS;
1366 * should set more info in call, such as the stack space
1367 * used by the args that needs to be added back to esp
1375 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1377 int sig_reg = mono_alloc_ireg (cfg);
1379 MONO_EMIT_NEW_ICONST (cfg, sig_reg, call->signature);
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1381 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1385 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1388 MonoMethodSignature *sig;
1392 sig = call->signature;
1393 n = sig->param_count + sig->hasthis;
1395 cinfo = calculate_sizes (sig, sig->pinvoke);
1397 for (i = 0; i < n; ++i) {
1398 ArgInfo *ainfo = cinfo->args + i;
1401 if (i >= sig->hasthis)
1402 t = sig->params [i - sig->hasthis];
1404 t = &mono_defaults.int_class->byval_arg;
1405 t = mono_type_get_underlying_type (t);
1407 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1408 emit_sig_cookie (cfg, call, cinfo);
1410 in = call->args [i];
1412 if (ainfo->regtype == RegTypeGeneral) {
1413 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1414 MONO_INST_NEW (cfg, ins, OP_MOVE);
1415 ins->dreg = mono_alloc_ireg (cfg);
1416 ins->sreg1 = in->dreg + 1;
1417 MONO_ADD_INS (cfg->cbb, ins);
1418 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1420 MONO_INST_NEW (cfg, ins, OP_MOVE);
1421 ins->dreg = mono_alloc_ireg (cfg);
1422 ins->sreg1 = in->dreg + 2;
1423 MONO_ADD_INS (cfg->cbb, ins);
1424 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1426 MONO_INST_NEW (cfg, ins, OP_MOVE);
1427 ins->dreg = mono_alloc_ireg (cfg);
1428 ins->sreg1 = in->dreg;
1429 MONO_ADD_INS (cfg->cbb, ins);
1431 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1433 } else if (ainfo->regtype == RegTypeStructByAddr) {
1434 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1435 ins->opcode = OP_OUTARG_VT;
1436 ins->sreg1 = in->dreg;
1437 ins->klass = in->klass;
1438 ins->inst_p0 = call;
1439 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1440 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1441 MONO_ADD_INS (cfg->cbb, ins);
1442 } else if (ainfo->regtype == RegTypeStructByVal) {
1443 /* this is further handled in mono_arch_emit_outarg_vt () */
1444 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1445 ins->opcode = OP_OUTARG_VT;
1446 ins->sreg1 = in->dreg;
1447 ins->klass = in->klass;
1448 ins->inst_p0 = call;
1449 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1450 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1451 MONO_ADD_INS (cfg->cbb, ins);
1452 } else if (ainfo->regtype == RegTypeBase) {
1453 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1454 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1455 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1456 if (t->type == MONO_TYPE_R8)
1457 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1459 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1461 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1463 } else if (ainfo->regtype == RegTypeFP) {
1464 if (t->type == MONO_TYPE_VALUETYPE) {
1465 /* this is further handled in mono_arch_emit_outarg_vt () */
1466 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1467 ins->opcode = OP_OUTARG_VT;
1468 ins->sreg1 = in->dreg;
1469 ins->klass = in->klass;
1470 ins->inst_p0 = call;
1471 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1472 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1473 MONO_ADD_INS (cfg->cbb, ins);
1475 cfg->flags |= MONO_CFG_HAS_FPOUT;
1477 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1478 ins->dreg = mono_alloc_freg (cfg);
1479 ins->sreg1 = in->dreg;
1480 MONO_ADD_INS (cfg->cbb, ins);
1482 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
1483 cfg->flags |= MONO_CFG_HAS_FPOUT;
1486 g_assert_not_reached ();
1490 /* Emit the signature cookie in the case that there is no
1491 additional argument */
1492 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1493 emit_sig_cookie (cfg, call, cinfo);
1495 if (cinfo->struct_ret) {
1498 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1499 vtarg->sreg1 = call->vret_var->dreg;
1500 vtarg->dreg = mono_alloc_preg (cfg);
1501 MONO_ADD_INS (cfg->cbb, vtarg);
1503 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1506 call->stack_usage = cinfo->stack_usage;
1507 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1508 cfg->flags |= MONO_CFG_HAS_CALLS;
1514 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1516 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1517 ArgInfo *ainfo = ins->inst_p1;
1518 int ovf_size = ainfo->vtsize;
1519 int doffset = ainfo->offset;
1520 int i, soffset, dreg;
1523 if (ainfo->regtype == RegTypeStructByVal) {
1526 Darwin needs some special handling for 1 and 2 byte arguments
1529 g_assert (ins->klass);
1530 size = mono_class_native_size (ins->klass, NULL);
1531 if (size == 2 || size == 1) {
1532 int tmpr = mono_alloc_ireg (cfg);
1534 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1536 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1537 dreg = mono_alloc_ireg (cfg);
1538 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1539 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1542 for (i = 0; i < ainfo->size; ++i) {
1543 dreg = mono_alloc_ireg (cfg);
1544 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1545 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1546 soffset += sizeof (gpointer);
1549 mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1550 } else if (ainfo->regtype == RegTypeFP) {
1551 int tmpr = mono_alloc_freg (cfg);
1552 if (ainfo->size == 4)
1553 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1555 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1556 dreg = mono_alloc_freg (cfg);
1557 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1558 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1560 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1564 /* FIXME: alignment? */
1565 if (call->signature->pinvoke) {
1566 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1567 vtcopy->backend.is_pinvoke = 1;
1569 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1572 g_assert (ovf_size > 0);
1574 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1575 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1578 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1580 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1585 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1587 MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
1590 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1593 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1594 ins->sreg1 = val->dreg + 1;
1595 ins->sreg2 = val->dreg + 2;
1596 MONO_ADD_INS (cfg->cbb, ins);
1599 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1600 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1604 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1607 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1609 mono_arch_is_inst_imm (gint64 imm)
1615 * Allow tracing to work with this interface (with an optional argument)
1619 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1623 ppc_load (code, ppc_r3, cfg->method);
1624 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1625 ppc_load (code, ppc_r0, func);
1626 ppc_mtlr (code, ppc_r0);
1640 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1643 int save_mode = SAVE_NONE;
1645 MonoMethod *method = cfg->method;
1646 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1647 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1651 offset = code - cfg->native_code;
1652 /* we need about 16 instructions */
1653 if (offset > (cfg->code_size - 16 * 4)) {
1654 cfg->code_size *= 2;
1655 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1656 code = cfg->native_code + offset;
1660 case MONO_TYPE_VOID:
1661 /* special case string .ctor icall */
1662 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1663 save_mode = SAVE_ONE;
1665 save_mode = SAVE_NONE;
1669 save_mode = SAVE_TWO;
1673 save_mode = SAVE_FP;
1675 case MONO_TYPE_VALUETYPE:
1676 save_mode = SAVE_STRUCT;
1679 save_mode = SAVE_ONE;
1683 switch (save_mode) {
1685 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1686 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1687 if (enable_arguments) {
1688 ppc_mr (code, ppc_r5, ppc_r4);
1689 ppc_mr (code, ppc_r4, ppc_r3);
1693 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1694 if (enable_arguments) {
1695 ppc_mr (code, ppc_r4, ppc_r3);
1699 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1700 if (enable_arguments) {
1701 /* FIXME: what reg? */
1702 ppc_fmr (code, ppc_f3, ppc_f1);
1703 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1704 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1708 if (enable_arguments) {
1709 /* FIXME: get the actual address */
1710 ppc_mr (code, ppc_r4, ppc_r3);
1718 ppc_load (code, ppc_r3, cfg->method);
1719 ppc_load (code, ppc_r0, func);
1720 ppc_mtlr (code, ppc_r0);
1723 switch (save_mode) {
1725 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1726 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1729 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1732 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1742 * Conditional branches have a small offset, so if it is likely overflowed,
1743 * we do a branch to the end of the method (uncond branches have much larger
1744 * offsets) where we perform the conditional and jump back unconditionally.
1745 * It's slightly slower, since we add two uncond branches, but it's very simple
1746 * with the current patch implementation and such large methods are likely not
1747 * going to be perf critical anyway.
1752 const char *exception;
1759 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1760 if (ins->flags & MONO_INST_BRLABEL) { \
1761 if (0 && ins->inst_i0->inst_c0) { \
1762 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1764 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1765 ppc_bc (code, (b0), (b1), 0); \
1768 if (0 && ins->inst_true_bb->native_offset) { \
1769 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1771 int br_disp = ins->inst_true_bb->max_offset - offset; \
1772 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1773 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1774 ovfj->data.bb = ins->inst_true_bb; \
1775 ovfj->ip_offset = 0; \
1776 ovfj->b0_cond = (b0); \
1777 ovfj->b1_cond = (b1); \
1778 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1781 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1782 ppc_bc (code, (b0), (b1), 0); \
1787 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1789 /* emit an exception if condition is fail
1791 * We assign the extra code used to throw the implicit exceptions
1792 * to cfg->bb_exit as far as the big branch handling is concerned
1794 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1796 int br_disp = cfg->bb_exit->max_offset - offset; \
1797 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1798 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1799 ovfj->data.exception = (exc_name); \
1800 ovfj->ip_offset = code - cfg->native_code; \
1801 ovfj->b0_cond = (b0); \
1802 ovfj->b1_cond = (b1); \
1803 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1805 cfg->bb_exit->max_offset += 24; \
1807 mono_add_patch_info (cfg, code - cfg->native_code, \
1808 MONO_PATCH_INFO_EXC, exc_name); \
1809 ppc_bcl (code, (b0), (b1), 0); \
1813 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1816 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1821 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1823 MonoInst *ins, *n, *last_ins = NULL;
1825 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1826 switch (ins->opcode) {
1828 /* remove unnecessary multiplication with 1 */
1829 if (ins->inst_imm == 1) {
1830 if (ins->dreg != ins->sreg1) {
1831 ins->opcode = OP_MOVE;
1833 MONO_DELETE_INS (bb, ins);
1837 int power2 = mono_is_power_of_two (ins->inst_imm);
1839 ins->opcode = OP_SHL_IMM;
1840 ins->inst_imm = power2;
1844 case OP_LOAD_MEMBASE:
1845 case OP_LOADI4_MEMBASE:
1847 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1848 * OP_LOAD_MEMBASE offset(basereg), reg
1850 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1851 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1852 ins->inst_basereg == last_ins->inst_destbasereg &&
1853 ins->inst_offset == last_ins->inst_offset) {
1854 if (ins->dreg == last_ins->sreg1) {
1855 MONO_DELETE_INS (bb, ins);
1858 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1859 ins->opcode = OP_MOVE;
1860 ins->sreg1 = last_ins->sreg1;
1864 * Note: reg1 must be different from the basereg in the second load
1865 * OP_LOAD_MEMBASE offset(basereg), reg1
1866 * OP_LOAD_MEMBASE offset(basereg), reg2
1868 * OP_LOAD_MEMBASE offset(basereg), reg1
1869 * OP_MOVE reg1, reg2
1871 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1872 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1873 ins->inst_basereg != last_ins->dreg &&
1874 ins->inst_basereg == last_ins->inst_basereg &&
1875 ins->inst_offset == last_ins->inst_offset) {
1877 if (ins->dreg == last_ins->dreg) {
1878 MONO_DELETE_INS (bb, ins);
1881 ins->opcode = OP_MOVE;
1882 ins->sreg1 = last_ins->dreg;
1885 //g_assert_not_reached ();
1889 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1890 * OP_LOAD_MEMBASE offset(basereg), reg
1892 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1893 * OP_ICONST reg, imm
1895 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1896 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1897 ins->inst_basereg == last_ins->inst_destbasereg &&
1898 ins->inst_offset == last_ins->inst_offset) {
1899 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1900 ins->opcode = OP_ICONST;
1901 ins->inst_c0 = last_ins->inst_imm;
1902 g_assert_not_reached (); // check this rule
1906 case OP_LOADU1_MEMBASE:
1907 case OP_LOADI1_MEMBASE:
1908 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1909 ins->inst_basereg == last_ins->inst_destbasereg &&
1910 ins->inst_offset == last_ins->inst_offset) {
1911 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1912 ins->sreg1 = last_ins->sreg1;
1915 case OP_LOADU2_MEMBASE:
1916 case OP_LOADI2_MEMBASE:
1917 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1918 ins->inst_basereg == last_ins->inst_destbasereg &&
1919 ins->inst_offset == last_ins->inst_offset) {
1920 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1921 ins->sreg1 = last_ins->sreg1;
1925 ins->opcode = OP_MOVE;
1929 if (ins->dreg == ins->sreg1) {
1930 MONO_DELETE_INS (bb, ins);
1934 * OP_MOVE sreg, dreg
1935 * OP_MOVE dreg, sreg
1937 if (last_ins && last_ins->opcode == OP_MOVE &&
1938 ins->sreg1 == last_ins->dreg &&
1939 ins->dreg == last_ins->sreg1) {
1940 MONO_DELETE_INS (bb, ins);
1948 bb->last_ins = last_ins;
1952 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1954 g_assert (cfg->new_ir);
1956 switch (ins->opcode) {
1957 case OP_ICONV_TO_R_UN: {
1958 static const guint64 adjust_val = 0x4330000000000000ULL;
1959 int msw_reg = mono_alloc_ireg (cfg);
1960 int adj_reg = mono_alloc_freg (cfg);
1961 int tmp_reg = mono_alloc_freg (cfg);
1962 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1963 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
1964 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
1965 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1966 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
1967 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1968 ins->opcode = OP_NOP;
1971 case OP_ICONV_TO_R4:
1972 case OP_ICONV_TO_R8: {
1973 /* FIXME: change precision for CEE_CONV_R4 */
1974 static const guint64 adjust_val = 0x4330000080000000ULL;
1975 int msw_reg = mono_alloc_ireg (cfg);
1976 int xored = mono_alloc_ireg (cfg);
1977 int adj_reg = mono_alloc_freg (cfg);
1978 int tmp_reg = mono_alloc_freg (cfg);
1979 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1980 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
1981 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
1982 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
1983 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
1984 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
1985 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1986 ins->opcode = OP_NOP;
1990 int msw_reg = mono_alloc_ireg (cfg);
1991 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
1992 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
1993 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
1994 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1995 ins->opcode = OP_NOP;
2002 * the branch_b0_table should maintain the order of these
2016 branch_b0_table [] = {
2031 branch_b1_table [] = {
2045 #define NEW_INS(cfg,dest,op) do { \
2046 MONO_INST_NEW((cfg), (dest), (op)); \
2047 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2051 map_to_reg_reg_op (int op)
2060 case OP_COMPARE_IMM:
2062 case OP_ICOMPARE_IMM:
2078 case OP_LOAD_MEMBASE:
2079 return OP_LOAD_MEMINDEX;
2080 case OP_LOADI4_MEMBASE:
2081 return OP_LOADI4_MEMINDEX;
2082 case OP_LOADU4_MEMBASE:
2083 return OP_LOADU4_MEMINDEX;
2084 case OP_LOADU1_MEMBASE:
2085 return OP_LOADU1_MEMINDEX;
2086 case OP_LOADI2_MEMBASE:
2087 return OP_LOADI2_MEMINDEX;
2088 case OP_LOADU2_MEMBASE:
2089 return OP_LOADU2_MEMINDEX;
2090 case OP_LOADI1_MEMBASE:
2091 return OP_LOADI1_MEMINDEX;
2092 case OP_LOADR4_MEMBASE:
2093 return OP_LOADR4_MEMINDEX;
2094 case OP_LOADR8_MEMBASE:
2095 return OP_LOADR8_MEMINDEX;
2096 case OP_STOREI1_MEMBASE_REG:
2097 return OP_STOREI1_MEMINDEX;
2098 case OP_STOREI2_MEMBASE_REG:
2099 return OP_STOREI2_MEMINDEX;
2100 case OP_STOREI4_MEMBASE_REG:
2101 return OP_STOREI4_MEMINDEX;
2102 case OP_STORE_MEMBASE_REG:
2103 return OP_STORE_MEMINDEX;
2104 case OP_STORER4_MEMBASE_REG:
2105 return OP_STORER4_MEMINDEX;
2106 case OP_STORER8_MEMBASE_REG:
2107 return OP_STORER8_MEMINDEX;
2108 case OP_STORE_MEMBASE_IMM:
2109 return OP_STORE_MEMBASE_REG;
2110 case OP_STOREI1_MEMBASE_IMM:
2111 return OP_STOREI1_MEMBASE_REG;
2112 case OP_STOREI2_MEMBASE_IMM:
2113 return OP_STOREI2_MEMBASE_REG;
2114 case OP_STOREI4_MEMBASE_IMM:
2115 return OP_STOREI4_MEMBASE_REG;
2117 return mono_op_imm_to_op (op);
2120 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2122 #define compare_opcode_is_unsigned(opcode) \
2123 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2124 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2125 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2126 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2127 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2129 * Remove from the instruction list the instructions that can't be
2130 * represented with very simple instructions with no register
2134 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2136 MonoInst *ins, *next, *temp, *last_ins = NULL;
2139 /* setup the virtual reg allocator */
2140 if (bb->max_vreg > cfg->rs->next_vreg)
2141 cfg->rs->next_vreg = bb->max_vreg;
2143 MONO_BB_FOR_EACH_INS (bb, ins) {
2145 switch (ins->opcode) {
2146 case OP_IDIV_UN_IMM:
2149 case OP_IREM_UN_IMM:
2150 NEW_INS (cfg, temp, OP_ICONST);
2151 temp->inst_c0 = ins->inst_imm;
2152 temp->dreg = mono_regstate_next_int (cfg->rs);
2153 ins->sreg2 = temp->dreg;
2154 if (ins->opcode == OP_IDIV_IMM)
2155 ins->opcode = OP_IDIV;
2156 else if (ins->opcode == OP_IREM_IMM)
2157 ins->opcode = OP_IREM;
2158 else if (ins->opcode == OP_IDIV_UN_IMM)
2159 ins->opcode = OP_IDIV_UN;
2160 else if (ins->opcode == OP_IREM_UN_IMM)
2161 ins->opcode = OP_IREM_UN;
2163 /* handle rem separately */
2168 /* we change a rem dest, src1, src2 to
2169 * div temp1, src1, src2
2170 * mul temp2, temp1, src2
2171 * sub dest, src1, temp2
2173 NEW_INS (cfg, mul, OP_IMUL);
2174 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2175 temp->sreg1 = ins->sreg1;
2176 temp->sreg2 = ins->sreg2;
2177 temp->dreg = mono_regstate_next_int (cfg->rs);
2178 mul->sreg1 = temp->dreg;
2179 mul->sreg2 = ins->sreg2;
2180 mul->dreg = mono_regstate_next_int (cfg->rs);
2181 ins->opcode = OP_ISUB;
2182 ins->sreg2 = mul->dreg;
2188 if (!ppc_is_imm16 (ins->inst_imm)) {
2189 NEW_INS (cfg, temp, OP_ICONST);
2190 temp->inst_c0 = ins->inst_imm;
2191 temp->dreg = mono_regstate_next_int (cfg->rs);
2192 ins->sreg2 = temp->dreg;
2193 ins->opcode = map_to_reg_reg_op (ins->opcode);
2198 if (!ppc_is_imm16 (-ins->inst_imm)) {
2199 NEW_INS (cfg, temp, OP_ICONST);
2200 temp->inst_c0 = ins->inst_imm;
2201 temp->dreg = mono_regstate_next_int (cfg->rs);
2202 ins->sreg2 = temp->dreg;
2203 ins->opcode = map_to_reg_reg_op (ins->opcode);
2212 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2213 NEW_INS (cfg, temp, OP_ICONST);
2214 temp->inst_c0 = ins->inst_imm;
2215 temp->dreg = mono_regstate_next_int (cfg->rs);
2216 ins->sreg2 = temp->dreg;
2217 ins->opcode = map_to_reg_reg_op (ins->opcode);
2225 NEW_INS (cfg, temp, OP_ICONST);
2226 temp->inst_c0 = ins->inst_imm;
2227 temp->dreg = mono_regstate_next_int (cfg->rs);
2228 ins->sreg2 = temp->dreg;
2229 ins->opcode = map_to_reg_reg_op (ins->opcode);
2231 case OP_COMPARE_IMM:
2232 case OP_ICOMPARE_IMM:
2234 /* Branch opts can eliminate the branch */
2235 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2236 ins->opcode = OP_NOP;
2240 if (compare_opcode_is_unsigned (next->opcode)) {
2241 if (!ppc_is_uimm16 (ins->inst_imm)) {
2242 NEW_INS (cfg, temp, OP_ICONST);
2243 temp->inst_c0 = ins->inst_imm;
2244 temp->dreg = mono_regstate_next_int (cfg->rs);
2245 ins->sreg2 = temp->dreg;
2246 ins->opcode = map_to_reg_reg_op (ins->opcode);
2249 if (!ppc_is_imm16 (ins->inst_imm)) {
2250 NEW_INS (cfg, temp, OP_ICONST);
2251 temp->inst_c0 = ins->inst_imm;
2252 temp->dreg = mono_regstate_next_int (cfg->rs);
2253 ins->sreg2 = temp->dreg;
2254 ins->opcode = map_to_reg_reg_op (ins->opcode);
2260 if (ins->inst_imm == 1) {
2261 ins->opcode = OP_MOVE;
2264 if (ins->inst_imm == 0) {
2265 ins->opcode = OP_ICONST;
2269 imm = mono_is_power_of_two (ins->inst_imm);
2271 ins->opcode = OP_SHL_IMM;
2272 ins->inst_imm = imm;
2275 if (!ppc_is_imm16 (ins->inst_imm)) {
2276 NEW_INS (cfg, temp, OP_ICONST);
2277 temp->inst_c0 = ins->inst_imm;
2278 temp->dreg = mono_regstate_next_int (cfg->rs);
2279 ins->sreg2 = temp->dreg;
2280 ins->opcode = map_to_reg_reg_op (ins->opcode);
2283 case OP_LOCALLOC_IMM:
2284 NEW_INS (cfg, temp, OP_ICONST);
2285 temp->inst_c0 = ins->inst_imm;
2286 temp->dreg = mono_regstate_next_int (cfg->rs);
2287 ins->sreg1 = temp->dreg;
2288 ins->opcode = OP_LOCALLOC;
2290 case OP_LOAD_MEMBASE:
2291 case OP_LOADI4_MEMBASE:
2292 case OP_LOADU4_MEMBASE:
2293 case OP_LOADI2_MEMBASE:
2294 case OP_LOADU2_MEMBASE:
2295 case OP_LOADI1_MEMBASE:
2296 case OP_LOADU1_MEMBASE:
2297 case OP_LOADR4_MEMBASE:
2298 case OP_LOADR8_MEMBASE:
2299 case OP_STORE_MEMBASE_REG:
2300 case OP_STOREI4_MEMBASE_REG:
2301 case OP_STOREI2_MEMBASE_REG:
2302 case OP_STOREI1_MEMBASE_REG:
2303 case OP_STORER4_MEMBASE_REG:
2304 case OP_STORER8_MEMBASE_REG:
2305 /* we can do two things: load the immed in a register
2306 * and use an indexed load, or see if the immed can be
2307 * represented as an ad_imm + a load with a smaller offset
2308 * that fits. We just do the first for now, optimize later.
2310 if (ppc_is_imm16 (ins->inst_offset))
2312 NEW_INS (cfg, temp, OP_ICONST);
2313 temp->inst_c0 = ins->inst_offset;
2314 temp->dreg = mono_regstate_next_int (cfg->rs);
2315 ins->sreg2 = temp->dreg;
2316 ins->opcode = map_to_reg_reg_op (ins->opcode);
2318 case OP_STORE_MEMBASE_IMM:
2319 case OP_STOREI1_MEMBASE_IMM:
2320 case OP_STOREI2_MEMBASE_IMM:
2321 case OP_STOREI4_MEMBASE_IMM:
2322 NEW_INS (cfg, temp, OP_ICONST);
2323 temp->inst_c0 = ins->inst_imm;
2324 temp->dreg = mono_regstate_next_int (cfg->rs);
2325 ins->sreg1 = temp->dreg;
2326 ins->opcode = map_to_reg_reg_op (ins->opcode);
2328 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2331 NEW_INS (cfg, temp, OP_ICONST);
2332 temp->inst_c0 = (guint32)ins->inst_p0;
2333 temp->dreg = mono_regstate_next_int (cfg->rs);
2334 ins->inst_basereg = temp->dreg;
2335 ins->inst_offset = 0;
2336 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2338 /* make it handle the possibly big ins->inst_offset
2339 * later optimize to use lis + load_membase
2345 bb->last_ins = last_ins;
2346 bb->max_vreg = cfg->rs->next_vreg;
2351 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2353 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2354 ppc_fctiwz (code, ppc_f0, sreg);
2355 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2356 ppc_lwz (code, dreg, -4, ppc_sp);
2359 ppc_andid (code, dreg, dreg, 0xff);
2361 ppc_andid (code, dreg, dreg, 0xffff);
2364 ppc_extsb (code, dreg, dreg);
2366 ppc_extsh (code, dreg, dreg);
2371 static unsigned char*
2372 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2375 int sreg = tree->sreg1;
2376 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2377 if (tree->flags & MONO_INST_INIT) {
2379 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2380 x86_push_reg (code, X86_EAX);
2383 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2384 x86_push_reg (code, X86_ECX);
2387 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2388 x86_push_reg (code, X86_EDI);
2392 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2393 if (sreg != X86_ECX)
2394 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2395 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2397 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2399 x86_prefix (code, X86_REP_PREFIX);
2402 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2403 x86_pop_reg (code, X86_EDI);
2404 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2405 x86_pop_reg (code, X86_ECX);
2406 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2407 x86_pop_reg (code, X86_EAX);
2415 const guchar *target;
2420 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2423 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2424 PatchData *pdata = (PatchData*)user_data;
2425 guchar *code = data;
2426 guint32 *thunks = data;
2427 guint32 *endthunks = (guint32*)(code + bsize);
2431 int difflow, diffhigh;
2433 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2434 difflow = (char*)pdata->code - (char*)thunks;
2435 diffhigh = (char*)pdata->code - (char*)endthunks;
2436 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2439 templ = (guchar*)load;
2440 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2441 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2443 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2444 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2445 while (thunks < endthunks) {
2446 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2447 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2448 ppc_patch (pdata->code, (guchar*)thunks);
2449 mono_arch_flush_icache (pdata->code, 4);
2452 static int num_thunks = 0;
2454 if ((num_thunks % 20) == 0)
2455 g_print ("num_thunks lookup: %d\n", num_thunks);
2458 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2459 /* found a free slot instead: emit thunk */
2460 code = (guchar*)thunks;
2461 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2462 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2463 ppc_mtctr (code, ppc_r0);
2464 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2465 mono_arch_flush_icache ((guchar*)thunks, 16);
2467 ppc_patch (pdata->code, (guchar*)thunks);
2468 mono_arch_flush_icache (pdata->code, 4);
2471 static int num_thunks = 0;
2473 if ((num_thunks % 20) == 0)
2474 g_print ("num_thunks: %d\n", num_thunks);
2478 /* skip 16 bytes, the size of the thunk */
2482 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2488 handle_thunk (int absolute, guchar *code, const guchar *target) {
2489 MonoDomain *domain = mono_domain_get ();
2493 pdata.target = target;
2494 pdata.absolute = absolute;
2497 mono_domain_lock (domain);
2498 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2501 /* this uses the first available slot */
2503 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2505 mono_domain_unlock (domain);
2507 if (pdata.found != 1)
2508 g_print ("thunk failed for %p from %p\n", target, code);
2509 g_assert (pdata.found == 1);
2513 ppc_patch (guchar *code, const guchar *target)
2515 guint32 ins = *(guint32*)code;
2516 guint32 prim = ins >> 26;
2519 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2521 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2522 gint diff = target - code;
2524 if (diff <= 33554431){
2525 ins = (18 << 26) | (diff) | (ins & 1);
2526 *(guint32*)code = ins;
2530 /* diff between 0 and -33554432 */
2531 if (diff >= -33554432){
2532 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2533 *(guint32*)code = ins;
2538 if ((glong)target >= 0){
2539 if ((glong)target <= 33554431){
2540 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2541 *(guint32*)code = ins;
2545 if ((glong)target >= -33554432){
2546 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2547 *(guint32*)code = ins;
2552 handle_thunk (TRUE, code, target);
2555 g_assert_not_reached ();
2562 guint32 li = (guint32)target;
2563 ins = (ins & 0xffff0000) | (ins & 3);
2564 ovf = li & 0xffff0000;
2565 if (ovf != 0 && ovf != 0xffff0000)
2566 g_assert_not_reached ();
2569 // FIXME: assert the top bits of li are 0
2571 gint diff = target - code;
2572 ins = (ins & 0xffff0000) | (ins & 3);
2573 ovf = diff & 0xffff0000;
2574 if (ovf != 0 && ovf != 0xffff0000)
2575 g_assert_not_reached ();
2579 *(guint32*)code = ins;
2583 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2585 /* the trampoline code will try to patch the blrl, blr, bcctr */
2586 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2589 /* this is the lis/ori/mtlr/blrl sequence */
2590 seq = (guint32*)code;
2591 g_assert ((seq [0] >> 26) == 15);
2592 g_assert ((seq [1] >> 26) == 24);
2593 g_assert ((seq [2] >> 26) == 31);
2594 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2595 /* FIXME: make this thread safe */
2596 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2597 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2598 mono_arch_flush_icache (code - 8, 8);
2600 g_assert_not_reached ();
2602 // g_print ("patched with 0x%08x\n", ins);
2606 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2608 switch (ins->opcode) {
2611 case OP_FCALL_MEMBASE:
2612 if (ins->dreg != ppc_f1)
2613 ppc_fmr (code, ins->dreg, ppc_f1);
2621 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2623 MonoInst *ins, *next;
2626 guint8 *code = cfg->native_code + cfg->code_len;
2627 MonoInst *last_ins = NULL;
2628 guint last_offset = 0;
2631 /* we don't align basic blocks of loops on ppc */
2633 if (cfg->verbose_level > 2)
2634 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2636 cpos = bb->max_offset;
2638 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2639 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2640 //g_assert (!mono_compile_aot);
2643 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2644 /* this is not thread save, but good enough */
2645 /* fixme: howto handle overflows? */
2646 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2649 MONO_BB_FOR_EACH_INS (bb, ins) {
2650 offset = code - cfg->native_code;
2652 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2654 if (offset > (cfg->code_size - max_len - 16)) {
2655 cfg->code_size *= 2;
2656 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2657 code = cfg->native_code + offset;
2659 // if (ins->cil_code)
2660 // g_print ("cil code\n");
2661 mono_debug_record_line_number (cfg, ins, offset);
2663 switch (ins->opcode) {
2666 case OP_DUMMY_STORE:
2667 case OP_NOT_REACHED:
2671 emit_tls_access (code, ins->dreg, ins->inst_offset);
2674 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2675 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2676 ppc_mr (code, ppc_r4, ppc_r0);
2679 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2680 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2681 ppc_mr (code, ppc_r4, ppc_r0);
2683 case OP_MEMORY_BARRIER:
2686 case OP_STOREI1_MEMBASE_REG:
2687 if (ppc_is_imm16 (ins->inst_offset)) {
2688 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2690 ppc_load (code, ppc_r0, ins->inst_offset);
2691 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2694 case OP_STOREI2_MEMBASE_REG:
2695 if (ppc_is_imm16 (ins->inst_offset)) {
2696 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2698 ppc_load (code, ppc_r0, ins->inst_offset);
2699 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2702 case OP_STORE_MEMBASE_REG:
2703 case OP_STOREI4_MEMBASE_REG:
2704 if (ppc_is_imm16 (ins->inst_offset)) {
2705 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2707 ppc_load (code, ppc_r0, ins->inst_offset);
2708 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2711 case OP_STOREI1_MEMINDEX:
2712 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2714 case OP_STOREI2_MEMINDEX:
2715 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2717 case OP_STORE_MEMINDEX:
2718 case OP_STOREI4_MEMINDEX:
2719 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2722 g_assert_not_reached ();
2724 case OP_LOAD_MEMBASE:
2725 case OP_LOADI4_MEMBASE:
2726 case OP_LOADU4_MEMBASE:
2727 if (ppc_is_imm16 (ins->inst_offset)) {
2728 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2730 ppc_load (code, ppc_r0, ins->inst_offset);
2731 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2734 case OP_LOADI1_MEMBASE:
2735 case OP_LOADU1_MEMBASE:
2736 if (ppc_is_imm16 (ins->inst_offset)) {
2737 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2739 ppc_load (code, ppc_r0, ins->inst_offset);
2740 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2742 if (ins->opcode == OP_LOADI1_MEMBASE)
2743 ppc_extsb (code, ins->dreg, ins->dreg);
2745 case OP_LOADU2_MEMBASE:
2746 if (ppc_is_imm16 (ins->inst_offset)) {
2747 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2749 ppc_load (code, ppc_r0, ins->inst_offset);
2750 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2753 case OP_LOADI2_MEMBASE:
2754 if (ppc_is_imm16 (ins->inst_offset)) {
2755 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2757 ppc_load (code, ppc_r0, ins->inst_offset);
2758 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2761 case OP_LOAD_MEMINDEX:
2762 case OP_LOADI4_MEMINDEX:
2763 case OP_LOADU4_MEMINDEX:
2764 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2766 case OP_LOADU2_MEMINDEX:
2767 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2769 case OP_LOADI2_MEMINDEX:
2770 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2772 case OP_LOADU1_MEMINDEX:
2773 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2775 case OP_LOADI1_MEMINDEX:
2776 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2777 ppc_extsb (code, ins->dreg, ins->dreg);
2779 case OP_ICONV_TO_I1:
2780 ppc_extsb (code, ins->dreg, ins->sreg1);
2782 case OP_ICONV_TO_I2:
2783 ppc_extsh (code, ins->dreg, ins->sreg1);
2785 case OP_ICONV_TO_U1:
2786 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2788 case OP_ICONV_TO_U2:
2789 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2794 if (next && compare_opcode_is_unsigned (next->opcode))
2795 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2797 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2799 case OP_COMPARE_IMM:
2800 case OP_ICOMPARE_IMM:
2802 if (next && compare_opcode_is_unsigned (next->opcode)) {
2803 if (ppc_is_uimm16 (ins->inst_imm)) {
2804 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2806 g_assert_not_reached ();
2809 if (ppc_is_imm16 (ins->inst_imm)) {
2810 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2812 g_assert_not_reached ();
2821 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2824 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2828 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2831 if (ppc_is_imm16 (ins->inst_imm)) {
2832 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2834 g_assert_not_reached ();
2839 if (ppc_is_imm16 (ins->inst_imm)) {
2840 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2842 g_assert_not_reached ();
2846 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2848 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2849 ppc_mfspr (code, ppc_r0, ppc_xer);
2850 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2851 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2853 case OP_IADD_OVF_UN:
2854 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2856 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2857 ppc_mfspr (code, ppc_r0, ppc_xer);
2858 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2859 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2862 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2864 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2865 ppc_mfspr (code, ppc_r0, ppc_xer);
2866 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2867 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2869 case OP_ISUB_OVF_UN:
2870 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2872 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2873 ppc_mfspr (code, ppc_r0, ppc_xer);
2874 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2875 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2877 case OP_ADD_OVF_CARRY:
2878 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2880 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2881 ppc_mfspr (code, ppc_r0, ppc_xer);
2882 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2883 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2885 case OP_ADD_OVF_UN_CARRY:
2886 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2888 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2889 ppc_mfspr (code, ppc_r0, ppc_xer);
2890 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2891 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2893 case OP_SUB_OVF_CARRY:
2894 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2896 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2897 ppc_mfspr (code, ppc_r0, ppc_xer);
2898 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2899 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2901 case OP_SUB_OVF_UN_CARRY:
2902 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2904 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2905 ppc_mfspr (code, ppc_r0, ppc_xer);
2906 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2907 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2911 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2914 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2918 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2922 // we add the negated value
2923 if (ppc_is_imm16 (-ins->inst_imm))
2924 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2926 g_assert_not_reached ();
2930 g_assert (ppc_is_imm16 (ins->inst_imm));
2931 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2934 ppc_subfze (code, ins->dreg, ins->sreg1);
2937 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2938 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2942 if (!(ins->inst_imm & 0xffff0000)) {
2943 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2944 } else if (!(ins->inst_imm & 0xffff)) {
2945 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2947 g_assert_not_reached ();
2951 guint8 *divisor_is_m1;
2952 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2954 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2955 divisor_is_m1 = code;
2956 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2957 ppc_lis (code, ppc_r0, 0x8000);
2958 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2959 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2960 ppc_patch (divisor_is_m1, code);
2961 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2963 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2964 ppc_mfspr (code, ppc_r0, ppc_xer);
2965 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2966 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2970 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2971 ppc_mfspr (code, ppc_r0, ppc_xer);
2972 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2973 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2979 g_assert_not_reached ();
2981 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2985 if (!(ins->inst_imm & 0xffff0000)) {
2986 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2987 } else if (!(ins->inst_imm & 0xffff)) {
2988 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2990 g_assert_not_reached ();
2994 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2998 if (!(ins->inst_imm & 0xffff0000)) {
2999 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3000 } else if (!(ins->inst_imm & 0xffff)) {
3001 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3003 g_assert_not_reached ();
3007 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3011 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3014 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3018 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3021 case OP_ISHR_UN_IMM:
3023 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3025 ppc_mr (code, ins->dreg, ins->sreg1);
3028 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3031 ppc_not (code, ins->dreg, ins->sreg1);
3034 ppc_neg (code, ins->dreg, ins->sreg1);
3037 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3041 if (ppc_is_imm16 (ins->inst_imm)) {
3042 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3044 g_assert_not_reached ();
3048 /* we annot use mcrxr, since it's not implemented on some processors
3049 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3051 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3052 ppc_mfspr (code, ppc_r0, ppc_xer);
3053 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3054 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3056 case OP_IMUL_OVF_UN:
3057 /* we first multiply to get the high word and compare to 0
3058 * to set the flags, then the result is discarded and then
3059 * we multiply to get the lower * bits result
3061 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3062 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3063 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3064 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3067 ppc_load (code, ins->dreg, ins->inst_c0);
3070 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3071 ppc_lis (code, ins->dreg, 0);
3072 ppc_ori (code, ins->dreg, ins->dreg, 0);
3074 case OP_ICONV_TO_I4:
3075 case OP_ICONV_TO_U4:
3077 ppc_mr (code, ins->dreg, ins->sreg1);
3080 int saved = ins->sreg1;
3081 if (ins->sreg1 == ppc_r3) {
3082 ppc_mr (code, ppc_r0, ins->sreg1);
3085 if (ins->sreg2 != ppc_r3)
3086 ppc_mr (code, ppc_r3, ins->sreg2);
3087 if (saved != ppc_r4)
3088 ppc_mr (code, ppc_r4, saved);
3092 ppc_fmr (code, ins->dreg, ins->sreg1);
3094 case OP_FCONV_TO_R4:
3095 ppc_frsp (code, ins->dreg, ins->sreg1);
3101 * Keep in sync with mono_arch_emit_epilog
3103 g_assert (!cfg->method->save_lmf);
3105 * Note: we can use ppc_r11 here because it is dead anyway:
3106 * we're leaving the method.
3108 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3109 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3110 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3112 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3113 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3115 ppc_mtlr (code, ppc_r0);
3117 if (ppc_is_imm16 (cfg->stack_usage)) {
3118 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3120 ppc_load (code, ppc_r11, cfg->stack_usage);
3121 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3123 if (!cfg->method->save_lmf) {
3124 /*for (i = 31; i >= 14; --i) {
3125 if (cfg->used_float_regs & (1 << i)) {
3126 pos += sizeof (double);
3127 ppc_lfd (code, i, -pos, cfg->frame_reg);
3130 for (i = 31; i >= 13; --i) {
3131 if (cfg->used_int_regs & (1 << i)) {
3132 pos += sizeof (gulong);
3133 ppc_lwz (code, i, -pos, cfg->frame_reg);
3137 /* FIXME restore from MonoLMF: though this can't happen yet */
3139 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3144 /* ensure ins->sreg1 is not NULL */
3145 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3148 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3149 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3151 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3152 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3154 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3163 call = (MonoCallInst*)ins;
3164 if (ins->flags & MONO_INST_HAS_METHOD)
3165 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3167 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3168 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3169 ppc_lis (code, ppc_r0, 0);
3170 ppc_ori (code, ppc_r0, ppc_r0, 0);
3171 ppc_mtlr (code, ppc_r0);
3176 /* FIXME: this should be handled somewhere else in the new jit */
3177 code = emit_move_return_value (cfg, ins, code);
3183 case OP_VOIDCALL_REG:
3185 ppc_mtlr (code, ins->sreg1);
3187 /* FIXME: this should be handled somewhere else in the new jit */
3188 code = emit_move_return_value (cfg, ins, code);
3190 case OP_FCALL_MEMBASE:
3191 case OP_LCALL_MEMBASE:
3192 case OP_VCALL_MEMBASE:
3193 case OP_VCALL2_MEMBASE:
3194 case OP_VOIDCALL_MEMBASE:
3195 case OP_CALL_MEMBASE:
3196 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3197 ppc_mtlr (code, ppc_r0);
3199 /* FIXME: this should be handled somewhere else in the new jit */
3200 code = emit_move_return_value (cfg, ins, code);
3203 g_assert_not_reached ();
3206 guint8 * zero_loop_jump, * zero_loop_start;
3207 /* keep alignment */
3208 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3209 int area_offset = alloca_waste;
3211 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3212 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3213 /* use ctr to store the number of words to 0 if needed */
3214 if (ins->flags & MONO_INST_INIT) {
3215 /* we zero 4 bytes at a time:
3216 * we add 7 instead of 3 so that we set the counter to
3217 * at least 1, otherwise the bdnz instruction will make
3218 * it negative and iterate billions of times.
3220 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3221 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3222 ppc_mtctr (code, ppc_r0);
3224 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3225 ppc_neg (code, ppc_r11, ppc_r11);
3226 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3228 if (ins->flags & MONO_INST_INIT) {
3229 /* adjust the dest reg by -4 so we can use stwu */
3230 /* we actually adjust -8 because we let the loop
3233 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3234 ppc_li (code, ppc_r11, 0);
3235 zero_loop_start = code;
3236 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3237 zero_loop_jump = code;
3238 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3239 ppc_patch (zero_loop_jump, zero_loop_start);
3241 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3246 ppc_mr (code, ppc_r3, ins->sreg1);
3247 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3248 (gpointer)"mono_arch_throw_exception");
3249 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3250 ppc_lis (code, ppc_r0, 0);
3251 ppc_ori (code, ppc_r0, ppc_r0, 0);
3252 ppc_mtlr (code, ppc_r0);
3261 ppc_mr (code, ppc_r3, ins->sreg1);
3262 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3263 (gpointer)"mono_arch_rethrow_exception");
3264 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3265 ppc_lis (code, ppc_r0, 0);
3266 ppc_ori (code, ppc_r0, ppc_r0, 0);
3267 ppc_mtlr (code, ppc_r0);
3274 case OP_START_HANDLER: {
3275 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3276 ppc_mflr (code, ppc_r0);
3277 if (ppc_is_imm16 (spvar->inst_offset)) {
3278 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3280 ppc_load (code, ppc_r11, spvar->inst_offset);
3281 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3285 case OP_ENDFILTER: {
3286 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3287 if (ins->sreg1 != ppc_r3)
3288 ppc_mr (code, ppc_r3, ins->sreg1);
3289 if (ppc_is_imm16 (spvar->inst_offset)) {
3290 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3292 ppc_load (code, ppc_r11, spvar->inst_offset);
3293 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3295 ppc_mtlr (code, ppc_r0);
3299 case OP_ENDFINALLY: {
3300 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3301 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3302 ppc_mtlr (code, ppc_r0);
3306 case OP_CALL_HANDLER:
3307 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3311 ins->inst_c0 = code - cfg->native_code;
3314 if (ins->flags & MONO_INST_BRLABEL) {
3315 /*if (ins->inst_i0->inst_c0) {
3317 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3319 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3323 /*if (ins->inst_target_bb->native_offset) {
3325 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3327 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3333 ppc_mtctr (code, ins->sreg1);
3334 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3338 ppc_li (code, ins->dreg, 0);
3339 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3340 ppc_li (code, ins->dreg, 1);
3346 ppc_li (code, ins->dreg, 1);
3347 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3348 ppc_li (code, ins->dreg, 0);
3354 ppc_li (code, ins->dreg, 1);
3355 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3356 ppc_li (code, ins->dreg, 0);
3358 case OP_COND_EXC_EQ:
3359 case OP_COND_EXC_NE_UN:
3360 case OP_COND_EXC_LT:
3361 case OP_COND_EXC_LT_UN:
3362 case OP_COND_EXC_GT:
3363 case OP_COND_EXC_GT_UN:
3364 case OP_COND_EXC_GE:
3365 case OP_COND_EXC_GE_UN:
3366 case OP_COND_EXC_LE:
3367 case OP_COND_EXC_LE_UN:
3368 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3370 case OP_COND_EXC_IEQ:
3371 case OP_COND_EXC_INE_UN:
3372 case OP_COND_EXC_ILT:
3373 case OP_COND_EXC_ILT_UN:
3374 case OP_COND_EXC_IGT:
3375 case OP_COND_EXC_IGT_UN:
3376 case OP_COND_EXC_IGE:
3377 case OP_COND_EXC_IGE_UN:
3378 case OP_COND_EXC_ILE:
3379 case OP_COND_EXC_ILE_UN:
3380 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3383 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3385 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3386 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3387 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3389 case OP_COND_EXC_OV:
3390 /*ppc_mcrxr (code, 0);
3391 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3393 case OP_COND_EXC_NC:
3394 case OP_COND_EXC_NO:
3395 g_assert_not_reached ();
3407 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3410 /* floating point opcodes */
3413 g_assert_not_reached ();
3414 case OP_STORER8_MEMBASE_REG:
3415 if (ppc_is_imm16 (ins->inst_offset)) {
3416 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3418 ppc_load (code, ppc_r0, ins->inst_offset);
3419 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3422 case OP_LOADR8_MEMBASE:
3423 if (ppc_is_imm16 (ins->inst_offset)) {
3424 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3426 ppc_load (code, ppc_r0, ins->inst_offset);
3427 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3430 case OP_STORER4_MEMBASE_REG:
3431 ppc_frsp (code, ins->sreg1, ins->sreg1);
3432 if (ppc_is_imm16 (ins->inst_offset)) {
3433 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3435 ppc_load (code, ppc_r0, ins->inst_offset);
3436 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3439 case OP_LOADR4_MEMBASE:
3440 if (ppc_is_imm16 (ins->inst_offset)) {
3441 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3443 ppc_load (code, ppc_r0, ins->inst_offset);
3444 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3447 case OP_LOADR4_MEMINDEX:
3448 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3450 case OP_LOADR8_MEMINDEX:
3451 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3453 case OP_STORER4_MEMINDEX:
3454 ppc_frsp (code, ins->sreg1, ins->sreg1);
3455 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3457 case OP_STORER8_MEMINDEX:
3458 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3461 case CEE_CONV_R4: /* FIXME: change precision */
3463 g_assert_not_reached ();
3464 case OP_FCONV_TO_I1:
3465 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3467 case OP_FCONV_TO_U1:
3468 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3470 case OP_FCONV_TO_I2:
3471 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3473 case OP_FCONV_TO_U2:
3474 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3476 case OP_FCONV_TO_I4:
3478 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3480 case OP_FCONV_TO_U4:
3482 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3484 case OP_FCONV_TO_I8:
3485 case OP_FCONV_TO_U8:
3486 g_assert_not_reached ();
3487 /* Implemented as helper calls */
3489 case OP_LCONV_TO_R_UN:
3490 g_assert_not_reached ();
3491 /* Implemented as helper calls */
3493 case OP_LCONV_TO_OVF_I4_2:
3494 case OP_LCONV_TO_OVF_I: {
3495 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3496 // Check if its negative
3497 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3498 negative_branch = code;
3499 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3500 // Its positive msword == 0
3501 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3502 msword_positive_branch = code;
3503 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3505 ovf_ex_target = code;
3506 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3508 ppc_patch (negative_branch, code);
3509 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3510 msword_negative_branch = code;
3511 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3512 ppc_patch (msword_negative_branch, ovf_ex_target);
3514 ppc_patch (msword_positive_branch, code);
3515 if (ins->dreg != ins->sreg1)
3516 ppc_mr (code, ins->dreg, ins->sreg1);
3520 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3523 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3526 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3529 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3532 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3535 ppc_fneg (code, ins->dreg, ins->sreg1);
3539 g_assert_not_reached ();
3542 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3545 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3546 ppc_li (code, ins->dreg, 0);
3547 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3548 ppc_li (code, ins->dreg, 1);
3551 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3552 ppc_li (code, ins->dreg, 1);
3553 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3554 ppc_li (code, ins->dreg, 0);
3557 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3558 ppc_li (code, ins->dreg, 1);
3559 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3560 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3561 ppc_li (code, ins->dreg, 0);
3564 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3565 ppc_li (code, ins->dreg, 1);
3566 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3567 ppc_li (code, ins->dreg, 0);
3570 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3571 ppc_li (code, ins->dreg, 1);
3572 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3573 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3574 ppc_li (code, ins->dreg, 0);
3577 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3580 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3583 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3584 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3587 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3588 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3591 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3592 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3595 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3596 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3599 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3600 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3603 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3606 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3607 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3610 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3613 g_assert_not_reached ();
3614 case OP_CHECK_FINITE: {
3615 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3616 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3617 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3618 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3621 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3622 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3626 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3627 g_assert_not_reached ();
3630 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3631 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3632 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3633 g_assert_not_reached ();
3639 last_offset = offset;
3642 cfg->code_len = code - cfg->native_code;
3646 mono_arch_register_lowlevel_calls (void)
3650 #define patch_lis_ori(ip,val) do {\
3651 guint16 *__lis_ori = (guint16*)(ip); \
3652 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3653 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3657 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3659 MonoJumpInfo *patch_info;
3661 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3662 unsigned char *ip = patch_info->ip.i + code;
3663 unsigned char *target;
3665 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3667 switch (patch_info->type) {
3668 case MONO_PATCH_INFO_IP:
3669 patch_lis_ori (ip, ip);
3671 case MONO_PATCH_INFO_METHOD_REL:
3672 g_assert_not_reached ();
3673 *((gpointer *)(ip)) = code + patch_info->data.offset;
3675 case MONO_PATCH_INFO_SWITCH: {
3676 gpointer *table = (gpointer *)patch_info->data.table->table;
3679 patch_lis_ori (ip, table);
3681 for (i = 0; i < patch_info->data.table->table_size; i++) {
3682 table [i] = (int)patch_info->data.table->table [i] + code;
3684 /* we put into the table the absolute address, no need for ppc_patch in this case */
3687 case MONO_PATCH_INFO_METHODCONST:
3688 case MONO_PATCH_INFO_CLASS:
3689 case MONO_PATCH_INFO_IMAGE:
3690 case MONO_PATCH_INFO_FIELD:
3691 case MONO_PATCH_INFO_VTABLE:
3692 case MONO_PATCH_INFO_IID:
3693 case MONO_PATCH_INFO_SFLDA:
3694 case MONO_PATCH_INFO_LDSTR:
3695 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3696 case MONO_PATCH_INFO_LDTOKEN:
3697 /* from OP_AOTCONST : lis + ori */
3698 patch_lis_ori (ip, target);
3700 case MONO_PATCH_INFO_R4:
3701 case MONO_PATCH_INFO_R8:
3702 g_assert_not_reached ();
3703 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3705 case MONO_PATCH_INFO_EXC_NAME:
3706 g_assert_not_reached ();
3707 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3709 case MONO_PATCH_INFO_NONE:
3710 case MONO_PATCH_INFO_BB_OVF:
3711 case MONO_PATCH_INFO_EXC_OVF:
3712 /* everything is dealt with at epilog output time */
3717 ppc_patch (ip, target);
3722 * Stack frame layout:
3724 * ------------------- sp
3725 * MonoLMF structure or saved registers
3726 * -------------------
3728 * -------------------
3730 * -------------------
3731 * optional 8 bytes for tracing
3732 * -------------------
3733 * param area size is cfg->param_area
3734 * -------------------
3735 * linkage area size is PPC_STACK_PARAM_OFFSET
3736 * ------------------- sp
3740 mono_arch_emit_prolog (MonoCompile *cfg)
3742 MonoMethod *method = cfg->method;
3744 MonoMethodSignature *sig;
3746 int alloc_size, pos, max_offset, i;
3752 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3755 sig = mono_method_signature (method);
3756 cfg->code_size = 256 + sig->param_count * 20;
3757 code = cfg->native_code = g_malloc (cfg->code_size);
3759 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3760 ppc_mflr (code, ppc_r0);
3761 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3764 alloc_size = cfg->stack_offset;
3767 if (!method->save_lmf) {
3768 /*for (i = 31; i >= 14; --i) {
3769 if (cfg->used_float_regs & (1 << i)) {
3770 pos += sizeof (gdouble);
3771 ppc_stfd (code, i, -pos, ppc_sp);
3774 for (i = 31; i >= 13; --i) {
3775 if (cfg->used_int_regs & (1 << i)) {
3776 pos += sizeof (gulong);
3777 ppc_stw (code, i, -pos, ppc_sp);
3782 pos += sizeof (MonoLMF);
3784 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3785 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3786 for (i = 14; i < 32; i++) {
3787 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3791 // align to PPC_STACK_ALIGNMENT bytes
3792 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3793 alloc_size += PPC_STACK_ALIGNMENT - 1;
3794 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3797 cfg->stack_usage = alloc_size;
3798 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3800 if (ppc_is_imm16 (-alloc_size)) {
3801 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3803 ppc_load (code, ppc_r11, -alloc_size);
3804 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3807 if (cfg->frame_reg != ppc_sp)
3808 ppc_mr (code, cfg->frame_reg, ppc_sp);
3810 /* compute max_offset in order to use short forward jumps
3811 * we always do it on ppc because the immediate displacement
3812 * for jumps is too small
3815 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3817 bb->max_offset = max_offset;
3819 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3822 MONO_BB_FOR_EACH_INS (bb, ins)
3823 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3826 /* load arguments allocated to register from the stack */
3829 cinfo = calculate_sizes (sig, sig->pinvoke);
3831 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3832 ArgInfo *ainfo = &cinfo->ret;
3835 inst = cfg->vret_addr;
3840 if (ppc_is_imm16 (inst->inst_offset)) {
3841 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3843 ppc_load (code, ppc_r11, inst->inst_offset);
3844 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3847 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3848 ArgInfo *ainfo = cinfo->args + i;
3849 inst = cfg->args [pos];
3851 if (cfg->verbose_level > 2)
3852 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3853 if (inst->opcode == OP_REGVAR) {
3854 if (ainfo->regtype == RegTypeGeneral)
3855 ppc_mr (code, inst->dreg, ainfo->reg);
3856 else if (ainfo->regtype == RegTypeFP)
3857 ppc_fmr (code, inst->dreg, ainfo->reg);
3858 else if (ainfo->regtype == RegTypeBase) {
3859 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3860 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3862 g_assert_not_reached ();
3864 if (cfg->verbose_level > 2)
3865 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3867 /* the argument should be put on the stack: FIXME handle size != word */
3868 if (ainfo->regtype == RegTypeGeneral) {
3869 switch (ainfo->size) {
3871 if (ppc_is_imm16 (inst->inst_offset)) {
3872 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3874 ppc_load (code, ppc_r11, inst->inst_offset);
3875 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3879 if (ppc_is_imm16 (inst->inst_offset)) {
3880 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3882 ppc_load (code, ppc_r11, inst->inst_offset);
3883 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3887 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3888 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3889 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3891 ppc_load (code, ppc_r11, inst->inst_offset);
3892 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3893 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3894 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3898 if (ppc_is_imm16 (inst->inst_offset)) {
3899 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3901 ppc_load (code, ppc_r11, inst->inst_offset);
3902 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3906 } else if (ainfo->regtype == RegTypeBase) {
3907 /* load the previous stack pointer in r11 */
3908 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3909 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3910 switch (ainfo->size) {
3912 if (ppc_is_imm16 (inst->inst_offset)) {
3913 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3915 ppc_load (code, ppc_r11, inst->inst_offset);
3916 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3920 if (ppc_is_imm16 (inst->inst_offset)) {
3921 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3923 ppc_load (code, ppc_r11, inst->inst_offset);
3924 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3928 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3929 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3930 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3931 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3934 g_assert_not_reached ();
3938 if (ppc_is_imm16 (inst->inst_offset)) {
3939 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3941 ppc_load (code, ppc_r11, inst->inst_offset);
3942 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3946 } else if (ainfo->regtype == RegTypeFP) {
3947 g_assert (ppc_is_imm16 (inst->inst_offset));
3948 if (ainfo->size == 8)
3949 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3950 else if (ainfo->size == 4)
3951 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3953 g_assert_not_reached ();
3954 } else if (ainfo->regtype == RegTypeStructByVal) {
3955 int doffset = inst->inst_offset;
3959 g_assert (ppc_is_imm16 (inst->inst_offset));
3960 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3961 /* FIXME: what if there is no class? */
3962 if (mono_class_from_mono_type (inst->inst_vtype))
3963 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3964 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3966 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3967 register. Should this case include linux/ppc?
3971 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3973 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3976 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3977 soffset += sizeof (gpointer);
3978 doffset += sizeof (gpointer);
3980 if (ainfo->vtsize) {
3981 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3982 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3983 if ((size & 3) != 0) {
3984 code = emit_memcpy (code, size - soffset,
3985 inst->inst_basereg, doffset,
3986 ppc_r11, ainfo->offset + soffset);
3988 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
3989 inst->inst_basereg, doffset,
3990 ppc_r11, ainfo->offset + soffset);
3993 } else if (ainfo->regtype == RegTypeStructByAddr) {
3994 /* if it was originally a RegTypeBase */
3995 if (ainfo->offset) {
3996 /* load the previous stack pointer in r11 */
3997 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3998 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4000 ppc_mr (code, ppc_r11, ainfo->reg);
4002 g_assert (ppc_is_imm16 (inst->inst_offset));
4003 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4004 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4006 g_assert_not_reached ();
4011 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4012 ppc_load (code, ppc_r3, cfg->domain);
4013 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4014 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4015 ppc_lis (code, ppc_r0, 0);
4016 ppc_ori (code, ppc_r0, ppc_r0, 0);
4017 ppc_mtlr (code, ppc_r0);
4024 if (method->save_lmf) {
4025 if (lmf_pthread_key != -1) {
4026 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4027 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4028 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4030 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4031 (gpointer)"mono_get_lmf_addr");
4032 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4033 ppc_lis (code, ppc_r0, 0);
4034 ppc_ori (code, ppc_r0, ppc_r0, 0);
4035 ppc_mtlr (code, ppc_r0);
4041 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4042 /* lmf_offset is the offset from the previous stack pointer,
4043 * alloc_size is the total stack space allocated, so the offset
4044 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4045 * The pointer to the struct is put in ppc_r11 (new_lmf).
4046 * The callee-saved registers are already in the MonoLMF structure
4048 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4049 /* ppc_r3 is the result from mono_get_lmf_addr () */
4050 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4051 /* new_lmf->previous_lmf = *lmf_addr */
4052 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4053 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4054 /* *(lmf_addr) = r11 */
4055 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4056 /* save method info */
4057 ppc_load (code, ppc_r0, method);
4058 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4059 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4060 /* save the current IP */
4061 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4062 ppc_load (code, ppc_r0, 0x01010101);
4063 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4067 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4069 cfg->code_len = code - cfg->native_code;
4070 g_assert (cfg->code_len < cfg->code_size);
4077 mono_arch_emit_epilog (MonoCompile *cfg)
4079 MonoJumpInfo *patch_info;
4080 MonoMethod *method = cfg->method;
4082 int max_epilog_size = 16 + 20*4;
4085 if (cfg->method->save_lmf)
4086 max_epilog_size += 128;
4088 if (mono_jit_trace_calls != NULL)
4089 max_epilog_size += 50;
4091 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4092 max_epilog_size += 50;
4094 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4095 cfg->code_size *= 2;
4096 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4097 mono_jit_stats.code_reallocs++;
4101 * Keep in sync with OP_JMP
4103 code = cfg->native_code + cfg->code_len;
4105 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4106 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4110 if (method->save_lmf) {
4112 pos += sizeof (MonoLMF);
4114 /* save the frame reg in r8 */
4115 ppc_mr (code, ppc_r8, cfg->frame_reg);
4116 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4117 /* r5 = previous_lmf */
4118 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4120 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4121 /* *(lmf_addr) = previous_lmf */
4122 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4123 /* FIXME: speedup: there is no actual need to restore the registers if
4124 * we didn't actually change them (idea from Zoltan).
4127 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4129 /*for (i = 14; i < 32; i++) {
4130 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4132 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4133 /* use the saved copy of the frame reg in r8 */
4134 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4135 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4136 ppc_mtlr (code, ppc_r0);
4138 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4140 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4141 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4142 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4144 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4145 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4147 ppc_mtlr (code, ppc_r0);
4149 if (ppc_is_imm16 (cfg->stack_usage)) {
4150 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4152 ppc_load (code, ppc_r11, cfg->stack_usage);
4153 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4156 /*for (i = 31; i >= 14; --i) {
4157 if (cfg->used_float_regs & (1 << i)) {
4158 pos += sizeof (double);
4159 ppc_lfd (code, i, -pos, ppc_sp);
4162 for (i = 31; i >= 13; --i) {
4163 if (cfg->used_int_regs & (1 << i)) {
4164 pos += sizeof (gulong);
4165 ppc_lwz (code, i, -pos, ppc_sp);
4171 cfg->code_len = code - cfg->native_code;
4173 g_assert (cfg->code_len < cfg->code_size);
4177 /* remove once throw_exception_by_name is eliminated */
4179 exception_id_by_name (const char *name)
4181 if (strcmp (name, "IndexOutOfRangeException") == 0)
4182 return MONO_EXC_INDEX_OUT_OF_RANGE;
4183 if (strcmp (name, "OverflowException") == 0)
4184 return MONO_EXC_OVERFLOW;
4185 if (strcmp (name, "ArithmeticException") == 0)
4186 return MONO_EXC_ARITHMETIC;
4187 if (strcmp (name, "DivideByZeroException") == 0)
4188 return MONO_EXC_DIVIDE_BY_ZERO;
4189 if (strcmp (name, "InvalidCastException") == 0)
4190 return MONO_EXC_INVALID_CAST;
4191 if (strcmp (name, "NullReferenceException") == 0)
4192 return MONO_EXC_NULL_REF;
4193 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4194 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4195 g_error ("Unknown intrinsic exception %s\n", name);
4200 mono_arch_emit_exceptions (MonoCompile *cfg)
4202 MonoJumpInfo *patch_info;
4205 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4206 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4207 int max_epilog_size = 50;
4209 /* count the number of exception infos */
4212 * make sure we have enough space for exceptions
4213 * 24 is the simulated call to throw_exception_by_name
4215 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4216 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4217 i = exception_id_by_name (patch_info->data.target);
4218 if (!exc_throw_found [i]) {
4219 max_epilog_size += 24;
4220 exc_throw_found [i] = TRUE;
4222 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4223 max_epilog_size += 12;
4224 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4225 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4226 i = exception_id_by_name (ovfj->data.exception);
4227 if (!exc_throw_found [i]) {
4228 max_epilog_size += 24;
4229 exc_throw_found [i] = TRUE;
4231 max_epilog_size += 8;
4235 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4236 cfg->code_size *= 2;
4237 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4238 mono_jit_stats.code_reallocs++;
4241 code = cfg->native_code + cfg->code_len;
4243 /* add code to raise exceptions */
4244 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4245 switch (patch_info->type) {
4246 case MONO_PATCH_INFO_BB_OVF: {
4247 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4248 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4249 /* patch the initial jump */
4250 ppc_patch (ip, code);
4251 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4253 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4254 /* jump back to the true target */
4256 ip = ovfj->data.bb->native_offset + cfg->native_code;
4257 ppc_patch (code - 4, ip);
4260 case MONO_PATCH_INFO_EXC_OVF: {
4261 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4262 MonoJumpInfo *newji;
4263 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4264 unsigned char *bcl = code;
4265 /* patch the initial jump: we arrived here with a call */
4266 ppc_patch (ip, code);
4267 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4269 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4270 /* patch the conditional jump to the right handler */
4271 /* make it processed next */
4272 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4273 newji->type = MONO_PATCH_INFO_EXC;
4274 newji->ip.i = bcl - cfg->native_code;
4275 newji->data.target = ovfj->data.exception;
4276 newji->next = patch_info->next;
4277 patch_info->next = newji;
4280 case MONO_PATCH_INFO_EXC: {
4281 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4282 i = exception_id_by_name (patch_info->data.target);
4283 if (exc_throw_pos [i]) {
4284 ppc_patch (ip, exc_throw_pos [i]);
4285 patch_info->type = MONO_PATCH_INFO_NONE;
4288 exc_throw_pos [i] = code;
4290 ppc_patch (ip, code);
4291 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4292 ppc_load (code, ppc_r3, patch_info->data.target);
4293 /* we got here from a conditional call, so the calling ip is set in lr already */
4294 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4295 patch_info->data.name = "mono_arch_throw_exception_by_name";
4296 patch_info->ip.i = code - cfg->native_code;
4297 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4298 ppc_lis (code, ppc_r0, 0);
4299 ppc_ori (code, ppc_r0, ppc_r0, 0);
4300 ppc_mtctr (code, ppc_r0);
4301 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4313 cfg->code_len = code - cfg->native_code;
4315 g_assert (cfg->code_len < cfg->code_size);
4320 try_offset_access (void *value, guint32 idx)
4322 register void* me __asm__ ("r2");
4323 void ***p = (void***)((char*)me + 284);
4324 int idx1 = idx / 32;
4325 int idx2 = idx % 32;
4328 if (value != p[idx1][idx2])
4334 setup_tls_access (void)
4337 guint32 *ins, *code;
4338 guint32 cmplwi_1023, li_0x48, blr_ins;
4339 if (tls_mode == TLS_MODE_FAILED)
4342 if (g_getenv ("MONO_NO_TLS")) {
4343 tls_mode = TLS_MODE_FAILED;
4347 if (tls_mode == TLS_MODE_DETECT) {
4348 ins = (guint32*)pthread_getspecific;
4349 /* uncond branch to the real method */
4350 if ((*ins >> 26) == 18) {
4352 val = (*ins & ~3) << 6;
4356 ins = (guint32*)val;
4358 ins = (guint32*) ((char*)ins + val);
4361 code = &cmplwi_1023;
4362 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4364 ppc_li (code, ppc_r4, 0x48);
4367 if (*ins == cmplwi_1023) {
4368 int found_lwz_284 = 0;
4369 for (ptk = 0; ptk < 20; ++ptk) {
4371 if (!*ins || *ins == blr_ins)
4373 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4378 if (!found_lwz_284) {
4379 tls_mode = TLS_MODE_FAILED;
4382 tls_mode = TLS_MODE_LTHREADS;
4383 } else if (*ins == li_0x48) {
4385 /* uncond branch to the real method */
4386 if ((*ins >> 26) == 18) {
4388 val = (*ins & ~3) << 6;
4392 ins = (guint32*)val;
4394 ins = (guint32*) ((char*)ins + val);
4396 code = (guint32*)&val;
4397 ppc_li (code, ppc_r0, 0x7FF2);
4398 if (ins [1] == val) {
4399 /* Darwin on G4, implement */
4400 tls_mode = TLS_MODE_FAILED;
4403 code = (guint32*)&val;
4404 ppc_mfspr (code, ppc_r3, 104);
4405 if (ins [1] != val) {
4406 tls_mode = TLS_MODE_FAILED;
4409 tls_mode = TLS_MODE_DARWIN_G5;
4412 tls_mode = TLS_MODE_FAILED;
4416 tls_mode = TLS_MODE_FAILED;
4420 if (monodomain_key == -1) {
4421 ptk = mono_domain_get_tls_key ();
4423 ptk = mono_pthread_key_for_tls (ptk);
4425 monodomain_key = ptk;
4429 if (lmf_pthread_key == -1) {
4430 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4432 /*g_print ("MonoLMF at: %d\n", ptk);*/
4433 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4434 init_tls_failed = 1;
4437 lmf_pthread_key = ptk;
4440 if (monothread_key == -1) {
4441 ptk = mono_thread_get_tls_key ();
4443 ptk = mono_pthread_key_for_tls (ptk);
4445 monothread_key = ptk;
4446 /*g_print ("thread inited: %d\n", ptk);*/
4449 /*g_print ("thread not inited yet %d\n", ptk);*/
4455 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4457 setup_tls_access ();
4461 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4466 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4468 int this_dreg = ppc_r3;
4473 /* add the this argument */
4474 if (this_reg != -1) {
4476 MONO_INST_NEW (cfg, this, OP_MOVE);
4477 this->type = this_type;
4478 this->sreg1 = this_reg;
4479 this->dreg = mono_regstate_next_int (cfg->rs);
4480 mono_bblock_add_inst (cfg->cbb, this);
4481 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4486 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4487 vtarg->type = STACK_MP;
4488 vtarg->sreg1 = vt_reg;
4489 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4490 mono_bblock_add_inst (cfg->cbb, vtarg);
4491 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4495 #ifdef MONO_ARCH_HAVE_IMT
4499 #define JUMP_IMM_SIZE 12
4500 #define ENABLE_WRONG_METHOD_CHECK 0
4503 * LOCKING: called with the domain lock held
4506 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4510 guint8 *code, *start;
4512 for (i = 0; i < count; ++i) {
4513 MonoIMTCheckItem *item = imt_entries [i];
4514 if (item->is_equals) {
4515 if (item->check_target_idx) {
4516 if (!item->compare_done)
4517 item->chunk_size += CMP_SIZE;
4518 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4520 item->chunk_size += JUMP_IMM_SIZE;
4521 #if ENABLE_WRONG_METHOD_CHECK
4522 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4526 item->chunk_size += CMP_SIZE + BR_SIZE;
4527 imt_entries [item->check_target_idx]->compare_done = TRUE;
4529 size += item->chunk_size;
4531 /* the initial load of the vtable address */
4533 code = mono_code_manager_reserve (domain->code_mp, size);
4535 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4536 for (i = 0; i < count; ++i) {
4537 MonoIMTCheckItem *item = imt_entries [i];
4538 item->code_target = code;
4539 if (item->is_equals) {
4540 if (item->check_target_idx) {
4541 if (!item->compare_done) {
4542 ppc_load (code, ppc_r0, (guint32)item->method);
4543 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4545 item->jmp_code = code;
4546 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4547 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4548 ppc_mtctr (code, ppc_r0);
4549 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4551 /* enable the commented code to assert on wrong method */
4552 #if ENABLE_WRONG_METHOD_CHECK
4553 ppc_load (code, ppc_r0, (guint32)item->method);
4554 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4555 item->jmp_code = code;
4556 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4558 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4559 ppc_mtctr (code, ppc_r0);
4560 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4561 #if ENABLE_WRONG_METHOD_CHECK
4562 ppc_patch (item->jmp_code, code);
4564 item->jmp_code = NULL;
4568 ppc_load (code, ppc_r0, (guint32)item->method);
4569 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4570 item->jmp_code = code;
4571 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4574 /* patch the branches to get to the target items */
4575 for (i = 0; i < count; ++i) {
4576 MonoIMTCheckItem *item = imt_entries [i];
4577 if (item->jmp_code) {
4578 if (item->check_target_idx) {
4579 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4584 mono_stats.imt_thunks_size += code - start;
4585 g_assert (code - start <= size);
4586 mono_arch_flush_icache (start, size);
4591 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4593 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4597 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4599 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4604 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4606 MonoInst *ins = NULL;
4608 /*if (cmethod->klass == mono_defaults.math_class) {
4609 if (strcmp (cmethod->name, "Sqrt") == 0) {
4610 MONO_INST_NEW (cfg, ins, OP_SQRT);
4611 ins->inst_i0 = args [0];
4618 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4625 mono_arch_print_tree (MonoInst *tree, int arity)
4630 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4634 setup_tls_access ();
4635 if (monodomain_key == -1)
4638 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4639 ins->inst_offset = monodomain_key;
4644 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4648 setup_tls_access ();
4649 if (monothread_key == -1)
4652 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4653 ins->inst_offset = monothread_key;
4658 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4660 /* FIXME: implement */
4661 g_assert_not_reached ();