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>
24 #define FORCE_INDIR_CALL 1
35 /* This mutex protects architecture specific caches */
36 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
37 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
38 static CRITICAL_SECTION mini_arch_mutex;
40 int mono_exc_esp_offset = 0;
41 static int tls_mode = TLS_MODE_DETECT;
42 static int lmf_pthread_key = -1;
43 static int monothread_key = -1;
44 static int monodomain_key = -1;
47 offsets_from_pthread_key (guint32 key, int *offset2)
51 *offset2 = idx2 * sizeof (gpointer);
52 return 284 + idx1 * sizeof (gpointer);
55 #define emit_linuxthreads_tls(code,dreg,key) do {\
57 off1 = offsets_from_pthread_key ((key), &off2); \
58 ppc_lwz ((code), (dreg), off1, ppc_r2); \
59 ppc_lwz ((code), (dreg), off2, (dreg)); \
62 #define emit_darwing5_tls(code,dreg,key) do {\
63 int off1 = 0x48 + key * sizeof (gpointer); \
64 ppc_mfspr ((code), (dreg), 104); \
65 ppc_lwz ((code), (dreg), off1, (dreg)); \
68 /* FIXME: ensure the sc call preserves all but r3 */
69 #define emit_darwing4_tls(code,dreg,key) do {\
70 int off1 = 0x48 + key * sizeof (gpointer); \
71 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
72 ppc_li ((code), ppc_r0, 0x7FF2); \
74 ppc_lwz ((code), (dreg), off1, ppc_r3); \
75 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
78 #define emit_tls_access(code,dreg,key) do { \
80 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
81 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
82 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
83 default: g_assert_not_reached (); \
88 mono_arch_regname (int reg) {
89 static const char rnames[][4] = {
90 "r0", "sp", "r2", "r3", "r4",
91 "r5", "r6", "r7", "r8", "r9",
92 "r10", "r11", "r12", "r13", "r14",
93 "r15", "r16", "r17", "r18", "r19",
94 "r20", "r21", "r22", "r23", "r24",
95 "r25", "r26", "r27", "r28", "r29",
98 if (reg >= 0 && reg < 32)
104 mono_arch_fregname (int reg) {
105 static const char rnames[][4] = {
106 "f0", "f1", "f2", "f3", "f4",
107 "f5", "f6", "f7", "f8", "f9",
108 "f10", "f11", "f12", "f13", "f14",
109 "f15", "f16", "f17", "f18", "f19",
110 "f20", "f21", "f22", "f23", "f24",
111 "f25", "f26", "f27", "f28", "f29",
114 if (reg >= 0 && reg < 32)
119 /* this function overwrites r0, r11, r12 */
121 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
123 /* unrolled, use the counter in big */
124 if (size > sizeof (gpointer) * 5) {
125 int shifted = size >> 2;
126 guint8 *copy_loop_start, *copy_loop_jump;
128 ppc_load (code, ppc_r0, shifted);
129 ppc_mtctr (code, ppc_r0);
130 g_assert (sreg == ppc_r11);
131 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
132 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
133 copy_loop_start = code;
134 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
135 ppc_stwu (code, ppc_r0, 4, ppc_r12);
136 copy_loop_jump = code;
137 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
138 ppc_patch (copy_loop_jump, copy_loop_start);
140 doffset = soffset = 0;
144 ppc_lwz (code, ppc_r0, soffset, sreg);
145 ppc_stw (code, ppc_r0, doffset, dreg);
151 ppc_lhz (code, ppc_r0, soffset, sreg);
152 ppc_sth (code, ppc_r0, doffset, dreg);
158 ppc_lbz (code, ppc_r0, soffset, sreg);
159 ppc_stb (code, ppc_r0, doffset, dreg);
168 * mono_arch_get_argument_info:
169 * @csig: a method signature
170 * @param_count: the number of parameters to consider
171 * @arg_info: an array to store the result infos
173 * Gathers information on parameters such as size, alignment and
174 * padding. arg_info should be large enought to hold param_count + 1 entries.
176 * Returns the size of the activation frame.
179 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
181 int k, frame_size = 0;
182 int size, align, pad;
185 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
186 frame_size += sizeof (gpointer);
190 arg_info [0].offset = offset;
193 frame_size += sizeof (gpointer);
197 arg_info [0].size = frame_size;
199 for (k = 0; k < param_count; k++) {
202 size = mono_type_native_stack_size (csig->params [k], &align);
204 size = mini_type_stack_size (NULL, csig->params [k], &align);
206 /* ignore alignment for now */
209 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
210 arg_info [k].pad = pad;
212 arg_info [k + 1].pad = 0;
213 arg_info [k + 1].size = size;
215 arg_info [k + 1].offset = offset;
219 align = MONO_ARCH_FRAME_ALIGNMENT;
220 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
221 arg_info [k].pad = pad;
227 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
231 guint32* code = (guint32*)code_ptr;
235 /* This is the 'blrl' instruction */
238 /* Sanity check: instruction must be 'blrl' */
239 if (*code != 0x4e800021)
242 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
243 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
247 /* OK, we're now at the 'blrl' instruction. Now walk backwards
248 till we get to a 'mtlr rA' */
250 if((*code & 0x7c0803a6) == 0x7c0803a6) {
252 /* Here we are: we reached the 'mtlr rA'.
253 Extract the register from the instruction */
254 reg = (*code & 0x03e00000) >> 21;
256 /* ok, this is a lwz reg, offset (vtreg)
257 * it is emitted with:
258 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
260 soff = (*code & 0xffff);
262 reg = (*code >> 16) & 0x1f;
263 g_assert (reg != ppc_r1);
264 /*g_print ("patching reg is %d\n", reg);*/
266 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
267 /* saved in the MonoLMF structure */
268 o = (gpointer)lmf->iregs [reg - 13];
275 *displacement = offset;
280 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
284 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
287 return (gpointer*)((char*)vt + displacement);
290 #define MAX_ARCH_DELEGATE_PARAMS 7
293 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
295 guint8 *code, *start;
297 /* FIXME: Support more cases */
298 if (MONO_TYPE_ISSTRUCT (sig->ret))
302 static guint8* cached = NULL;
303 mono_mini_arch_lock ();
305 mono_mini_arch_unlock ();
309 start = code = mono_global_codeman_reserve (16);
311 /* Replace the this argument with the target */
312 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
313 ppc_mtctr (code, ppc_r0);
314 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
315 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
317 g_assert ((code - start) <= 16);
319 mono_arch_flush_icache (start, 16);
321 mono_mini_arch_unlock ();
324 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
327 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
329 for (i = 0; i < sig->param_count; ++i)
330 if (!mono_is_regsize_var (sig->params [i]))
333 mono_mini_arch_lock ();
334 code = cache [sig->param_count];
336 mono_mini_arch_unlock ();
340 size = 12 + sig->param_count * 4;
341 start = code = mono_global_codeman_reserve (size);
343 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
344 ppc_mtctr (code, ppc_r0);
345 /* slide down the arguments */
346 for (i = 0; i < sig->param_count; ++i) {
347 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
349 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
351 g_assert ((code - start) <= size);
353 mono_arch_flush_icache (start, size);
354 cache [sig->param_count] = start;
355 mono_mini_arch_unlock ();
362 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
364 /* FIXME: handle returning a struct */
365 if (MONO_TYPE_ISSTRUCT (sig->ret))
366 return (gpointer)regs [ppc_r4];
367 return (gpointer)regs [ppc_r3];
371 * Initialize the cpu to execute managed code.
374 mono_arch_cpu_init (void)
379 * Initialize architecture specific code.
382 mono_arch_init (void)
384 InitializeCriticalSection (&mini_arch_mutex);
388 * Cleanup architecture specific code.
391 mono_arch_cleanup (void)
393 DeleteCriticalSection (&mini_arch_mutex);
397 * This function returns the optimizations supported on this cpu.
400 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
404 /* no ppc-specific optimizations yet */
410 is_regsize_var (MonoType *t) {
413 t = mono_type_get_underlying_type (t);
420 case MONO_TYPE_FNPTR:
422 case MONO_TYPE_OBJECT:
423 case MONO_TYPE_STRING:
424 case MONO_TYPE_CLASS:
425 case MONO_TYPE_SZARRAY:
426 case MONO_TYPE_ARRAY:
428 case MONO_TYPE_GENERICINST:
429 if (!mono_type_generic_inst_is_valuetype (t))
432 case MONO_TYPE_VALUETYPE:
439 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
444 for (i = 0; i < cfg->num_varinfo; i++) {
445 MonoInst *ins = cfg->varinfo [i];
446 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
449 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
452 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
455 /* we can only allocate 32 bit values */
456 if (is_regsize_var (ins->inst_vtype)) {
457 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
458 g_assert (i == vmv->idx);
459 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
467 mono_arch_get_global_int_regs (MonoCompile *cfg)
471 if (cfg->frame_reg != ppc_sp)
473 /* ppc_r13 is used by the system on PPC EABI */
474 for (i = 14; i < top; ++i)
475 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
481 * mono_arch_regalloc_cost:
483 * Return the cost, in number of memory references, of the action of
484 * allocating the variable VMV into a register during global register
488 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
500 mono_arch_flush_icache (guint8 *code, gint size)
502 guint8 *p, *endp, *start;
503 static int cachelinesize = 0;
504 static int cachelineinc = 16;
506 if (!cachelinesize) {
510 mib [1] = HW_CACHELINE;
511 len = sizeof (cachelinesize);
512 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
516 cachelineinc = cachelinesize;
517 /*g_print ("setting cl size to %d\n", cachelinesize);*/
519 #elif defined(__linux__)
520 /* sadly this will work only with 2.6 kernels... */
521 FILE* f = fopen ("/proc/self/auxv", "rb");
524 while (fread (&vec, sizeof (vec), 1, f) == 1) {
525 if (vec.type == 19) {
526 cachelinesize = vec.value;
535 #warning Need a way to get cache line size
541 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
542 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
544 for (p = start; p < endp; p += cachelineinc) {
545 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
548 for (p = start; p < endp; p += cachelineinc) {
549 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
554 for (p = start; p < endp; p += cachelineinc) {
555 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
562 #define ALWAYS_ON_STACK(s) s
563 #define FP_ALSO_IN_REG(s) s
565 #define ALWAYS_ON_STACK(s)
566 #define FP_ALSO_IN_REG(s)
567 #define ALIGN_DOUBLES
580 guint32 vtsize; /* in param area */
582 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
583 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
598 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
601 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
602 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
603 ainfo->reg = ppc_sp; /* in the caller */
604 ainfo->regtype = RegTypeBase;
607 ALWAYS_ON_STACK (*stack_size += 4);
611 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
613 //*stack_size += (*stack_size % 8);
615 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
616 ainfo->reg = ppc_sp; /* in the caller */
617 ainfo->regtype = RegTypeBase;
624 ALWAYS_ON_STACK (*stack_size += 8);
633 /* size == 4 is checked already */
635 has_only_a_r4_field (MonoClass *klass)
640 while ((f = mono_class_get_fields (klass, &iter))) {
641 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
642 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
652 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
655 int n = sig->hasthis + sig->param_count;
657 guint32 stack_size = 0;
658 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
660 fr = PPC_FIRST_FPARG_REG;
661 gr = PPC_FIRST_ARG_REG;
663 /* FIXME: handle returning a struct */
664 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
665 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
666 cinfo->struct_ret = PPC_FIRST_ARG_REG;
671 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
674 DEBUG(printf("params: %d\n", sig->param_count));
675 for (i = 0; i < sig->param_count; ++i) {
676 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
677 /* Prevent implicit arguments and sig_cookie from
678 being passed in registers */
679 gr = PPC_LAST_ARG_REG + 1;
680 /* Emit the signature cookie just before the implicit arguments */
681 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
683 DEBUG(printf("param %d: ", i));
684 if (sig->params [i]->byref) {
685 DEBUG(printf("byref\n"));
686 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
690 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
691 switch (simpletype) {
692 case MONO_TYPE_BOOLEAN:
695 cinfo->args [n].size = 1;
696 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
702 cinfo->args [n].size = 2;
703 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
708 cinfo->args [n].size = 4;
709 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
715 case MONO_TYPE_FNPTR:
716 case MONO_TYPE_CLASS:
717 case MONO_TYPE_OBJECT:
718 case MONO_TYPE_STRING:
719 case MONO_TYPE_SZARRAY:
720 case MONO_TYPE_ARRAY:
721 cinfo->args [n].size = sizeof (gpointer);
722 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
725 case MONO_TYPE_GENERICINST:
726 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
727 cinfo->args [n].size = sizeof (gpointer);
728 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
733 case MONO_TYPE_VALUETYPE: {
736 klass = mono_class_from_mono_type (sig->params [i]);
738 size = mono_class_native_size (klass, NULL);
740 size = mono_class_value_size (klass, NULL);
742 if (size == 4 && has_only_a_r4_field (klass)) {
743 cinfo->args [n].size = 4;
745 /* It was 7, now it is 8 in LinuxPPC */
746 if (fr <= PPC_LAST_FPARG_REG) {
747 cinfo->args [n].regtype = RegTypeFP;
748 cinfo->args [n].reg = fr;
750 FP_ALSO_IN_REG (gr ++);
751 ALWAYS_ON_STACK (stack_size += 4);
753 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
754 cinfo->args [n].regtype = RegTypeBase;
755 cinfo->args [n].reg = ppc_sp; /* in the caller*/
762 DEBUG(printf ("load %d bytes struct\n",
763 mono_class_native_size (sig->params [i]->data.klass, NULL)));
764 #if PPC_PASS_STRUCTS_BY_VALUE
766 int align_size = size;
768 align_size += (sizeof (gpointer) - 1);
769 align_size &= ~(sizeof (gpointer) - 1);
770 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
771 cinfo->args [n].regtype = RegTypeStructByVal;
772 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
773 cinfo->args [n].size = 0;
774 cinfo->args [n].vtsize = nwords;
776 int rest = PPC_LAST_ARG_REG - gr + 1;
777 int n_in_regs = rest >= nwords? nwords: rest;
778 cinfo->args [n].size = n_in_regs;
779 cinfo->args [n].vtsize = nwords - n_in_regs;
780 cinfo->args [n].reg = gr;
783 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
784 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
785 stack_size += nwords * sizeof (gpointer);
788 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
789 cinfo->args [n].regtype = RegTypeStructByAddr;
790 cinfo->args [n].vtsize = size;
795 case MONO_TYPE_TYPEDBYREF: {
796 int size = sizeof (MonoTypedRef);
797 /* keep in sync or merge with the valuetype case */
798 #if PPC_PASS_STRUCTS_BY_VALUE
800 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
801 cinfo->args [n].regtype = RegTypeStructByVal;
802 if (gr <= PPC_LAST_ARG_REG) {
803 int rest = PPC_LAST_ARG_REG - gr + 1;
804 int n_in_regs = rest >= nwords? nwords: rest;
805 cinfo->args [n].size = n_in_regs;
806 cinfo->args [n].vtsize = nwords - n_in_regs;
807 cinfo->args [n].reg = gr;
810 cinfo->args [n].size = 0;
811 cinfo->args [n].vtsize = nwords;
813 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
814 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
815 stack_size += nwords * sizeof (gpointer);
818 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
819 cinfo->args [n].regtype = RegTypeStructByAddr;
820 cinfo->args [n].vtsize = size;
827 cinfo->args [n].size = 8;
828 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
832 cinfo->args [n].size = 4;
834 /* It was 7, now it is 8 in LinuxPPC */
835 if (fr <= PPC_LAST_FPARG_REG) {
836 cinfo->args [n].regtype = RegTypeFP;
837 cinfo->args [n].reg = fr;
839 FP_ALSO_IN_REG (gr ++);
840 ALWAYS_ON_STACK (stack_size += 4);
842 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
843 cinfo->args [n].regtype = RegTypeBase;
844 cinfo->args [n].reg = ppc_sp; /* in the caller*/
850 cinfo->args [n].size = 8;
851 /* It was 7, now it is 8 in LinuxPPC */
852 if (fr <= PPC_LAST_FPARG_REG) {
853 cinfo->args [n].regtype = RegTypeFP;
854 cinfo->args [n].reg = fr;
856 FP_ALSO_IN_REG (gr += 2);
857 ALWAYS_ON_STACK (stack_size += 8);
859 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
860 cinfo->args [n].regtype = RegTypeBase;
861 cinfo->args [n].reg = ppc_sp; /* in the caller*/
867 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
872 simpletype = mono_type_get_underlying_type (sig->ret)->type;
873 switch (simpletype) {
874 case MONO_TYPE_BOOLEAN:
885 case MONO_TYPE_FNPTR:
886 case MONO_TYPE_CLASS:
887 case MONO_TYPE_OBJECT:
888 case MONO_TYPE_SZARRAY:
889 case MONO_TYPE_ARRAY:
890 case MONO_TYPE_STRING:
891 cinfo->ret.reg = ppc_r3;
895 cinfo->ret.reg = ppc_r3;
899 cinfo->ret.reg = ppc_f1;
900 cinfo->ret.regtype = RegTypeFP;
902 case MONO_TYPE_GENERICINST:
903 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
904 cinfo->ret.reg = ppc_r3;
908 case MONO_TYPE_VALUETYPE:
910 case MONO_TYPE_TYPEDBYREF:
914 g_error ("Can't handle as return value 0x%x", sig->ret->type);
918 /* align stack size to 16 */
919 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
920 stack_size = (stack_size + 15) & ~15;
922 cinfo->stack_usage = stack_size;
928 * Set var information according to the calling convention. ppc version.
929 * The locals var stuff should most likely be split in another method.
932 mono_arch_allocate_vars (MonoCompile *m)
934 MonoMethodSignature *sig;
935 MonoMethodHeader *header;
937 int i, offset, size, align, curinst;
938 int frame_reg = ppc_sp;
940 m->flags |= MONO_CFG_HAS_SPILLUP;
942 /* allow room for the vararg method args: void* and long/double */
943 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
944 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
945 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
946 * call convs needs to be handled this way.
948 if (m->flags & MONO_CFG_HAS_VARARGS)
949 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
950 /* gtk-sharp and other broken code will dllimport vararg functions even with
951 * non-varargs signatures. Since there is little hope people will get this right
952 * we assume they won't.
954 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
955 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
957 header = mono_method_get_header (m->method);
960 * We use the frame register also for any method that has
961 * exception clauses. This way, when the handlers are called,
962 * the code will reference local variables using the frame reg instead of
963 * the stack pointer: if we had to restore the stack pointer, we'd
964 * corrupt the method frames that are already on the stack (since
965 * filters get called before stack unwinding happens) when the filter
966 * code would call any method (this also applies to finally etc.).
968 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
970 m->frame_reg = frame_reg;
971 if (frame_reg != ppc_sp) {
972 m->used_int_regs |= 1 << frame_reg;
975 sig = mono_method_signature (m->method);
979 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
980 m->ret->opcode = OP_REGVAR;
981 m->ret->inst_c0 = ppc_r3;
983 /* FIXME: handle long and FP values */
984 switch (mono_type_get_underlying_type (sig->ret)->type) {
988 m->ret->opcode = OP_REGVAR;
989 m->ret->inst_c0 = ppc_r3;
993 /* local vars are at a positive offset from the stack pointer */
995 * also note that if the function uses alloca, we use ppc_r31
996 * to point at the local variables.
998 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
999 /* align the offset to 16 bytes: not sure this is needed here */
1001 //offset &= ~(16 - 1);
1003 /* add parameter area size for called functions */
1004 offset += m->param_area;
1006 offset &= ~(16 - 1);
1008 /* allow room to save the return value */
1009 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1012 /* the MonoLMF structure is stored just below the stack pointer */
1015 /* this stuff should not be needed on ppc and the new jit,
1016 * because a call on ppc to the handlers doesn't change the
1017 * stack pointer and the jist doesn't manipulate the stack pointer
1018 * for operations involving valuetypes.
1020 /* reserve space to store the esp */
1021 offset += sizeof (gpointer);
1023 /* this is a global constant */
1024 mono_exc_esp_offset = offset;
1026 if (sig->call_convention == MONO_CALL_VARARG) {
1027 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1030 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1032 offset += sizeof(gpointer) - 1;
1033 offset &= ~(sizeof(gpointer) - 1);
1034 inst->inst_offset = offset;
1035 inst->opcode = OP_REGOFFSET;
1036 inst->inst_basereg = frame_reg;
1037 offset += sizeof(gpointer);
1038 if (sig->call_convention == MONO_CALL_VARARG)
1039 m->sig_cookie += sizeof (gpointer);
1042 curinst = m->locals_start;
1043 for (i = curinst; i < m->num_varinfo; ++i) {
1044 inst = m->varinfo [i];
1045 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1048 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1049 * pinvoke wrappers when they call functions returning structure */
1050 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1051 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1053 size = mono_type_size (inst->inst_vtype, &align);
1055 offset += align - 1;
1056 offset &= ~(align - 1);
1057 inst->inst_offset = offset;
1058 inst->opcode = OP_REGOFFSET;
1059 inst->inst_basereg = frame_reg;
1061 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1066 inst = m->args [curinst];
1067 if (inst->opcode != OP_REGVAR) {
1068 inst->opcode = OP_REGOFFSET;
1069 inst->inst_basereg = frame_reg;
1070 offset += sizeof (gpointer) - 1;
1071 offset &= ~(sizeof (gpointer) - 1);
1072 inst->inst_offset = offset;
1073 offset += sizeof (gpointer);
1074 if (sig->call_convention == MONO_CALL_VARARG)
1075 m->sig_cookie += sizeof (gpointer);
1080 for (i = 0; i < sig->param_count; ++i) {
1081 inst = m->args [curinst];
1082 if (inst->opcode != OP_REGVAR) {
1083 inst->opcode = OP_REGOFFSET;
1084 inst->inst_basereg = frame_reg;
1085 size = mono_type_size (sig->params [i], &align);
1086 offset += align - 1;
1087 offset &= ~(align - 1);
1088 inst->inst_offset = offset;
1090 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1091 m->sig_cookie += size;
1096 /* align the offset to 16 bytes */
1098 offset &= ~(16 - 1);
1101 m->stack_offset = offset;
1105 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1106 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1110 * take the arguments and generate the arch-specific
1111 * instructions to properly call the function in call.
1112 * This includes pushing, moving arguments to the right register
1114 * Issue: who does the spilling if needed, and when?
1117 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1119 MonoMethodSignature *sig;
1124 sig = call->signature;
1125 n = sig->param_count + sig->hasthis;
1127 cinfo = calculate_sizes (sig, sig->pinvoke);
1128 if (cinfo->struct_ret)
1129 call->used_iregs |= 1 << cinfo->struct_ret;
1131 for (i = 0; i < n; ++i) {
1132 ainfo = cinfo->args + i;
1133 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1135 cfg->disable_aot = TRUE;
1137 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1138 sig_arg->inst_p0 = call->signature;
1140 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1141 arg->inst_imm = cinfo->sig_cookie.offset;
1142 arg->inst_left = sig_arg;
1143 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1145 if (is_virtual && i == 0) {
1146 /* the argument will be attached to the call instrucion */
1147 in = call->args [i];
1148 call->used_iregs |= 1 << ainfo->reg;
1150 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1151 in = call->args [i];
1152 arg->cil_code = in->cil_code;
1153 arg->inst_left = in;
1154 arg->inst_call = call;
1155 arg->type = in->type;
1156 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1157 if (ainfo->regtype == RegTypeGeneral) {
1158 arg->backend.reg3 = ainfo->reg;
1159 call->used_iregs |= 1 << ainfo->reg;
1160 if (arg->type == STACK_I8)
1161 call->used_iregs |= 1 << (ainfo->reg + 1);
1162 } else if (ainfo->regtype == RegTypeStructByAddr) {
1163 if (ainfo->offset) {
1164 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1165 arg->opcode = OP_OUTARG_MEMBASE;
1166 ai->reg = ainfo->reg;
1167 ai->size = sizeof (gpointer);
1168 ai->offset = ainfo->offset;
1169 arg->backend.data = ai;
1171 arg->backend.reg3 = ainfo->reg;
1172 call->used_iregs |= 1 << ainfo->reg;
1174 } else if (ainfo->regtype == RegTypeStructByVal) {
1176 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1177 /* mark the used regs */
1178 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1179 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1181 arg->opcode = OP_OUTARG_VT;
1182 ai->reg = ainfo->reg;
1183 ai->size = ainfo->size;
1184 ai->vtsize = ainfo->vtsize;
1185 ai->offset = ainfo->offset;
1186 arg->backend.data = ai;
1187 } else if (ainfo->regtype == RegTypeBase) {
1188 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1189 arg->opcode = OP_OUTARG_MEMBASE;
1190 ai->reg = ainfo->reg;
1191 ai->size = ainfo->size;
1192 ai->offset = ainfo->offset;
1193 arg->backend.data = ai;
1194 } else if (ainfo->regtype == RegTypeFP) {
1195 arg->opcode = OP_OUTARG_R8;
1196 arg->backend.reg3 = ainfo->reg;
1197 call->used_fregs |= 1 << ainfo->reg;
1198 if (ainfo->size == 4) {
1199 arg->opcode = OP_OUTARG_R8;
1200 /* we reduce the precision */
1202 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1203 conv->inst_left = arg->inst_left;
1204 arg->inst_left = conv;*/
1207 g_assert_not_reached ();
1211 call->stack_usage = cinfo->stack_usage;
1212 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1213 cfg->flags |= MONO_CFG_HAS_CALLS;
1215 * should set more info in call, such as the stack space
1216 * used by the args that needs to be added back to esp
1224 * Allow tracing to work with this interface (with an optional argument)
1228 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1232 ppc_load (code, ppc_r3, cfg->method);
1233 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1234 ppc_load (code, ppc_r0, func);
1235 ppc_mtlr (code, ppc_r0);
1249 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1252 int save_mode = SAVE_NONE;
1254 MonoMethod *method = cfg->method;
1255 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1256 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1260 offset = code - cfg->native_code;
1261 /* we need about 16 instructions */
1262 if (offset > (cfg->code_size - 16 * 4)) {
1263 cfg->code_size *= 2;
1264 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1265 code = cfg->native_code + offset;
1269 case MONO_TYPE_VOID:
1270 /* special case string .ctor icall */
1271 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1272 save_mode = SAVE_ONE;
1274 save_mode = SAVE_NONE;
1278 save_mode = SAVE_TWO;
1282 save_mode = SAVE_FP;
1284 case MONO_TYPE_VALUETYPE:
1285 save_mode = SAVE_STRUCT;
1288 save_mode = SAVE_ONE;
1292 switch (save_mode) {
1294 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1295 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1296 if (enable_arguments) {
1297 ppc_mr (code, ppc_r5, ppc_r4);
1298 ppc_mr (code, ppc_r4, ppc_r3);
1302 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1303 if (enable_arguments) {
1304 ppc_mr (code, ppc_r4, ppc_r3);
1308 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1309 if (enable_arguments) {
1310 /* FIXME: what reg? */
1311 ppc_fmr (code, ppc_f3, ppc_f1);
1312 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1313 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1317 if (enable_arguments) {
1318 /* FIXME: get the actual address */
1319 ppc_mr (code, ppc_r4, ppc_r3);
1327 ppc_load (code, ppc_r3, cfg->method);
1328 ppc_load (code, ppc_r0, func);
1329 ppc_mtlr (code, ppc_r0);
1332 switch (save_mode) {
1334 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1335 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1338 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1341 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1351 * Conditional branches have a small offset, so if it is likely overflowed,
1352 * we do a branch to the end of the method (uncond branches have much larger
1353 * offsets) where we perform the conditional and jump back unconditionally.
1354 * It's slightly slower, since we add two uncond branches, but it's very simple
1355 * with the current patch implementation and such large methods are likely not
1356 * going to be perf critical anyway.
1361 const char *exception;
1368 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1369 if (ins->flags & MONO_INST_BRLABEL) { \
1370 if (0 && ins->inst_i0->inst_c0) { \
1371 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1373 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1374 ppc_bc (code, (b0), (b1), 0); \
1377 if (0 && ins->inst_true_bb->native_offset) { \
1378 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1380 int br_disp = ins->inst_true_bb->max_offset - offset; \
1381 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1382 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1383 ovfj->data.bb = ins->inst_true_bb; \
1384 ovfj->ip_offset = 0; \
1385 ovfj->b0_cond = (b0); \
1386 ovfj->b1_cond = (b1); \
1387 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1390 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1391 ppc_bc (code, (b0), (b1), 0); \
1396 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1398 /* emit an exception if condition is fail
1400 * We assign the extra code used to throw the implicit exceptions
1401 * to cfg->bb_exit as far as the big branch handling is concerned
1403 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1405 int br_disp = cfg->bb_exit->max_offset - offset; \
1406 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1407 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1408 ovfj->data.exception = (exc_name); \
1409 ovfj->ip_offset = code - cfg->native_code; \
1410 ovfj->b0_cond = (b0); \
1411 ovfj->b1_cond = (b1); \
1412 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1414 cfg->bb_exit->max_offset += 24; \
1416 mono_add_patch_info (cfg, code - cfg->native_code, \
1417 MONO_PATCH_INFO_EXC, exc_name); \
1418 ppc_bcl (code, (b0), (b1), 0); \
1422 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1425 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1429 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
1430 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1431 switch (ins->opcode) {
1433 /* remove unnecessary multiplication with 1 */
1434 if (ins->inst_imm == 1) {
1435 if (ins->dreg != ins->sreg1) {
1436 ins->opcode = OP_MOVE;
1442 int power2 = mono_is_power_of_two (ins->inst_imm);
1444 ins->opcode = OP_SHL_IMM;
1445 ins->inst_imm = power2;
1449 case OP_LOAD_MEMBASE:
1450 case OP_LOADI4_MEMBASE:
1452 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1453 * OP_LOAD_MEMBASE offset(basereg), reg
1455 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1456 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1457 ins->inst_basereg == last_ins->inst_destbasereg &&
1458 ins->inst_offset == last_ins->inst_offset) {
1459 if (ins->dreg == last_ins->sreg1) {
1463 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1464 ins->opcode = OP_MOVE;
1465 ins->sreg1 = last_ins->sreg1;
1469 * Note: reg1 must be different from the basereg in the second load
1470 * OP_LOAD_MEMBASE offset(basereg), reg1
1471 * OP_LOAD_MEMBASE offset(basereg), reg2
1473 * OP_LOAD_MEMBASE offset(basereg), reg1
1474 * OP_MOVE reg1, reg2
1476 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1477 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1478 ins->inst_basereg != last_ins->dreg &&
1479 ins->inst_basereg == last_ins->inst_basereg &&
1480 ins->inst_offset == last_ins->inst_offset) {
1482 if (ins->dreg == last_ins->dreg) {
1486 ins->opcode = OP_MOVE;
1487 ins->sreg1 = last_ins->dreg;
1490 //g_assert_not_reached ();
1494 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1495 * OP_LOAD_MEMBASE offset(basereg), reg
1497 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1498 * OP_ICONST reg, imm
1500 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1501 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1502 ins->inst_basereg == last_ins->inst_destbasereg &&
1503 ins->inst_offset == last_ins->inst_offset) {
1504 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1505 ins->opcode = OP_ICONST;
1506 ins->inst_c0 = last_ins->inst_imm;
1507 g_assert_not_reached (); // check this rule
1511 case OP_LOADU1_MEMBASE:
1512 case OP_LOADI1_MEMBASE:
1513 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1514 ins->inst_basereg == last_ins->inst_destbasereg &&
1515 ins->inst_offset == last_ins->inst_offset) {
1516 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1517 ins->sreg1 = last_ins->sreg1;
1520 case OP_LOADU2_MEMBASE:
1521 case OP_LOADI2_MEMBASE:
1522 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1523 ins->inst_basereg == last_ins->inst_destbasereg &&
1524 ins->inst_offset == last_ins->inst_offset) {
1525 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1526 ins->sreg1 = last_ins->sreg1;
1532 ins->opcode = OP_MOVE;
1536 if (ins->dreg == ins->sreg1) {
1541 * OP_MOVE sreg, dreg
1542 * OP_MOVE dreg, sreg
1544 if (last_ins && last_ins->opcode == OP_MOVE &&
1545 ins->sreg1 == last_ins->dreg &&
1546 ins->dreg == last_ins->sreg1) {
1556 * the branch_b0_table should maintain the order of these
1570 branch_b0_table [] = {
1585 branch_b1_table [] = {
1599 #define NEW_INS(cfg,ins,dest,op) do { \
1600 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1601 (dest)->opcode = (op); \
1602 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1606 map_to_reg_reg_op (int op)
1615 case OP_COMPARE_IMM:
1631 case OP_LOAD_MEMBASE:
1632 return OP_LOAD_MEMINDEX;
1633 case OP_LOADI4_MEMBASE:
1634 return OP_LOADI4_MEMINDEX;
1635 case OP_LOADU4_MEMBASE:
1636 return OP_LOADU4_MEMINDEX;
1637 case OP_LOADU1_MEMBASE:
1638 return OP_LOADU1_MEMINDEX;
1639 case OP_LOADI2_MEMBASE:
1640 return OP_LOADI2_MEMINDEX;
1641 case OP_LOADU2_MEMBASE:
1642 return OP_LOADU2_MEMINDEX;
1643 case OP_LOADI1_MEMBASE:
1644 return OP_LOADI1_MEMINDEX;
1645 case OP_LOADR4_MEMBASE:
1646 return OP_LOADR4_MEMINDEX;
1647 case OP_LOADR8_MEMBASE:
1648 return OP_LOADR8_MEMINDEX;
1649 case OP_STOREI1_MEMBASE_REG:
1650 return OP_STOREI1_MEMINDEX;
1651 case OP_STOREI2_MEMBASE_REG:
1652 return OP_STOREI2_MEMINDEX;
1653 case OP_STOREI4_MEMBASE_REG:
1654 return OP_STOREI4_MEMINDEX;
1655 case OP_STORE_MEMBASE_REG:
1656 return OP_STORE_MEMINDEX;
1657 case OP_STORER4_MEMBASE_REG:
1658 return OP_STORER4_MEMINDEX;
1659 case OP_STORER8_MEMBASE_REG:
1660 return OP_STORER8_MEMINDEX;
1661 case OP_STORE_MEMBASE_IMM:
1662 return OP_STORE_MEMBASE_REG;
1663 case OP_STOREI1_MEMBASE_IMM:
1664 return OP_STOREI1_MEMBASE_REG;
1665 case OP_STOREI2_MEMBASE_IMM:
1666 return OP_STOREI2_MEMBASE_REG;
1667 case OP_STOREI4_MEMBASE_IMM:
1668 return OP_STOREI4_MEMBASE_REG;
1670 g_assert_not_reached ();
1673 #define compare_opcode_is_unsigned(opcode) \
1674 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1675 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1676 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1678 * Remove from the instruction list the instructions that can't be
1679 * represented with very simple instructions with no register
1683 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1685 MonoInst *ins, *next, *temp;
1688 /* setup the virtual reg allocator */
1689 if (bb->max_vreg > cfg->rs->next_vreg)
1690 cfg->rs->next_vreg = bb->max_vreg;
1692 MONO_BB_FOR_EACH_INS (bb, ins) {
1694 switch (ins->opcode) {
1697 if (!ppc_is_imm16 (ins->inst_imm)) {
1698 NEW_INS (cfg, ins, temp, OP_ICONST);
1699 temp->inst_c0 = ins->inst_imm;
1700 temp->dreg = mono_regstate_next_int (cfg->rs);
1701 ins->sreg2 = temp->dreg;
1702 ins->opcode = map_to_reg_reg_op (ins->opcode);
1706 if (!ppc_is_imm16 (-ins->inst_imm)) {
1707 NEW_INS (cfg, ins, temp, OP_ICONST);
1708 temp->inst_c0 = ins->inst_imm;
1709 temp->dreg = mono_regstate_next_int (cfg->rs);
1710 ins->sreg2 = temp->dreg;
1711 ins->opcode = map_to_reg_reg_op (ins->opcode);
1717 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1718 NEW_INS (cfg, ins, temp, OP_ICONST);
1719 temp->inst_c0 = ins->inst_imm;
1720 temp->dreg = mono_regstate_next_int (cfg->rs);
1721 ins->sreg2 = temp->dreg;
1722 ins->opcode = map_to_reg_reg_op (ins->opcode);
1728 NEW_INS (cfg, ins, temp, OP_ICONST);
1729 temp->inst_c0 = ins->inst_imm;
1730 temp->dreg = mono_regstate_next_int (cfg->rs);
1731 ins->sreg2 = temp->dreg;
1732 ins->opcode = map_to_reg_reg_op (ins->opcode);
1734 case OP_COMPARE_IMM:
1735 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1737 if (compare_opcode_is_unsigned (next->opcode)) {
1738 if (!ppc_is_uimm16 (ins->inst_imm)) {
1739 NEW_INS (cfg, ins, temp, OP_ICONST);
1740 temp->inst_c0 = ins->inst_imm;
1741 temp->dreg = mono_regstate_next_int (cfg->rs);
1742 ins->sreg2 = temp->dreg;
1743 ins->opcode = map_to_reg_reg_op (ins->opcode);
1746 if (!ppc_is_imm16 (ins->inst_imm)) {
1747 NEW_INS (cfg, ins, temp, OP_ICONST);
1748 temp->inst_c0 = ins->inst_imm;
1749 temp->dreg = mono_regstate_next_int (cfg->rs);
1750 ins->sreg2 = temp->dreg;
1751 ins->opcode = map_to_reg_reg_op (ins->opcode);
1756 if (ins->inst_imm == 1) {
1757 ins->opcode = OP_MOVE;
1760 if (ins->inst_imm == 0) {
1761 ins->opcode = OP_ICONST;
1765 imm = mono_is_power_of_two (ins->inst_imm);
1767 ins->opcode = OP_SHL_IMM;
1768 ins->inst_imm = imm;
1771 if (!ppc_is_imm16 (ins->inst_imm)) {
1772 NEW_INS (cfg, ins, temp, OP_ICONST);
1773 temp->inst_c0 = ins->inst_imm;
1774 temp->dreg = mono_regstate_next_int (cfg->rs);
1775 ins->sreg2 = temp->dreg;
1776 ins->opcode = map_to_reg_reg_op (ins->opcode);
1779 case OP_LOAD_MEMBASE:
1780 case OP_LOADI4_MEMBASE:
1781 case OP_LOADU4_MEMBASE:
1782 case OP_LOADI2_MEMBASE:
1783 case OP_LOADU2_MEMBASE:
1784 case OP_LOADI1_MEMBASE:
1785 case OP_LOADU1_MEMBASE:
1786 case OP_LOADR4_MEMBASE:
1787 case OP_LOADR8_MEMBASE:
1788 case OP_STORE_MEMBASE_REG:
1789 case OP_STOREI4_MEMBASE_REG:
1790 case OP_STOREI2_MEMBASE_REG:
1791 case OP_STOREI1_MEMBASE_REG:
1792 case OP_STORER4_MEMBASE_REG:
1793 case OP_STORER8_MEMBASE_REG:
1794 /* we can do two things: load the immed in a register
1795 * and use an indexed load, or see if the immed can be
1796 * represented as an ad_imm + a load with a smaller offset
1797 * that fits. We just do the first for now, optimize later.
1799 if (ppc_is_imm16 (ins->inst_offset))
1801 NEW_INS (cfg, ins, temp, OP_ICONST);
1802 temp->inst_c0 = ins->inst_offset;
1803 temp->dreg = mono_regstate_next_int (cfg->rs);
1804 ins->sreg2 = temp->dreg;
1805 ins->opcode = map_to_reg_reg_op (ins->opcode);
1807 case OP_STORE_MEMBASE_IMM:
1808 case OP_STOREI1_MEMBASE_IMM:
1809 case OP_STOREI2_MEMBASE_IMM:
1810 case OP_STOREI4_MEMBASE_IMM:
1811 NEW_INS (cfg, ins, temp, OP_ICONST);
1812 temp->inst_c0 = ins->inst_imm;
1813 temp->dreg = mono_regstate_next_int (cfg->rs);
1814 ins->sreg1 = temp->dreg;
1815 ins->opcode = map_to_reg_reg_op (ins->opcode);
1816 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1819 NEW_INS (cfg, ins, temp, OP_ICONST);
1820 temp->inst_c0 = ins->inst_p0;
1821 temp->dreg = mono_regstate_next_int (cfg->rs);
1822 ins->inst_basereg = temp->dreg;
1823 ins->inst_offset = 0;
1824 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
1825 /* make it handle the possibly big ins->inst_offset
1826 * later optimize to use lis + load_membase
1831 bb->max_vreg = cfg->rs->next_vreg;
1836 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1838 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
1840 mono_arch_lowering_pass (cfg, bb);
1841 mono_local_regalloc (cfg, bb);
1845 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1847 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1848 ppc_fctiwz (code, ppc_f0, sreg);
1849 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1850 ppc_lwz (code, dreg, -4, ppc_sp);
1853 ppc_andid (code, dreg, dreg, 0xff);
1855 ppc_andid (code, dreg, dreg, 0xffff);
1858 ppc_extsb (code, dreg, dreg);
1860 ppc_extsh (code, dreg, dreg);
1865 static unsigned char*
1866 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1869 int sreg = tree->sreg1;
1870 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1871 if (tree->flags & MONO_INST_INIT) {
1873 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1874 x86_push_reg (code, X86_EAX);
1877 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1878 x86_push_reg (code, X86_ECX);
1881 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1882 x86_push_reg (code, X86_EDI);
1886 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1887 if (sreg != X86_ECX)
1888 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1889 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1891 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1893 x86_prefix (code, X86_REP_PREFIX);
1896 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1897 x86_pop_reg (code, X86_EDI);
1898 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1899 x86_pop_reg (code, X86_ECX);
1900 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1901 x86_pop_reg (code, X86_EAX);
1914 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1917 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1918 PatchData *pdata = (PatchData*)user_data;
1919 guchar *code = data;
1920 guint32 *thunks = data;
1921 guint32 *endthunks = (guint32*)(code + bsize);
1925 int difflow, diffhigh;
1927 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1928 difflow = (char*)pdata->code - (char*)thunks;
1929 diffhigh = (char*)pdata->code - (char*)endthunks;
1930 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1933 templ = (guchar*)load;
1934 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1935 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1937 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1938 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1939 while (thunks < endthunks) {
1940 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1941 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1942 ppc_patch (pdata->code, (guchar*)thunks);
1943 mono_arch_flush_icache (pdata->code, 4);
1946 static int num_thunks = 0;
1948 if ((num_thunks % 20) == 0)
1949 g_print ("num_thunks lookup: %d\n", num_thunks);
1952 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1953 /* found a free slot instead: emit thunk */
1954 code = (guchar*)thunks;
1955 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1956 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1957 ppc_mtctr (code, ppc_r0);
1958 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1959 mono_arch_flush_icache ((guchar*)thunks, 16);
1961 ppc_patch (pdata->code, (guchar*)thunks);
1962 mono_arch_flush_icache (pdata->code, 4);
1965 static int num_thunks = 0;
1967 if ((num_thunks % 20) == 0)
1968 g_print ("num_thunks: %d\n", num_thunks);
1972 /* skip 16 bytes, the size of the thunk */
1976 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1982 handle_thunk (int absolute, guchar *code, guchar *target) {
1983 MonoDomain *domain = mono_domain_get ();
1987 pdata.target = target;
1988 pdata.absolute = absolute;
1991 mono_domain_lock (domain);
1992 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1995 /* this uses the first available slot */
1997 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1999 mono_domain_unlock (domain);
2001 if (pdata.found != 1)
2002 g_print ("thunk failed for %p from %p\n", target, code);
2003 g_assert (pdata.found == 1);
2007 ppc_patch (guchar *code, guchar *target)
2009 guint32 ins = *(guint32*)code;
2010 guint32 prim = ins >> 26;
2013 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2015 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2016 gint diff = target - code;
2018 if (diff <= 33554431){
2019 ins = (18 << 26) | (diff) | (ins & 1);
2020 *(guint32*)code = ins;
2024 /* diff between 0 and -33554432 */
2025 if (diff >= -33554432){
2026 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2027 *(guint32*)code = ins;
2032 if ((glong)target >= 0){
2033 if ((glong)target <= 33554431){
2034 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2035 *(guint32*)code = ins;
2039 if ((glong)target >= -33554432){
2040 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2041 *(guint32*)code = ins;
2046 handle_thunk (TRUE, code, target);
2049 g_assert_not_reached ();
2056 guint32 li = (guint32)target;
2057 ins = (ins & 0xffff0000) | (ins & 3);
2058 ovf = li & 0xffff0000;
2059 if (ovf != 0 && ovf != 0xffff0000)
2060 g_assert_not_reached ();
2063 // FIXME: assert the top bits of li are 0
2065 gint diff = target - code;
2066 ins = (ins & 0xffff0000) | (ins & 3);
2067 ovf = diff & 0xffff0000;
2068 if (ovf != 0 && ovf != 0xffff0000)
2069 g_assert_not_reached ();
2073 *(guint32*)code = ins;
2077 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2079 /* the trampoline code will try to patch the blrl, blr, bcctr */
2080 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2083 /* this is the lis/ori/mtlr/blrl sequence */
2084 seq = (guint32*)code;
2085 g_assert ((seq [0] >> 26) == 15);
2086 g_assert ((seq [1] >> 26) == 24);
2087 g_assert ((seq [2] >> 26) == 31);
2088 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2089 /* FIXME: make this thread safe */
2090 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2091 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2092 mono_arch_flush_icache (code - 8, 8);
2094 g_assert_not_reached ();
2096 // g_print ("patched with 0x%08x\n", ins);
2100 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2102 MonoInst *ins, *next;
2105 guint8 *code = cfg->native_code + cfg->code_len;
2106 guint last_offset = 0;
2109 if (cfg->opt & MONO_OPT_PEEPHOLE)
2110 peephole_pass (cfg, bb);
2112 /* we don't align basic blocks of loops on ppc */
2114 if (cfg->verbose_level > 2)
2115 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2117 cpos = bb->max_offset;
2119 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2120 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2121 //g_assert (!mono_compile_aot);
2124 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2125 /* this is not thread save, but good enough */
2126 /* fixme: howto handle overflows? */
2127 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2130 MONO_BB_FOR_EACH_INS (bb, ins) {
2131 offset = code - cfg->native_code;
2133 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2135 if (offset > (cfg->code_size - max_len - 16)) {
2136 cfg->code_size *= 2;
2137 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2138 code = cfg->native_code + offset;
2140 // if (ins->cil_code)
2141 // g_print ("cil code\n");
2142 mono_debug_record_line_number (cfg, ins, offset);
2144 switch (ins->opcode) {
2146 emit_tls_access (code, ins->dreg, ins->inst_offset);
2149 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2150 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2151 ppc_mr (code, ppc_r4, ppc_r0);
2154 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2155 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2156 ppc_mr (code, ppc_r4, ppc_r0);
2158 case OP_MEMORY_BARRIER:
2161 case OP_STOREI1_MEMBASE_REG:
2162 if (ppc_is_imm16 (ins->inst_offset)) {
2163 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2165 g_assert_not_reached ();
2168 case OP_STOREI2_MEMBASE_REG:
2169 if (ppc_is_imm16 (ins->inst_offset)) {
2170 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2172 g_assert_not_reached ();
2175 case OP_STORE_MEMBASE_REG:
2176 case OP_STOREI4_MEMBASE_REG:
2177 if (ppc_is_imm16 (ins->inst_offset)) {
2178 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2180 g_assert_not_reached ();
2183 case OP_STOREI1_MEMINDEX:
2184 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2186 case OP_STOREI2_MEMINDEX:
2187 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2189 case OP_STORE_MEMINDEX:
2190 case OP_STOREI4_MEMINDEX:
2191 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2194 g_assert_not_reached ();
2196 case OP_LOAD_MEMBASE:
2197 case OP_LOADI4_MEMBASE:
2198 case OP_LOADU4_MEMBASE:
2199 if (ppc_is_imm16 (ins->inst_offset)) {
2200 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2202 g_assert_not_reached ();
2205 case OP_LOADI1_MEMBASE:
2206 case OP_LOADU1_MEMBASE:
2207 if (ppc_is_imm16 (ins->inst_offset)) {
2208 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2210 g_assert_not_reached ();
2212 if (ins->opcode == OP_LOADI1_MEMBASE)
2213 ppc_extsb (code, ins->dreg, ins->dreg);
2215 case OP_LOADU2_MEMBASE:
2216 if (ppc_is_imm16 (ins->inst_offset)) {
2217 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2219 g_assert_not_reached ();
2222 case OP_LOADI2_MEMBASE:
2223 if (ppc_is_imm16 (ins->inst_offset)) {
2224 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2226 g_assert_not_reached ();
2229 case OP_LOAD_MEMINDEX:
2230 case OP_LOADI4_MEMINDEX:
2231 case OP_LOADU4_MEMINDEX:
2232 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2234 case OP_LOADU2_MEMINDEX:
2235 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2237 case OP_LOADI2_MEMINDEX:
2238 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2240 case OP_LOADU1_MEMINDEX:
2241 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2243 case OP_LOADI1_MEMINDEX:
2244 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2245 ppc_extsb (code, ins->dreg, ins->dreg);
2248 ppc_extsb (code, ins->dreg, ins->sreg1);
2251 ppc_extsh (code, ins->dreg, ins->sreg1);
2254 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2257 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2260 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2261 if (next && compare_opcode_is_unsigned (next->opcode))
2262 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2264 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2266 case OP_COMPARE_IMM:
2267 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2268 if (next && compare_opcode_is_unsigned (next->opcode)) {
2269 if (ppc_is_uimm16 (ins->inst_imm)) {
2270 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2272 g_assert_not_reached ();
2275 if (ppc_is_imm16 (ins->inst_imm)) {
2276 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2278 g_assert_not_reached ();
2286 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2289 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2292 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2295 if (ppc_is_imm16 (ins->inst_imm)) {
2296 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2298 g_assert_not_reached ();
2302 if (ppc_is_imm16 (ins->inst_imm)) {
2303 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2305 g_assert_not_reached ();
2309 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2311 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2312 ppc_mfspr (code, ppc_r0, ppc_xer);
2313 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2314 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2316 case CEE_ADD_OVF_UN:
2317 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2319 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2320 ppc_mfspr (code, ppc_r0, ppc_xer);
2321 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2322 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2325 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2327 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2328 ppc_mfspr (code, ppc_r0, ppc_xer);
2329 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2330 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2332 case CEE_SUB_OVF_UN:
2333 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2335 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2336 ppc_mfspr (code, ppc_r0, ppc_xer);
2337 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2338 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2340 case OP_ADD_OVF_CARRY:
2341 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2343 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2344 ppc_mfspr (code, ppc_r0, ppc_xer);
2345 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2346 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2348 case OP_ADD_OVF_UN_CARRY:
2349 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2351 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2352 ppc_mfspr (code, ppc_r0, ppc_xer);
2353 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2354 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2356 case OP_SUB_OVF_CARRY:
2357 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2359 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2360 ppc_mfspr (code, ppc_r0, ppc_xer);
2361 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2362 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2364 case OP_SUB_OVF_UN_CARRY:
2365 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2367 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2368 ppc_mfspr (code, ppc_r0, ppc_xer);
2369 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2370 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2373 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2376 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2379 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2382 // we add the negated value
2383 if (ppc_is_imm16 (-ins->inst_imm))
2384 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2386 g_assert_not_reached ();
2390 g_assert (ppc_is_imm16 (ins->inst_imm));
2391 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2394 ppc_subfze (code, ins->dreg, ins->sreg1);
2397 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2398 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2401 if (!(ins->inst_imm & 0xffff0000)) {
2402 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2403 } else if (!(ins->inst_imm & 0xffff)) {
2404 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2406 g_assert_not_reached ();
2410 guint32 *divisor_is_m1;
2411 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2413 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2414 divisor_is_m1 = code;
2415 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2416 ppc_lis (code, ppc_r0, 0x8000);
2417 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2418 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2419 ppc_patch (divisor_is_m1, code);
2420 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2422 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2423 ppc_mfspr (code, ppc_r0, ppc_xer);
2424 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2425 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2429 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2430 ppc_mfspr (code, ppc_r0, ppc_xer);
2431 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2432 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2438 g_assert_not_reached ();
2440 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2443 if (!(ins->inst_imm & 0xffff0000)) {
2444 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2445 } else if (!(ins->inst_imm & 0xffff)) {
2446 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2448 g_assert_not_reached ();
2452 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2455 if (!(ins->inst_imm & 0xffff0000)) {
2456 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2457 } else if (!(ins->inst_imm & 0xffff)) {
2458 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2460 g_assert_not_reached ();
2464 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2467 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2470 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2473 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2477 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2479 ppc_mr (code, ins->dreg, ins->sreg1);
2482 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2485 ppc_not (code, ins->dreg, ins->sreg1);
2488 ppc_neg (code, ins->dreg, ins->sreg1);
2491 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2494 if (ppc_is_imm16 (ins->inst_imm)) {
2495 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2497 g_assert_not_reached ();
2501 /* we annot use mcrxr, since it's not implemented on some processors
2502 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2504 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2505 ppc_mfspr (code, ppc_r0, ppc_xer);
2506 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2507 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2509 case CEE_MUL_OVF_UN:
2510 /* we first multiply to get the high word and compare to 0
2511 * to set the flags, then the result is discarded and then
2512 * we multiply to get the lower * bits result
2514 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2515 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2516 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2517 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2520 ppc_load (code, ins->dreg, ins->inst_c0);
2523 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2524 ppc_lis (code, ins->dreg, 0);
2525 ppc_ori (code, ins->dreg, ins->dreg, 0);
2530 ppc_mr (code, ins->dreg, ins->sreg1);
2533 int saved = ins->sreg1;
2534 if (ins->sreg1 == ppc_r3) {
2535 ppc_mr (code, ppc_r0, ins->sreg1);
2538 if (ins->sreg2 != ppc_r3)
2539 ppc_mr (code, ppc_r3, ins->sreg2);
2540 if (saved != ppc_r4)
2541 ppc_mr (code, ppc_r4, saved);
2545 ppc_fmr (code, ins->dreg, ins->sreg1);
2547 case OP_FCONV_TO_R4:
2548 ppc_frsp (code, ins->dreg, ins->sreg1);
2554 * Keep in sync with mono_arch_emit_epilog
2556 g_assert (!cfg->method->save_lmf);
2558 * Note: we can use ppc_r11 here because it is dead anyway:
2559 * we're leaving the method.
2561 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2562 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2563 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2565 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2566 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2568 ppc_mtlr (code, ppc_r0);
2570 if (ppc_is_imm16 (cfg->stack_usage)) {
2571 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2573 ppc_load (code, ppc_r11, cfg->stack_usage);
2574 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2576 if (!cfg->method->save_lmf) {
2577 /*for (i = 31; i >= 14; --i) {
2578 if (cfg->used_float_regs & (1 << i)) {
2579 pos += sizeof (double);
2580 ppc_lfd (code, i, -pos, cfg->frame_reg);
2583 for (i = 31; i >= 13; --i) {
2584 if (cfg->used_int_regs & (1 << i)) {
2585 pos += sizeof (gulong);
2586 ppc_lwz (code, i, -pos, cfg->frame_reg);
2590 /* FIXME restore from MonoLMF: though this can't happen yet */
2592 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2597 /* ensure ins->sreg1 is not NULL */
2598 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2601 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2602 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2604 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
2605 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
2607 ppc_stw (code, ppc_r0, 0, ins->sreg1);
2615 call = (MonoCallInst*)ins;
2616 if (ins->flags & MONO_INST_HAS_METHOD)
2617 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2619 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2620 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2621 ppc_lis (code, ppc_r0, 0);
2622 ppc_ori (code, ppc_r0, ppc_r0, 0);
2623 ppc_mtlr (code, ppc_r0);
2632 case OP_VOIDCALL_REG:
2634 ppc_mtlr (code, ins->sreg1);
2637 case OP_FCALL_MEMBASE:
2638 case OP_LCALL_MEMBASE:
2639 case OP_VCALL_MEMBASE:
2640 case OP_VOIDCALL_MEMBASE:
2641 case OP_CALL_MEMBASE:
2642 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2643 ppc_mtlr (code, ppc_r0);
2647 g_assert_not_reached ();
2650 guint32 * zero_loop_jump, * zero_loop_start;
2651 /* keep alignment */
2652 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2653 int area_offset = alloca_waste;
2655 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2656 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2657 /* use ctr to store the number of words to 0 if needed */
2658 if (ins->flags & MONO_INST_INIT) {
2659 /* we zero 4 bytes at a time:
2660 * we add 7 instead of 3 so that we set the counter to
2661 * at least 1, otherwise the bdnz instruction will make
2662 * it negative and iterate billions of times.
2664 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2665 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2666 ppc_mtctr (code, ppc_r0);
2668 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2669 ppc_neg (code, ppc_r11, ppc_r11);
2670 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2672 if (ins->flags & MONO_INST_INIT) {
2673 /* adjust the dest reg by -4 so we can use stwu */
2674 /* we actually adjust -8 because we let the loop
2677 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2678 ppc_li (code, ppc_r11, 0);
2679 zero_loop_start = code;
2680 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2681 zero_loop_jump = code;
2682 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2683 ppc_patch (zero_loop_jump, zero_loop_start);
2685 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2690 ppc_mr (code, ppc_r3, ins->sreg1);
2691 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2692 (gpointer)"mono_arch_throw_exception");
2693 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2694 ppc_lis (code, ppc_r0, 0);
2695 ppc_ori (code, ppc_r0, ppc_r0, 0);
2696 ppc_mtlr (code, ppc_r0);
2705 ppc_mr (code, ppc_r3, ins->sreg1);
2706 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2707 (gpointer)"mono_arch_rethrow_exception");
2708 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2709 ppc_lis (code, ppc_r0, 0);
2710 ppc_ori (code, ppc_r0, ppc_r0, 0);
2711 ppc_mtlr (code, ppc_r0);
2718 case OP_START_HANDLER:
2719 ppc_mflr (code, ppc_r0);
2720 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2721 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2723 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2724 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2728 if (ins->sreg1 != ppc_r3)
2729 ppc_mr (code, ppc_r3, ins->sreg1);
2730 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2731 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2733 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2734 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2736 ppc_mtlr (code, ppc_r0);
2740 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2741 ppc_mtlr (code, ppc_r0);
2744 case OP_CALL_HANDLER:
2745 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2749 ins->inst_c0 = code - cfg->native_code;
2752 if (ins->flags & MONO_INST_BRLABEL) {
2753 /*if (ins->inst_i0->inst_c0) {
2755 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2757 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2761 /*if (ins->inst_target_bb->native_offset) {
2763 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2765 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2771 ppc_mtctr (code, ins->sreg1);
2772 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2775 ppc_li (code, ins->dreg, 0);
2776 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2777 ppc_li (code, ins->dreg, 1);
2781 ppc_li (code, ins->dreg, 1);
2782 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2783 ppc_li (code, ins->dreg, 0);
2787 ppc_li (code, ins->dreg, 1);
2788 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2789 ppc_li (code, ins->dreg, 0);
2791 case OP_COND_EXC_EQ:
2792 case OP_COND_EXC_NE_UN:
2793 case OP_COND_EXC_LT:
2794 case OP_COND_EXC_LT_UN:
2795 case OP_COND_EXC_GT:
2796 case OP_COND_EXC_GT_UN:
2797 case OP_COND_EXC_GE:
2798 case OP_COND_EXC_GE_UN:
2799 case OP_COND_EXC_LE:
2800 case OP_COND_EXC_LE_UN:
2801 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2804 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2806 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2807 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2808 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2810 case OP_COND_EXC_OV:
2811 /*ppc_mcrxr (code, 0);
2812 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2814 case OP_COND_EXC_NC:
2815 case OP_COND_EXC_NO:
2816 g_assert_not_reached ();
2828 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2831 /* floating point opcodes */
2834 g_assert_not_reached ();
2835 case OP_STORER8_MEMBASE_REG:
2836 if (ppc_is_imm16 (ins->inst_offset)) {
2837 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2839 g_assert_not_reached ();
2842 case OP_LOADR8_MEMBASE:
2843 if (ppc_is_imm16 (ins->inst_offset)) {
2844 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2846 g_assert_not_reached ();
2849 case OP_STORER4_MEMBASE_REG:
2850 ppc_frsp (code, ins->sreg1, ins->sreg1);
2851 if (ppc_is_imm16 (ins->inst_offset)) {
2852 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2854 g_assert_not_reached ();
2857 case OP_LOADR4_MEMBASE:
2858 if (ppc_is_imm16 (ins->inst_offset)) {
2859 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2861 g_assert_not_reached ();
2864 case OP_LOADR4_MEMINDEX:
2865 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2867 case OP_LOADR8_MEMINDEX:
2868 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2870 case OP_STORER4_MEMINDEX:
2871 ppc_frsp (code, ins->sreg1, ins->sreg1);
2872 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2874 case OP_STORER8_MEMINDEX:
2875 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2878 case CEE_CONV_R4: /* FIXME: change precision */
2880 g_assert_not_reached ();
2881 case OP_FCONV_TO_I1:
2882 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2884 case OP_FCONV_TO_U1:
2885 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2887 case OP_FCONV_TO_I2:
2888 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2890 case OP_FCONV_TO_U2:
2891 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2893 case OP_FCONV_TO_I4:
2895 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2897 case OP_FCONV_TO_U4:
2899 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2901 case OP_FCONV_TO_I8:
2902 case OP_FCONV_TO_U8:
2903 g_assert_not_reached ();
2904 /* Implemented as helper calls */
2906 case OP_LCONV_TO_R_UN:
2907 g_assert_not_reached ();
2908 /* Implemented as helper calls */
2910 case OP_LCONV_TO_OVF_I: {
2911 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2912 // Check if its negative
2913 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2914 negative_branch = code;
2915 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2916 // Its positive msword == 0
2917 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2918 msword_positive_branch = code;
2919 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2921 ovf_ex_target = code;
2922 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2924 ppc_patch (negative_branch, code);
2925 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2926 msword_negative_branch = code;
2927 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2928 ppc_patch (msword_negative_branch, ovf_ex_target);
2930 ppc_patch (msword_positive_branch, code);
2931 if (ins->dreg != ins->sreg1)
2932 ppc_mr (code, ins->dreg, ins->sreg1);
2936 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2939 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2942 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2945 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2948 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2951 ppc_fneg (code, ins->dreg, ins->sreg1);
2955 g_assert_not_reached ();
2958 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2961 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2962 ppc_li (code, ins->dreg, 0);
2963 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2964 ppc_li (code, ins->dreg, 1);
2967 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2968 ppc_li (code, ins->dreg, 1);
2969 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2970 ppc_li (code, ins->dreg, 0);
2973 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2974 ppc_li (code, ins->dreg, 1);
2975 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2976 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2977 ppc_li (code, ins->dreg, 0);
2980 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2981 ppc_li (code, ins->dreg, 1);
2982 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2983 ppc_li (code, ins->dreg, 0);
2986 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2987 ppc_li (code, ins->dreg, 1);
2988 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2989 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2990 ppc_li (code, ins->dreg, 0);
2993 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2996 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2999 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3000 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3003 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3004 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3007 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3008 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3011 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3012 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3015 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3016 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3019 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3022 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3023 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3026 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3029 g_assert_not_reached ();
3030 case OP_CHECK_FINITE: {
3031 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3032 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3033 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3034 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3038 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3039 g_assert_not_reached ();
3042 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3043 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3044 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3045 g_assert_not_reached ();
3050 last_offset = offset;
3053 cfg->code_len = code - cfg->native_code;
3057 mono_arch_register_lowlevel_calls (void)
3061 #define patch_lis_ori(ip,val) do {\
3062 guint16 *__lis_ori = (guint16*)(ip); \
3063 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3064 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3068 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3070 MonoJumpInfo *patch_info;
3072 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3073 unsigned char *ip = patch_info->ip.i + code;
3074 const unsigned char *target;
3076 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3078 switch (patch_info->type) {
3079 case MONO_PATCH_INFO_IP:
3080 patch_lis_ori (ip, ip);
3082 case MONO_PATCH_INFO_METHOD_REL:
3083 g_assert_not_reached ();
3084 *((gpointer *)(ip)) = code + patch_info->data.offset;
3086 case MONO_PATCH_INFO_SWITCH: {
3087 gpointer *table = (gpointer *)patch_info->data.table->table;
3090 patch_lis_ori (ip, table);
3092 for (i = 0; i < patch_info->data.table->table_size; i++) {
3093 table [i] = (int)patch_info->data.table->table [i] + code;
3095 /* we put into the table the absolute address, no need for ppc_patch in this case */
3098 case MONO_PATCH_INFO_METHODCONST:
3099 case MONO_PATCH_INFO_CLASS:
3100 case MONO_PATCH_INFO_IMAGE:
3101 case MONO_PATCH_INFO_FIELD:
3102 case MONO_PATCH_INFO_VTABLE:
3103 case MONO_PATCH_INFO_IID:
3104 case MONO_PATCH_INFO_SFLDA:
3105 case MONO_PATCH_INFO_LDSTR:
3106 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3107 case MONO_PATCH_INFO_LDTOKEN:
3108 /* from OP_AOTCONST : lis + ori */
3109 patch_lis_ori (ip, target);
3111 case MONO_PATCH_INFO_R4:
3112 case MONO_PATCH_INFO_R8:
3113 g_assert_not_reached ();
3114 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3116 case MONO_PATCH_INFO_EXC_NAME:
3117 g_assert_not_reached ();
3118 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3120 case MONO_PATCH_INFO_NONE:
3121 case MONO_PATCH_INFO_BB_OVF:
3122 case MONO_PATCH_INFO_EXC_OVF:
3123 /* everything is dealt with at epilog output time */
3128 ppc_patch (ip, target);
3133 * Stack frame layout:
3135 * ------------------- sp
3136 * MonoLMF structure or saved registers
3137 * -------------------
3139 * -------------------
3141 * -------------------
3142 * optional 8 bytes for tracing
3143 * -------------------
3144 * param area size is cfg->param_area
3145 * -------------------
3146 * linkage area size is PPC_STACK_PARAM_OFFSET
3147 * ------------------- sp
3151 mono_arch_emit_prolog (MonoCompile *cfg)
3153 MonoMethod *method = cfg->method;
3155 MonoMethodSignature *sig;
3157 int alloc_size, pos, max_offset, i;
3163 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3166 sig = mono_method_signature (method);
3167 cfg->code_size = 256 + sig->param_count * 20;
3168 code = cfg->native_code = g_malloc (cfg->code_size);
3170 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3171 ppc_mflr (code, ppc_r0);
3172 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3175 alloc_size = cfg->stack_offset;
3178 if (!method->save_lmf) {
3179 /*for (i = 31; i >= 14; --i) {
3180 if (cfg->used_float_regs & (1 << i)) {
3181 pos += sizeof (gdouble);
3182 ppc_stfd (code, i, -pos, ppc_sp);
3185 for (i = 31; i >= 13; --i) {
3186 if (cfg->used_int_regs & (1 << i)) {
3187 pos += sizeof (gulong);
3188 ppc_stw (code, i, -pos, ppc_sp);
3193 pos += sizeof (MonoLMF);
3195 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3196 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3197 for (i = 14; i < 32; i++) {
3198 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3202 // align to PPC_STACK_ALIGNMENT bytes
3203 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3204 alloc_size += PPC_STACK_ALIGNMENT - 1;
3205 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3208 cfg->stack_usage = alloc_size;
3209 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3211 if (ppc_is_imm16 (-alloc_size)) {
3212 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3214 ppc_load (code, ppc_r11, -alloc_size);
3215 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3218 if (cfg->frame_reg != ppc_sp)
3219 ppc_mr (code, cfg->frame_reg, ppc_sp);
3221 /* compute max_offset in order to use short forward jumps
3222 * we always do it on ppc because the immediate displacement
3223 * for jumps is too small
3226 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3228 bb->max_offset = max_offset;
3230 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3233 MONO_BB_FOR_EACH_INS (bb, ins)
3234 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3237 /* load arguments allocated to register from the stack */
3240 cinfo = calculate_sizes (sig, sig->pinvoke);
3242 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3243 ArgInfo *ainfo = &cinfo->ret;
3245 if (ppc_is_imm16 (inst->inst_offset)) {
3246 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3248 ppc_load (code, ppc_r11, inst->inst_offset);
3249 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3252 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3253 ArgInfo *ainfo = cinfo->args + i;
3254 inst = cfg->args [pos];
3256 if (cfg->verbose_level > 2)
3257 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3258 if (inst->opcode == OP_REGVAR) {
3259 if (ainfo->regtype == RegTypeGeneral)
3260 ppc_mr (code, inst->dreg, ainfo->reg);
3261 else if (ainfo->regtype == RegTypeFP)
3262 ppc_fmr (code, inst->dreg, ainfo->reg);
3263 else if (ainfo->regtype == RegTypeBase) {
3264 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3265 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3267 g_assert_not_reached ();
3269 if (cfg->verbose_level > 2)
3270 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3272 /* the argument should be put on the stack: FIXME handle size != word */
3273 if (ainfo->regtype == RegTypeGeneral) {
3274 switch (ainfo->size) {
3276 if (ppc_is_imm16 (inst->inst_offset)) {
3277 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3279 ppc_load (code, ppc_r11, inst->inst_offset);
3280 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3284 if (ppc_is_imm16 (inst->inst_offset)) {
3285 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3287 ppc_load (code, ppc_r11, inst->inst_offset);
3288 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3292 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3293 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3294 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3296 ppc_load (code, ppc_r11, inst->inst_offset);
3297 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3298 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3299 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3303 if (ppc_is_imm16 (inst->inst_offset)) {
3304 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3306 ppc_load (code, ppc_r11, inst->inst_offset);
3307 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3311 } else if (ainfo->regtype == RegTypeBase) {
3312 /* load the previous stack pointer in r11 */
3313 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3314 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3315 switch (ainfo->size) {
3317 if (ppc_is_imm16 (inst->inst_offset)) {
3318 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3320 ppc_load (code, ppc_r11, inst->inst_offset);
3321 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3325 if (ppc_is_imm16 (inst->inst_offset)) {
3326 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3328 ppc_load (code, ppc_r11, inst->inst_offset);
3329 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3333 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3334 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3335 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3336 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3339 g_assert_not_reached ();
3343 if (ppc_is_imm16 (inst->inst_offset)) {
3344 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3346 ppc_load (code, ppc_r11, inst->inst_offset);
3347 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3351 } else if (ainfo->regtype == RegTypeFP) {
3352 g_assert (ppc_is_imm16 (inst->inst_offset));
3353 if (ainfo->size == 8)
3354 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3355 else if (ainfo->size == 4)
3356 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3358 g_assert_not_reached ();
3359 } else if (ainfo->regtype == RegTypeStructByVal) {
3360 int doffset = inst->inst_offset;
3364 g_assert (ppc_is_imm16 (inst->inst_offset));
3365 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3366 if (mono_class_from_mono_type (inst->inst_vtype))
3367 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3368 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3370 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3371 register. Should this case include linux/ppc?
3375 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3377 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3380 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3381 soffset += sizeof (gpointer);
3382 doffset += sizeof (gpointer);
3384 if (ainfo->vtsize) {
3385 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3386 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3387 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3388 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3390 } else if (ainfo->regtype == RegTypeStructByAddr) {
3391 /* if it was originally a RegTypeBase */
3392 if (ainfo->offset) {
3393 /* load the previous stack pointer in r11 */
3394 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3395 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3397 ppc_mr (code, ppc_r11, ainfo->reg);
3399 g_assert (ppc_is_imm16 (inst->inst_offset));
3400 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3401 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3403 g_assert_not_reached ();
3408 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3409 ppc_load (code, ppc_r3, cfg->domain);
3410 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3411 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3412 ppc_lis (code, ppc_r0, 0);
3413 ppc_ori (code, ppc_r0, ppc_r0, 0);
3414 ppc_mtlr (code, ppc_r0);
3421 if (method->save_lmf) {
3422 if (lmf_pthread_key != -1) {
3423 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3424 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3425 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3427 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3428 (gpointer)"mono_get_lmf_addr");
3429 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3430 ppc_lis (code, ppc_r0, 0);
3431 ppc_ori (code, ppc_r0, ppc_r0, 0);
3432 ppc_mtlr (code, ppc_r0);
3438 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3439 /* lmf_offset is the offset from the previous stack pointer,
3440 * alloc_size is the total stack space allocated, so the offset
3441 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3442 * The pointer to the struct is put in ppc_r11 (new_lmf).
3443 * The callee-saved registers are already in the MonoLMF structure
3445 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3446 /* ppc_r3 is the result from mono_get_lmf_addr () */
3447 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3448 /* new_lmf->previous_lmf = *lmf_addr */
3449 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3450 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3451 /* *(lmf_addr) = r11 */
3452 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3453 /* save method info */
3454 ppc_load (code, ppc_r0, method);
3455 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3456 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3457 /* save the current IP */
3458 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3459 ppc_load (code, ppc_r0, 0x01010101);
3460 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3464 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3466 cfg->code_len = code - cfg->native_code;
3467 g_assert (cfg->code_len < cfg->code_size);
3474 mono_arch_emit_epilog (MonoCompile *cfg)
3476 MonoJumpInfo *patch_info;
3477 MonoMethod *method = cfg->method;
3479 int max_epilog_size = 16 + 20*4;
3482 if (cfg->method->save_lmf)
3483 max_epilog_size += 128;
3485 if (mono_jit_trace_calls != NULL)
3486 max_epilog_size += 50;
3488 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3489 max_epilog_size += 50;
3491 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3492 cfg->code_size *= 2;
3493 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3494 mono_jit_stats.code_reallocs++;
3498 * Keep in sync with OP_JMP
3500 code = cfg->native_code + cfg->code_len;
3502 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3503 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3507 if (method->save_lmf) {
3509 pos += sizeof (MonoLMF);
3511 /* save the frame reg in r8 */
3512 ppc_mr (code, ppc_r8, cfg->frame_reg);
3513 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3514 /* r5 = previous_lmf */
3515 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3517 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3518 /* *(lmf_addr) = previous_lmf */
3519 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3520 /* FIXME: speedup: there is no actual need to restore the registers if
3521 * we didn't actually change them (idea from Zoltan).
3524 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3526 /*for (i = 14; i < 32; i++) {
3527 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3529 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3530 /* use the saved copy of the frame reg in r8 */
3531 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3532 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3533 ppc_mtlr (code, ppc_r0);
3535 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3537 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3538 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3539 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3541 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3542 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3544 ppc_mtlr (code, ppc_r0);
3546 if (ppc_is_imm16 (cfg->stack_usage)) {
3547 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3549 ppc_load (code, ppc_r11, cfg->stack_usage);
3550 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3553 /*for (i = 31; i >= 14; --i) {
3554 if (cfg->used_float_regs & (1 << i)) {
3555 pos += sizeof (double);
3556 ppc_lfd (code, i, -pos, ppc_sp);
3559 for (i = 31; i >= 13; --i) {
3560 if (cfg->used_int_regs & (1 << i)) {
3561 pos += sizeof (gulong);
3562 ppc_lwz (code, i, -pos, ppc_sp);
3568 cfg->code_len = code - cfg->native_code;
3570 g_assert (cfg->code_len < cfg->code_size);
3574 /* remove once throw_exception_by_name is eliminated */
3576 exception_id_by_name (const char *name)
3578 if (strcmp (name, "IndexOutOfRangeException") == 0)
3579 return MONO_EXC_INDEX_OUT_OF_RANGE;
3580 if (strcmp (name, "OverflowException") == 0)
3581 return MONO_EXC_OVERFLOW;
3582 if (strcmp (name, "ArithmeticException") == 0)
3583 return MONO_EXC_ARITHMETIC;
3584 if (strcmp (name, "DivideByZeroException") == 0)
3585 return MONO_EXC_DIVIDE_BY_ZERO;
3586 if (strcmp (name, "InvalidCastException") == 0)
3587 return MONO_EXC_INVALID_CAST;
3588 if (strcmp (name, "NullReferenceException") == 0)
3589 return MONO_EXC_NULL_REF;
3590 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3591 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3592 g_error ("Unknown intrinsic exception %s\n", name);
3597 mono_arch_emit_exceptions (MonoCompile *cfg)
3599 MonoJumpInfo *patch_info;
3602 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3603 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3606 int max_epilog_size = 50;
3608 /* count the number of exception infos */
3611 * make sure we have enough space for exceptions
3612 * 24 is the simulated call to throw_exception_by_name
3614 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3615 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3616 i = exception_id_by_name (patch_info->data.target);
3617 if (!exc_throw_found [i]) {
3618 max_epilog_size += 24;
3619 exc_throw_found [i] = TRUE;
3621 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3622 max_epilog_size += 12;
3623 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3624 MonoOvfJump *ovfj = patch_info->data.target;
3625 i = exception_id_by_name (ovfj->data.exception);
3626 if (!exc_throw_found [i]) {
3627 max_epilog_size += 24;
3628 exc_throw_found [i] = TRUE;
3630 max_epilog_size += 8;
3634 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3635 cfg->code_size *= 2;
3636 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3637 mono_jit_stats.code_reallocs++;
3640 code = cfg->native_code + cfg->code_len;
3642 /* add code to raise exceptions */
3643 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3644 switch (patch_info->type) {
3645 case MONO_PATCH_INFO_BB_OVF: {
3646 MonoOvfJump *ovfj = patch_info->data.target;
3647 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3648 /* patch the initial jump */
3649 ppc_patch (ip, code);
3650 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3652 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3653 /* jump back to the true target */
3655 ip = ovfj->data.bb->native_offset + cfg->native_code;
3656 ppc_patch (code - 4, ip);
3659 case MONO_PATCH_INFO_EXC_OVF: {
3660 MonoOvfJump *ovfj = patch_info->data.target;
3661 MonoJumpInfo *newji;
3662 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3663 unsigned char *bcl = code;
3664 /* patch the initial jump: we arrived here with a call */
3665 ppc_patch (ip, code);
3666 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3668 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3669 /* patch the conditional jump to the right handler */
3670 /* make it processed next */
3671 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3672 newji->type = MONO_PATCH_INFO_EXC;
3673 newji->ip.i = bcl - cfg->native_code;
3674 newji->data.target = ovfj->data.exception;
3675 newji->next = patch_info->next;
3676 patch_info->next = newji;
3679 case MONO_PATCH_INFO_EXC: {
3680 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3681 i = exception_id_by_name (patch_info->data.target);
3682 if (exc_throw_pos [i]) {
3683 ppc_patch (ip, exc_throw_pos [i]);
3684 patch_info->type = MONO_PATCH_INFO_NONE;
3687 exc_throw_pos [i] = code;
3689 ppc_patch (ip, code);
3690 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3691 ppc_load (code, ppc_r3, patch_info->data.target);
3692 /* we got here from a conditional call, so the calling ip is set in lr already */
3693 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3694 patch_info->data.name = "mono_arch_throw_exception_by_name";
3695 patch_info->ip.i = code - cfg->native_code;
3696 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3697 ppc_lis (code, ppc_r0, 0);
3698 ppc_ori (code, ppc_r0, ppc_r0, 0);
3699 ppc_mtctr (code, ppc_r0);
3700 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3712 cfg->code_len = code - cfg->native_code;
3714 g_assert (cfg->code_len < cfg->code_size);
3719 try_offset_access (void *value, guint32 idx)
3721 register void* me __asm__ ("r2");
3722 void ***p = (void***)((char*)me + 284);
3723 int idx1 = idx / 32;
3724 int idx2 = idx % 32;
3727 if (value != p[idx1][idx2])
3733 setup_tls_access (void)
3736 guint32 *ins, *code;
3737 guint32 cmplwi_1023, li_0x48, blr_ins;
3738 if (tls_mode == TLS_MODE_FAILED)
3741 if (g_getenv ("MONO_NO_TLS")) {
3742 tls_mode = TLS_MODE_FAILED;
3746 if (tls_mode == TLS_MODE_DETECT) {
3747 ins = (guint32*)pthread_getspecific;
3748 /* uncond branch to the real method */
3749 if ((*ins >> 26) == 18) {
3751 val = (*ins & ~3) << 6;
3755 ins = (guint32*)val;
3757 ins = (guint32*) ((char*)ins + val);
3760 code = &cmplwi_1023;
3761 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3763 ppc_li (code, ppc_r4, 0x48);
3766 if (*ins == cmplwi_1023) {
3767 int found_lwz_284 = 0;
3768 for (ptk = 0; ptk < 20; ++ptk) {
3770 if (!*ins || *ins == blr_ins)
3772 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3777 if (!found_lwz_284) {
3778 tls_mode = TLS_MODE_FAILED;
3781 tls_mode = TLS_MODE_LTHREADS;
3782 } else if (*ins == li_0x48) {
3784 /* uncond branch to the real method */
3785 if ((*ins >> 26) == 18) {
3787 val = (*ins & ~3) << 6;
3791 ins = (guint32*)val;
3793 ins = (guint32*) ((char*)ins + val);
3796 ppc_li (code, ppc_r0, 0x7FF2);
3797 if (ins [1] == val) {
3798 /* Darwin on G4, implement */
3799 tls_mode = TLS_MODE_FAILED;
3803 ppc_mfspr (code, ppc_r3, 104);
3804 if (ins [1] != val) {
3805 tls_mode = TLS_MODE_FAILED;
3808 tls_mode = TLS_MODE_DARWIN_G5;
3811 tls_mode = TLS_MODE_FAILED;
3815 tls_mode = TLS_MODE_FAILED;
3819 if (monodomain_key == -1) {
3820 ptk = mono_domain_get_tls_key ();
3822 ptk = mono_pthread_key_for_tls (ptk);
3824 monodomain_key = ptk;
3828 if (lmf_pthread_key == -1) {
3829 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3831 /*g_print ("MonoLMF at: %d\n", ptk);*/
3832 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3833 init_tls_failed = 1;
3836 lmf_pthread_key = ptk;
3839 if (monothread_key == -1) {
3840 ptk = mono_thread_get_tls_key ();
3842 ptk = mono_pthread_key_for_tls (ptk);
3844 monothread_key = ptk;
3845 /*g_print ("thread inited: %d\n", ptk);*/
3848 /*g_print ("thread not inited yet %d\n", ptk);*/
3854 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3856 setup_tls_access ();
3860 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3865 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3867 int this_dreg = ppc_r3;
3872 /* add the this argument */
3873 if (this_reg != -1) {
3875 MONO_INST_NEW (cfg, this, OP_MOVE);
3876 this->type = this_type;
3877 this->sreg1 = this_reg;
3878 this->dreg = mono_regstate_next_int (cfg->rs);
3879 mono_bblock_add_inst (cfg->cbb, this);
3880 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3885 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3886 vtarg->type = STACK_MP;
3887 vtarg->sreg1 = vt_reg;
3888 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3889 mono_bblock_add_inst (cfg->cbb, vtarg);
3890 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3894 #ifdef MONO_ARCH_HAVE_IMT
3898 #define JUMP_IMM_SIZE 12
3899 #define ENABLE_WRONG_METHOD_CHECK 0
3902 * LOCKING: called with the domain lock held
3905 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3909 guint8 *code, *start;
3911 for (i = 0; i < count; ++i) {
3912 MonoIMTCheckItem *item = imt_entries [i];
3913 if (item->is_equals) {
3914 if (item->check_target_idx) {
3915 if (!item->compare_done)
3916 item->chunk_size += CMP_SIZE;
3917 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
3919 item->chunk_size += JUMP_IMM_SIZE;
3920 #if ENABLE_WRONG_METHOD_CHECK
3921 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
3925 item->chunk_size += CMP_SIZE + BR_SIZE;
3926 imt_entries [item->check_target_idx]->compare_done = TRUE;
3928 size += item->chunk_size;
3930 /* the initial load of the vtable address */
3932 code = mono_code_manager_reserve (domain->code_mp, size);
3934 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
3935 for (i = 0; i < count; ++i) {
3936 MonoIMTCheckItem *item = imt_entries [i];
3937 item->code_target = code;
3938 if (item->is_equals) {
3939 if (item->check_target_idx) {
3940 if (!item->compare_done) {
3941 ppc_load (code, ppc_r0, (guint32)item->method);
3942 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3944 item->jmp_code = code;
3945 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3946 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3947 ppc_mtctr (code, ppc_r0);
3948 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3950 /* enable the commented code to assert on wrong method */
3951 #if ENABLE_WRONG_METHOD_CHECK
3952 ppc_load (code, ppc_r0, (guint32)item->method);
3953 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3954 item->jmp_code = code;
3955 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3957 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3958 ppc_mtctr (code, ppc_r0);
3959 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3960 #if ENABLE_WRONG_METHOD_CHECK
3961 ppc_patch (item->jmp_code, code);
3963 item->jmp_code = NULL;
3967 ppc_load (code, ppc_r0, (guint32)item->method);
3968 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3969 item->jmp_code = code;
3970 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
3973 /* patch the branches to get to the target items */
3974 for (i = 0; i < count; ++i) {
3975 MonoIMTCheckItem *item = imt_entries [i];
3976 if (item->jmp_code) {
3977 if (item->check_target_idx) {
3978 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
3983 mono_stats.imt_thunks_size += code - start;
3984 g_assert (code - start <= size);
3985 mono_arch_flush_icache (start, size);
3990 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
3992 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
3996 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
3998 return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
4003 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4005 MonoInst *ins = NULL;
4007 if (cmethod->klass == mono_defaults.thread_class &&
4008 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4009 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4011 /*if (cmethod->klass == mono_defaults.math_class) {
4012 if (strcmp (cmethod->name, "Sqrt") == 0) {
4013 MONO_INST_NEW (cfg, ins, OP_SQRT);
4014 ins->inst_i0 = args [0];
4021 mono_arch_print_tree (MonoInst *tree, int arity)
4026 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4030 setup_tls_access ();
4031 if (monodomain_key == -1)
4034 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4035 ins->inst_offset = monodomain_key;
4040 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4044 setup_tls_access ();
4045 if (monothread_key == -1)
4048 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4049 ins->inst_offset = monothread_key;