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;
1106 mono_arch_create_vars (MonoCompile *cfg)
1110 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1111 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1115 * take the arguments and generate the arch-specific
1116 * instructions to properly call the function in call.
1117 * This includes pushing, moving arguments to the right register
1119 * Issue: who does the spilling if needed, and when?
1122 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1124 MonoMethodSignature *sig;
1129 sig = call->signature;
1130 n = sig->param_count + sig->hasthis;
1132 cinfo = calculate_sizes (sig, sig->pinvoke);
1133 if (cinfo->struct_ret)
1134 call->used_iregs |= 1 << cinfo->struct_ret;
1136 for (i = 0; i < n; ++i) {
1137 ainfo = cinfo->args + i;
1138 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1140 cfg->disable_aot = TRUE;
1142 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1143 sig_arg->inst_p0 = call->signature;
1145 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1146 arg->inst_imm = cinfo->sig_cookie.offset;
1147 arg->inst_left = sig_arg;
1148 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1150 if (is_virtual && i == 0) {
1151 /* the argument will be attached to the call instrucion */
1152 in = call->args [i];
1153 call->used_iregs |= 1 << ainfo->reg;
1155 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1156 in = call->args [i];
1157 arg->cil_code = in->cil_code;
1158 arg->inst_left = in;
1159 arg->inst_call = call;
1160 arg->type = in->type;
1161 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1162 if (ainfo->regtype == RegTypeGeneral) {
1163 arg->backend.reg3 = ainfo->reg;
1164 call->used_iregs |= 1 << ainfo->reg;
1165 if (arg->type == STACK_I8)
1166 call->used_iregs |= 1 << (ainfo->reg + 1);
1167 } else if (ainfo->regtype == RegTypeStructByAddr) {
1168 if (ainfo->offset) {
1169 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1170 arg->opcode = OP_OUTARG_MEMBASE;
1171 ai->reg = ainfo->reg;
1172 ai->size = sizeof (gpointer);
1173 ai->offset = ainfo->offset;
1174 arg->backend.data = ai;
1176 arg->backend.reg3 = ainfo->reg;
1177 call->used_iregs |= 1 << ainfo->reg;
1179 } else if (ainfo->regtype == RegTypeStructByVal) {
1181 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1182 /* mark the used regs */
1183 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1184 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1186 arg->opcode = OP_OUTARG_VT;
1187 ai->reg = ainfo->reg;
1188 ai->size = ainfo->size;
1189 ai->vtsize = ainfo->vtsize;
1190 ai->offset = ainfo->offset;
1191 arg->backend.data = ai;
1192 } else if (ainfo->regtype == RegTypeBase) {
1193 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1194 arg->opcode = OP_OUTARG_MEMBASE;
1195 ai->reg = ainfo->reg;
1196 ai->size = ainfo->size;
1197 ai->offset = ainfo->offset;
1198 arg->backend.data = ai;
1199 } else if (ainfo->regtype == RegTypeFP) {
1200 arg->opcode = OP_OUTARG_R8;
1201 arg->backend.reg3 = ainfo->reg;
1202 call->used_fregs |= 1 << ainfo->reg;
1203 if (ainfo->size == 4) {
1204 arg->opcode = OP_OUTARG_R8;
1205 /* we reduce the precision */
1207 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1208 conv->inst_left = arg->inst_left;
1209 arg->inst_left = conv;*/
1212 g_assert_not_reached ();
1216 call->stack_usage = cinfo->stack_usage;
1217 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1218 cfg->flags |= MONO_CFG_HAS_CALLS;
1220 * should set more info in call, such as the stack space
1221 * used by the args that needs to be added back to esp
1229 * Allow tracing to work with this interface (with an optional argument)
1233 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1237 ppc_load (code, ppc_r3, cfg->method);
1238 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1239 ppc_load (code, ppc_r0, func);
1240 ppc_mtlr (code, ppc_r0);
1254 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1257 int save_mode = SAVE_NONE;
1259 MonoMethod *method = cfg->method;
1260 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1261 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1265 offset = code - cfg->native_code;
1266 /* we need about 16 instructions */
1267 if (offset > (cfg->code_size - 16 * 4)) {
1268 cfg->code_size *= 2;
1269 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1270 code = cfg->native_code + offset;
1274 case MONO_TYPE_VOID:
1275 /* special case string .ctor icall */
1276 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1277 save_mode = SAVE_ONE;
1279 save_mode = SAVE_NONE;
1283 save_mode = SAVE_TWO;
1287 save_mode = SAVE_FP;
1289 case MONO_TYPE_VALUETYPE:
1290 save_mode = SAVE_STRUCT;
1293 save_mode = SAVE_ONE;
1297 switch (save_mode) {
1299 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1300 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1301 if (enable_arguments) {
1302 ppc_mr (code, ppc_r5, ppc_r4);
1303 ppc_mr (code, ppc_r4, ppc_r3);
1307 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1308 if (enable_arguments) {
1309 ppc_mr (code, ppc_r4, ppc_r3);
1313 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1314 if (enable_arguments) {
1315 /* FIXME: what reg? */
1316 ppc_fmr (code, ppc_f3, ppc_f1);
1317 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1318 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1322 if (enable_arguments) {
1323 /* FIXME: get the actual address */
1324 ppc_mr (code, ppc_r4, ppc_r3);
1332 ppc_load (code, ppc_r3, cfg->method);
1333 ppc_load (code, ppc_r0, func);
1334 ppc_mtlr (code, ppc_r0);
1337 switch (save_mode) {
1339 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1340 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1343 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1346 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1356 * Conditional branches have a small offset, so if it is likely overflowed,
1357 * we do a branch to the end of the method (uncond branches have much larger
1358 * offsets) where we perform the conditional and jump back unconditionally.
1359 * It's slightly slower, since we add two uncond branches, but it's very simple
1360 * with the current patch implementation and such large methods are likely not
1361 * going to be perf critical anyway.
1366 const char *exception;
1373 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1374 if (ins->flags & MONO_INST_BRLABEL) { \
1375 if (0 && ins->inst_i0->inst_c0) { \
1376 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1378 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1379 ppc_bc (code, (b0), (b1), 0); \
1382 if (0 && ins->inst_true_bb->native_offset) { \
1383 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1385 int br_disp = ins->inst_true_bb->max_offset - offset; \
1386 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1387 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1388 ovfj->data.bb = ins->inst_true_bb; \
1389 ovfj->ip_offset = 0; \
1390 ovfj->b0_cond = (b0); \
1391 ovfj->b1_cond = (b1); \
1392 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1395 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1396 ppc_bc (code, (b0), (b1), 0); \
1401 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1403 /* emit an exception if condition is fail
1405 * We assign the extra code used to throw the implicit exceptions
1406 * to cfg->bb_exit as far as the big branch handling is concerned
1408 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1410 int br_disp = cfg->bb_exit->max_offset - offset; \
1411 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1412 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1413 ovfj->data.exception = (exc_name); \
1414 ovfj->ip_offset = code - cfg->native_code; \
1415 ovfj->b0_cond = (b0); \
1416 ovfj->b1_cond = (b1); \
1417 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1419 cfg->bb_exit->max_offset += 24; \
1421 mono_add_patch_info (cfg, code - cfg->native_code, \
1422 MONO_PATCH_INFO_EXC, exc_name); \
1423 ppc_bcl (code, (b0), (b1), 0); \
1427 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1430 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1435 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1439 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
1440 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1441 switch (ins->opcode) {
1443 /* remove unnecessary multiplication with 1 */
1444 if (ins->inst_imm == 1) {
1445 if (ins->dreg != ins->sreg1) {
1446 ins->opcode = OP_MOVE;
1452 int power2 = mono_is_power_of_two (ins->inst_imm);
1454 ins->opcode = OP_SHL_IMM;
1455 ins->inst_imm = power2;
1459 case OP_LOAD_MEMBASE:
1460 case OP_LOADI4_MEMBASE:
1462 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1463 * OP_LOAD_MEMBASE offset(basereg), reg
1465 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1466 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1467 ins->inst_basereg == last_ins->inst_destbasereg &&
1468 ins->inst_offset == last_ins->inst_offset) {
1469 if (ins->dreg == last_ins->sreg1) {
1473 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1474 ins->opcode = OP_MOVE;
1475 ins->sreg1 = last_ins->sreg1;
1479 * Note: reg1 must be different from the basereg in the second load
1480 * OP_LOAD_MEMBASE offset(basereg), reg1
1481 * OP_LOAD_MEMBASE offset(basereg), reg2
1483 * OP_LOAD_MEMBASE offset(basereg), reg1
1484 * OP_MOVE reg1, reg2
1486 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1487 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1488 ins->inst_basereg != last_ins->dreg &&
1489 ins->inst_basereg == last_ins->inst_basereg &&
1490 ins->inst_offset == last_ins->inst_offset) {
1492 if (ins->dreg == last_ins->dreg) {
1496 ins->opcode = OP_MOVE;
1497 ins->sreg1 = last_ins->dreg;
1500 //g_assert_not_reached ();
1504 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1505 * OP_LOAD_MEMBASE offset(basereg), reg
1507 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1508 * OP_ICONST reg, imm
1510 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1511 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1512 ins->inst_basereg == last_ins->inst_destbasereg &&
1513 ins->inst_offset == last_ins->inst_offset) {
1514 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1515 ins->opcode = OP_ICONST;
1516 ins->inst_c0 = last_ins->inst_imm;
1517 g_assert_not_reached (); // check this rule
1521 case OP_LOADU1_MEMBASE:
1522 case OP_LOADI1_MEMBASE:
1523 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1524 ins->inst_basereg == last_ins->inst_destbasereg &&
1525 ins->inst_offset == last_ins->inst_offset) {
1526 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1527 ins->sreg1 = last_ins->sreg1;
1530 case OP_LOADU2_MEMBASE:
1531 case OP_LOADI2_MEMBASE:
1532 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1533 ins->inst_basereg == last_ins->inst_destbasereg &&
1534 ins->inst_offset == last_ins->inst_offset) {
1535 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1536 ins->sreg1 = last_ins->sreg1;
1542 ins->opcode = OP_MOVE;
1546 if (ins->dreg == ins->sreg1) {
1551 * OP_MOVE sreg, dreg
1552 * OP_MOVE dreg, sreg
1554 if (last_ins && last_ins->opcode == OP_MOVE &&
1555 ins->sreg1 == last_ins->dreg &&
1556 ins->dreg == last_ins->sreg1) {
1566 * the branch_b0_table should maintain the order of these
1580 branch_b0_table [] = {
1595 branch_b1_table [] = {
1609 #define NEW_INS(cfg,ins,dest,op) do { \
1610 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1611 (dest)->opcode = (op); \
1612 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1616 map_to_reg_reg_op (int op)
1625 case OP_COMPARE_IMM:
1641 case OP_LOAD_MEMBASE:
1642 return OP_LOAD_MEMINDEX;
1643 case OP_LOADI4_MEMBASE:
1644 return OP_LOADI4_MEMINDEX;
1645 case OP_LOADU4_MEMBASE:
1646 return OP_LOADU4_MEMINDEX;
1647 case OP_LOADU1_MEMBASE:
1648 return OP_LOADU1_MEMINDEX;
1649 case OP_LOADI2_MEMBASE:
1650 return OP_LOADI2_MEMINDEX;
1651 case OP_LOADU2_MEMBASE:
1652 return OP_LOADU2_MEMINDEX;
1653 case OP_LOADI1_MEMBASE:
1654 return OP_LOADI1_MEMINDEX;
1655 case OP_LOADR4_MEMBASE:
1656 return OP_LOADR4_MEMINDEX;
1657 case OP_LOADR8_MEMBASE:
1658 return OP_LOADR8_MEMINDEX;
1659 case OP_STOREI1_MEMBASE_REG:
1660 return OP_STOREI1_MEMINDEX;
1661 case OP_STOREI2_MEMBASE_REG:
1662 return OP_STOREI2_MEMINDEX;
1663 case OP_STOREI4_MEMBASE_REG:
1664 return OP_STOREI4_MEMINDEX;
1665 case OP_STORE_MEMBASE_REG:
1666 return OP_STORE_MEMINDEX;
1667 case OP_STORER4_MEMBASE_REG:
1668 return OP_STORER4_MEMINDEX;
1669 case OP_STORER8_MEMBASE_REG:
1670 return OP_STORER8_MEMINDEX;
1671 case OP_STORE_MEMBASE_IMM:
1672 return OP_STORE_MEMBASE_REG;
1673 case OP_STOREI1_MEMBASE_IMM:
1674 return OP_STOREI1_MEMBASE_REG;
1675 case OP_STOREI2_MEMBASE_IMM:
1676 return OP_STOREI2_MEMBASE_REG;
1677 case OP_STOREI4_MEMBASE_IMM:
1678 return OP_STOREI4_MEMBASE_REG;
1680 g_assert_not_reached ();
1683 #define compare_opcode_is_unsigned(opcode) \
1684 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1685 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1686 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1688 * Remove from the instruction list the instructions that can't be
1689 * represented with very simple instructions with no register
1693 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1695 MonoInst *ins, *next, *temp;
1698 /* setup the virtual reg allocator */
1699 if (bb->max_vreg > cfg->rs->next_vreg)
1700 cfg->rs->next_vreg = bb->max_vreg;
1702 MONO_BB_FOR_EACH_INS (bb, ins) {
1704 switch (ins->opcode) {
1707 if (!ppc_is_imm16 (ins->inst_imm)) {
1708 NEW_INS (cfg, ins, temp, OP_ICONST);
1709 temp->inst_c0 = ins->inst_imm;
1710 temp->dreg = mono_regstate_next_int (cfg->rs);
1711 ins->sreg2 = temp->dreg;
1712 ins->opcode = map_to_reg_reg_op (ins->opcode);
1716 if (!ppc_is_imm16 (-ins->inst_imm)) {
1717 NEW_INS (cfg, ins, temp, OP_ICONST);
1718 temp->inst_c0 = ins->inst_imm;
1719 temp->dreg = mono_regstate_next_int (cfg->rs);
1720 ins->sreg2 = temp->dreg;
1721 ins->opcode = map_to_reg_reg_op (ins->opcode);
1727 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
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);
1738 NEW_INS (cfg, ins, temp, OP_ICONST);
1739 temp->inst_c0 = ins->inst_imm;
1740 temp->dreg = mono_regstate_next_int (cfg->rs);
1741 ins->sreg2 = temp->dreg;
1742 ins->opcode = map_to_reg_reg_op (ins->opcode);
1744 case OP_COMPARE_IMM:
1745 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1747 if (compare_opcode_is_unsigned (next->opcode)) {
1748 if (!ppc_is_uimm16 (ins->inst_imm)) {
1749 NEW_INS (cfg, ins, temp, OP_ICONST);
1750 temp->inst_c0 = ins->inst_imm;
1751 temp->dreg = mono_regstate_next_int (cfg->rs);
1752 ins->sreg2 = temp->dreg;
1753 ins->opcode = map_to_reg_reg_op (ins->opcode);
1756 if (!ppc_is_imm16 (ins->inst_imm)) {
1757 NEW_INS (cfg, ins, temp, OP_ICONST);
1758 temp->inst_c0 = ins->inst_imm;
1759 temp->dreg = mono_regstate_next_int (cfg->rs);
1760 ins->sreg2 = temp->dreg;
1761 ins->opcode = map_to_reg_reg_op (ins->opcode);
1766 if (ins->inst_imm == 1) {
1767 ins->opcode = OP_MOVE;
1770 if (ins->inst_imm == 0) {
1771 ins->opcode = OP_ICONST;
1775 imm = mono_is_power_of_two (ins->inst_imm);
1777 ins->opcode = OP_SHL_IMM;
1778 ins->inst_imm = imm;
1781 if (!ppc_is_imm16 (ins->inst_imm)) {
1782 NEW_INS (cfg, ins, temp, OP_ICONST);
1783 temp->inst_c0 = ins->inst_imm;
1784 temp->dreg = mono_regstate_next_int (cfg->rs);
1785 ins->sreg2 = temp->dreg;
1786 ins->opcode = map_to_reg_reg_op (ins->opcode);
1789 case OP_LOAD_MEMBASE:
1790 case OP_LOADI4_MEMBASE:
1791 case OP_LOADU4_MEMBASE:
1792 case OP_LOADI2_MEMBASE:
1793 case OP_LOADU2_MEMBASE:
1794 case OP_LOADI1_MEMBASE:
1795 case OP_LOADU1_MEMBASE:
1796 case OP_LOADR4_MEMBASE:
1797 case OP_LOADR8_MEMBASE:
1798 case OP_STORE_MEMBASE_REG:
1799 case OP_STOREI4_MEMBASE_REG:
1800 case OP_STOREI2_MEMBASE_REG:
1801 case OP_STOREI1_MEMBASE_REG:
1802 case OP_STORER4_MEMBASE_REG:
1803 case OP_STORER8_MEMBASE_REG:
1804 /* we can do two things: load the immed in a register
1805 * and use an indexed load, or see if the immed can be
1806 * represented as an ad_imm + a load with a smaller offset
1807 * that fits. We just do the first for now, optimize later.
1809 if (ppc_is_imm16 (ins->inst_offset))
1811 NEW_INS (cfg, ins, temp, OP_ICONST);
1812 temp->inst_c0 = ins->inst_offset;
1813 temp->dreg = mono_regstate_next_int (cfg->rs);
1814 ins->sreg2 = temp->dreg;
1815 ins->opcode = map_to_reg_reg_op (ins->opcode);
1817 case OP_STORE_MEMBASE_IMM:
1818 case OP_STOREI1_MEMBASE_IMM:
1819 case OP_STOREI2_MEMBASE_IMM:
1820 case OP_STOREI4_MEMBASE_IMM:
1821 NEW_INS (cfg, ins, temp, OP_ICONST);
1822 temp->inst_c0 = ins->inst_imm;
1823 temp->dreg = mono_regstate_next_int (cfg->rs);
1824 ins->sreg1 = temp->dreg;
1825 ins->opcode = map_to_reg_reg_op (ins->opcode);
1826 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1829 NEW_INS (cfg, ins, temp, OP_ICONST);
1830 temp->inst_c0 = ins->inst_p0;
1831 temp->dreg = mono_regstate_next_int (cfg->rs);
1832 ins->inst_basereg = temp->dreg;
1833 ins->inst_offset = 0;
1834 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
1835 /* make it handle the possibly big ins->inst_offset
1836 * later optimize to use lis + load_membase
1841 bb->max_vreg = cfg->rs->next_vreg;
1846 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1848 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1849 ppc_fctiwz (code, ppc_f0, sreg);
1850 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1851 ppc_lwz (code, dreg, -4, ppc_sp);
1854 ppc_andid (code, dreg, dreg, 0xff);
1856 ppc_andid (code, dreg, dreg, 0xffff);
1859 ppc_extsb (code, dreg, dreg);
1861 ppc_extsh (code, dreg, dreg);
1866 static unsigned char*
1867 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1870 int sreg = tree->sreg1;
1871 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1872 if (tree->flags & MONO_INST_INIT) {
1874 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1875 x86_push_reg (code, X86_EAX);
1878 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1879 x86_push_reg (code, X86_ECX);
1882 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1883 x86_push_reg (code, X86_EDI);
1887 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1888 if (sreg != X86_ECX)
1889 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1890 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1892 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1894 x86_prefix (code, X86_REP_PREFIX);
1897 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1898 x86_pop_reg (code, X86_EDI);
1899 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1900 x86_pop_reg (code, X86_ECX);
1901 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1902 x86_pop_reg (code, X86_EAX);
1915 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1918 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1919 PatchData *pdata = (PatchData*)user_data;
1920 guchar *code = data;
1921 guint32 *thunks = data;
1922 guint32 *endthunks = (guint32*)(code + bsize);
1926 int difflow, diffhigh;
1928 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1929 difflow = (char*)pdata->code - (char*)thunks;
1930 diffhigh = (char*)pdata->code - (char*)endthunks;
1931 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1934 templ = (guchar*)load;
1935 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1936 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1938 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1939 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1940 while (thunks < endthunks) {
1941 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1942 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1943 ppc_patch (pdata->code, (guchar*)thunks);
1944 mono_arch_flush_icache (pdata->code, 4);
1947 static int num_thunks = 0;
1949 if ((num_thunks % 20) == 0)
1950 g_print ("num_thunks lookup: %d\n", num_thunks);
1953 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1954 /* found a free slot instead: emit thunk */
1955 code = (guchar*)thunks;
1956 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1957 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1958 ppc_mtctr (code, ppc_r0);
1959 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1960 mono_arch_flush_icache ((guchar*)thunks, 16);
1962 ppc_patch (pdata->code, (guchar*)thunks);
1963 mono_arch_flush_icache (pdata->code, 4);
1966 static int num_thunks = 0;
1968 if ((num_thunks % 20) == 0)
1969 g_print ("num_thunks: %d\n", num_thunks);
1973 /* skip 16 bytes, the size of the thunk */
1977 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1983 handle_thunk (int absolute, guchar *code, guchar *target) {
1984 MonoDomain *domain = mono_domain_get ();
1988 pdata.target = target;
1989 pdata.absolute = absolute;
1992 mono_domain_lock (domain);
1993 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1996 /* this uses the first available slot */
1998 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2000 mono_domain_unlock (domain);
2002 if (pdata.found != 1)
2003 g_print ("thunk failed for %p from %p\n", target, code);
2004 g_assert (pdata.found == 1);
2008 ppc_patch (guchar *code, guchar *target)
2010 guint32 ins = *(guint32*)code;
2011 guint32 prim = ins >> 26;
2014 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2016 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2017 gint diff = target - code;
2019 if (diff <= 33554431){
2020 ins = (18 << 26) | (diff) | (ins & 1);
2021 *(guint32*)code = ins;
2025 /* diff between 0 and -33554432 */
2026 if (diff >= -33554432){
2027 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2028 *(guint32*)code = ins;
2033 if ((glong)target >= 0){
2034 if ((glong)target <= 33554431){
2035 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2036 *(guint32*)code = ins;
2040 if ((glong)target >= -33554432){
2041 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2042 *(guint32*)code = ins;
2047 handle_thunk (TRUE, code, target);
2050 g_assert_not_reached ();
2057 guint32 li = (guint32)target;
2058 ins = (ins & 0xffff0000) | (ins & 3);
2059 ovf = li & 0xffff0000;
2060 if (ovf != 0 && ovf != 0xffff0000)
2061 g_assert_not_reached ();
2064 // FIXME: assert the top bits of li are 0
2066 gint diff = target - code;
2067 ins = (ins & 0xffff0000) | (ins & 3);
2068 ovf = diff & 0xffff0000;
2069 if (ovf != 0 && ovf != 0xffff0000)
2070 g_assert_not_reached ();
2074 *(guint32*)code = ins;
2078 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2080 /* the trampoline code will try to patch the blrl, blr, bcctr */
2081 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2084 /* this is the lis/ori/mtlr/blrl sequence */
2085 seq = (guint32*)code;
2086 g_assert ((seq [0] >> 26) == 15);
2087 g_assert ((seq [1] >> 26) == 24);
2088 g_assert ((seq [2] >> 26) == 31);
2089 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2090 /* FIXME: make this thread safe */
2091 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2092 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2093 mono_arch_flush_icache (code - 8, 8);
2095 g_assert_not_reached ();
2097 // g_print ("patched with 0x%08x\n", ins);
2101 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2103 MonoInst *ins, *next;
2106 guint8 *code = cfg->native_code + cfg->code_len;
2107 guint last_offset = 0;
2110 /* we don't align basic blocks of loops on ppc */
2112 if (cfg->verbose_level > 2)
2113 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2115 cpos = bb->max_offset;
2117 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2118 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2119 //g_assert (!mono_compile_aot);
2122 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2123 /* this is not thread save, but good enough */
2124 /* fixme: howto handle overflows? */
2125 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2128 MONO_BB_FOR_EACH_INS (bb, ins) {
2129 offset = code - cfg->native_code;
2131 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2133 if (offset > (cfg->code_size - max_len - 16)) {
2134 cfg->code_size *= 2;
2135 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2136 code = cfg->native_code + offset;
2138 // if (ins->cil_code)
2139 // g_print ("cil code\n");
2140 mono_debug_record_line_number (cfg, ins, offset);
2142 switch (ins->opcode) {
2144 emit_tls_access (code, ins->dreg, ins->inst_offset);
2147 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2148 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2149 ppc_mr (code, ppc_r4, ppc_r0);
2152 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2153 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2154 ppc_mr (code, ppc_r4, ppc_r0);
2156 case OP_MEMORY_BARRIER:
2159 case OP_STOREI1_MEMBASE_REG:
2160 if (ppc_is_imm16 (ins->inst_offset)) {
2161 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2163 g_assert_not_reached ();
2166 case OP_STOREI2_MEMBASE_REG:
2167 if (ppc_is_imm16 (ins->inst_offset)) {
2168 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2170 g_assert_not_reached ();
2173 case OP_STORE_MEMBASE_REG:
2174 case OP_STOREI4_MEMBASE_REG:
2175 if (ppc_is_imm16 (ins->inst_offset)) {
2176 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2178 g_assert_not_reached ();
2181 case OP_STOREI1_MEMINDEX:
2182 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2184 case OP_STOREI2_MEMINDEX:
2185 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2187 case OP_STORE_MEMINDEX:
2188 case OP_STOREI4_MEMINDEX:
2189 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2192 g_assert_not_reached ();
2194 case OP_LOAD_MEMBASE:
2195 case OP_LOADI4_MEMBASE:
2196 case OP_LOADU4_MEMBASE:
2197 if (ppc_is_imm16 (ins->inst_offset)) {
2198 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2200 g_assert_not_reached ();
2203 case OP_LOADI1_MEMBASE:
2204 case OP_LOADU1_MEMBASE:
2205 if (ppc_is_imm16 (ins->inst_offset)) {
2206 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2208 g_assert_not_reached ();
2210 if (ins->opcode == OP_LOADI1_MEMBASE)
2211 ppc_extsb (code, ins->dreg, ins->dreg);
2213 case OP_LOADU2_MEMBASE:
2214 if (ppc_is_imm16 (ins->inst_offset)) {
2215 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2217 g_assert_not_reached ();
2220 case OP_LOADI2_MEMBASE:
2221 if (ppc_is_imm16 (ins->inst_offset)) {
2222 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2224 g_assert_not_reached ();
2227 case OP_LOAD_MEMINDEX:
2228 case OP_LOADI4_MEMINDEX:
2229 case OP_LOADU4_MEMINDEX:
2230 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2232 case OP_LOADU2_MEMINDEX:
2233 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2235 case OP_LOADI2_MEMINDEX:
2236 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2238 case OP_LOADU1_MEMINDEX:
2239 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2241 case OP_LOADI1_MEMINDEX:
2242 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2243 ppc_extsb (code, ins->dreg, ins->dreg);
2246 ppc_extsb (code, ins->dreg, ins->sreg1);
2249 ppc_extsh (code, ins->dreg, ins->sreg1);
2252 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2255 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2258 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2259 if (next && compare_opcode_is_unsigned (next->opcode))
2260 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2262 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2264 case OP_COMPARE_IMM:
2265 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2266 if (next && compare_opcode_is_unsigned (next->opcode)) {
2267 if (ppc_is_uimm16 (ins->inst_imm)) {
2268 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2270 g_assert_not_reached ();
2273 if (ppc_is_imm16 (ins->inst_imm)) {
2274 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2276 g_assert_not_reached ();
2284 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2287 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2290 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2293 if (ppc_is_imm16 (ins->inst_imm)) {
2294 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2296 g_assert_not_reached ();
2300 if (ppc_is_imm16 (ins->inst_imm)) {
2301 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2303 g_assert_not_reached ();
2307 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2309 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2310 ppc_mfspr (code, ppc_r0, ppc_xer);
2311 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2312 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2314 case CEE_ADD_OVF_UN:
2315 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2317 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2318 ppc_mfspr (code, ppc_r0, ppc_xer);
2319 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2320 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2323 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2325 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2326 ppc_mfspr (code, ppc_r0, ppc_xer);
2327 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2328 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2330 case CEE_SUB_OVF_UN:
2331 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2333 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2334 ppc_mfspr (code, ppc_r0, ppc_xer);
2335 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2336 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2338 case OP_ADD_OVF_CARRY:
2339 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2341 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2342 ppc_mfspr (code, ppc_r0, ppc_xer);
2343 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2344 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2346 case OP_ADD_OVF_UN_CARRY:
2347 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2349 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2350 ppc_mfspr (code, ppc_r0, ppc_xer);
2351 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2352 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2354 case OP_SUB_OVF_CARRY:
2355 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2357 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2358 ppc_mfspr (code, ppc_r0, ppc_xer);
2359 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2360 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2362 case OP_SUB_OVF_UN_CARRY:
2363 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2365 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2366 ppc_mfspr (code, ppc_r0, ppc_xer);
2367 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2368 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2371 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2374 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2377 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2380 // we add the negated value
2381 if (ppc_is_imm16 (-ins->inst_imm))
2382 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2384 g_assert_not_reached ();
2388 g_assert (ppc_is_imm16 (ins->inst_imm));
2389 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2392 ppc_subfze (code, ins->dreg, ins->sreg1);
2395 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2396 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2399 if (!(ins->inst_imm & 0xffff0000)) {
2400 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2401 } else if (!(ins->inst_imm & 0xffff)) {
2402 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2404 g_assert_not_reached ();
2408 guint32 *divisor_is_m1;
2409 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2411 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2412 divisor_is_m1 = code;
2413 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2414 ppc_lis (code, ppc_r0, 0x8000);
2415 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2416 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2417 ppc_patch (divisor_is_m1, code);
2418 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2420 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2421 ppc_mfspr (code, ppc_r0, ppc_xer);
2422 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2423 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2427 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2428 ppc_mfspr (code, ppc_r0, ppc_xer);
2429 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2430 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2436 g_assert_not_reached ();
2438 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2441 if (!(ins->inst_imm & 0xffff0000)) {
2442 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2443 } else if (!(ins->inst_imm & 0xffff)) {
2444 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2446 g_assert_not_reached ();
2450 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2453 if (!(ins->inst_imm & 0xffff0000)) {
2454 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2455 } else if (!(ins->inst_imm & 0xffff)) {
2456 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2458 g_assert_not_reached ();
2462 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2465 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2468 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2471 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2475 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2477 ppc_mr (code, ins->dreg, ins->sreg1);
2480 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2483 ppc_not (code, ins->dreg, ins->sreg1);
2486 ppc_neg (code, ins->dreg, ins->sreg1);
2489 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2492 if (ppc_is_imm16 (ins->inst_imm)) {
2493 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2495 g_assert_not_reached ();
2499 /* we annot use mcrxr, since it's not implemented on some processors
2500 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2502 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2503 ppc_mfspr (code, ppc_r0, ppc_xer);
2504 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2505 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2507 case CEE_MUL_OVF_UN:
2508 /* we first multiply to get the high word and compare to 0
2509 * to set the flags, then the result is discarded and then
2510 * we multiply to get the lower * bits result
2512 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2513 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2514 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2515 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2518 ppc_load (code, ins->dreg, ins->inst_c0);
2521 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2522 ppc_lis (code, ins->dreg, 0);
2523 ppc_ori (code, ins->dreg, ins->dreg, 0);
2528 ppc_mr (code, ins->dreg, ins->sreg1);
2531 int saved = ins->sreg1;
2532 if (ins->sreg1 == ppc_r3) {
2533 ppc_mr (code, ppc_r0, ins->sreg1);
2536 if (ins->sreg2 != ppc_r3)
2537 ppc_mr (code, ppc_r3, ins->sreg2);
2538 if (saved != ppc_r4)
2539 ppc_mr (code, ppc_r4, saved);
2543 ppc_fmr (code, ins->dreg, ins->sreg1);
2545 case OP_FCONV_TO_R4:
2546 ppc_frsp (code, ins->dreg, ins->sreg1);
2552 * Keep in sync with mono_arch_emit_epilog
2554 g_assert (!cfg->method->save_lmf);
2556 * Note: we can use ppc_r11 here because it is dead anyway:
2557 * we're leaving the method.
2559 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2560 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2561 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2563 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2564 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2566 ppc_mtlr (code, ppc_r0);
2568 if (ppc_is_imm16 (cfg->stack_usage)) {
2569 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2571 ppc_load (code, ppc_r11, cfg->stack_usage);
2572 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2574 if (!cfg->method->save_lmf) {
2575 /*for (i = 31; i >= 14; --i) {
2576 if (cfg->used_float_regs & (1 << i)) {
2577 pos += sizeof (double);
2578 ppc_lfd (code, i, -pos, cfg->frame_reg);
2581 for (i = 31; i >= 13; --i) {
2582 if (cfg->used_int_regs & (1 << i)) {
2583 pos += sizeof (gulong);
2584 ppc_lwz (code, i, -pos, cfg->frame_reg);
2588 /* FIXME restore from MonoLMF: though this can't happen yet */
2590 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2595 /* ensure ins->sreg1 is not NULL */
2596 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2599 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2600 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2602 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
2603 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
2605 ppc_stw (code, ppc_r0, 0, ins->sreg1);
2613 call = (MonoCallInst*)ins;
2614 if (ins->flags & MONO_INST_HAS_METHOD)
2615 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2617 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2618 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2619 ppc_lis (code, ppc_r0, 0);
2620 ppc_ori (code, ppc_r0, ppc_r0, 0);
2621 ppc_mtlr (code, ppc_r0);
2630 case OP_VOIDCALL_REG:
2632 ppc_mtlr (code, ins->sreg1);
2635 case OP_FCALL_MEMBASE:
2636 case OP_LCALL_MEMBASE:
2637 case OP_VCALL_MEMBASE:
2638 case OP_VOIDCALL_MEMBASE:
2639 case OP_CALL_MEMBASE:
2640 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2641 ppc_mtlr (code, ppc_r0);
2645 g_assert_not_reached ();
2648 guint32 * zero_loop_jump, * zero_loop_start;
2649 /* keep alignment */
2650 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2651 int area_offset = alloca_waste;
2653 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2654 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2655 /* use ctr to store the number of words to 0 if needed */
2656 if (ins->flags & MONO_INST_INIT) {
2657 /* we zero 4 bytes at a time:
2658 * we add 7 instead of 3 so that we set the counter to
2659 * at least 1, otherwise the bdnz instruction will make
2660 * it negative and iterate billions of times.
2662 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2663 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2664 ppc_mtctr (code, ppc_r0);
2666 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2667 ppc_neg (code, ppc_r11, ppc_r11);
2668 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2670 if (ins->flags & MONO_INST_INIT) {
2671 /* adjust the dest reg by -4 so we can use stwu */
2672 /* we actually adjust -8 because we let the loop
2675 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2676 ppc_li (code, ppc_r11, 0);
2677 zero_loop_start = code;
2678 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2679 zero_loop_jump = code;
2680 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2681 ppc_patch (zero_loop_jump, zero_loop_start);
2683 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2688 ppc_mr (code, ppc_r3, ins->sreg1);
2689 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2690 (gpointer)"mono_arch_throw_exception");
2691 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2692 ppc_lis (code, ppc_r0, 0);
2693 ppc_ori (code, ppc_r0, ppc_r0, 0);
2694 ppc_mtlr (code, ppc_r0);
2703 ppc_mr (code, ppc_r3, ins->sreg1);
2704 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2705 (gpointer)"mono_arch_rethrow_exception");
2706 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2707 ppc_lis (code, ppc_r0, 0);
2708 ppc_ori (code, ppc_r0, ppc_r0, 0);
2709 ppc_mtlr (code, ppc_r0);
2716 case OP_START_HANDLER:
2717 ppc_mflr (code, ppc_r0);
2718 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2719 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2721 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2722 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2726 if (ins->sreg1 != ppc_r3)
2727 ppc_mr (code, ppc_r3, ins->sreg1);
2728 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2729 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2731 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2732 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2734 ppc_mtlr (code, ppc_r0);
2738 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2739 ppc_mtlr (code, ppc_r0);
2742 case OP_CALL_HANDLER:
2743 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2747 ins->inst_c0 = code - cfg->native_code;
2750 if (ins->flags & MONO_INST_BRLABEL) {
2751 /*if (ins->inst_i0->inst_c0) {
2753 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2755 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2759 /*if (ins->inst_target_bb->native_offset) {
2761 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2763 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2769 ppc_mtctr (code, ins->sreg1);
2770 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2773 ppc_li (code, ins->dreg, 0);
2774 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2775 ppc_li (code, ins->dreg, 1);
2779 ppc_li (code, ins->dreg, 1);
2780 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2781 ppc_li (code, ins->dreg, 0);
2785 ppc_li (code, ins->dreg, 1);
2786 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2787 ppc_li (code, ins->dreg, 0);
2789 case OP_COND_EXC_EQ:
2790 case OP_COND_EXC_NE_UN:
2791 case OP_COND_EXC_LT:
2792 case OP_COND_EXC_LT_UN:
2793 case OP_COND_EXC_GT:
2794 case OP_COND_EXC_GT_UN:
2795 case OP_COND_EXC_GE:
2796 case OP_COND_EXC_GE_UN:
2797 case OP_COND_EXC_LE:
2798 case OP_COND_EXC_LE_UN:
2799 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2802 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2804 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2805 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2806 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2808 case OP_COND_EXC_OV:
2809 /*ppc_mcrxr (code, 0);
2810 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2812 case OP_COND_EXC_NC:
2813 case OP_COND_EXC_NO:
2814 g_assert_not_reached ();
2826 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2829 /* floating point opcodes */
2832 g_assert_not_reached ();
2833 case OP_STORER8_MEMBASE_REG:
2834 if (ppc_is_imm16 (ins->inst_offset)) {
2835 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2837 g_assert_not_reached ();
2840 case OP_LOADR8_MEMBASE:
2841 if (ppc_is_imm16 (ins->inst_offset)) {
2842 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2844 g_assert_not_reached ();
2847 case OP_STORER4_MEMBASE_REG:
2848 ppc_frsp (code, ins->sreg1, ins->sreg1);
2849 if (ppc_is_imm16 (ins->inst_offset)) {
2850 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2852 g_assert_not_reached ();
2855 case OP_LOADR4_MEMBASE:
2856 if (ppc_is_imm16 (ins->inst_offset)) {
2857 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2859 g_assert_not_reached ();
2862 case OP_LOADR4_MEMINDEX:
2863 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2865 case OP_LOADR8_MEMINDEX:
2866 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2868 case OP_STORER4_MEMINDEX:
2869 ppc_frsp (code, ins->sreg1, ins->sreg1);
2870 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2872 case OP_STORER8_MEMINDEX:
2873 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2876 case CEE_CONV_R4: /* FIXME: change precision */
2878 g_assert_not_reached ();
2879 case OP_FCONV_TO_I1:
2880 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2882 case OP_FCONV_TO_U1:
2883 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2885 case OP_FCONV_TO_I2:
2886 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2888 case OP_FCONV_TO_U2:
2889 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2891 case OP_FCONV_TO_I4:
2893 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2895 case OP_FCONV_TO_U4:
2897 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2899 case OP_FCONV_TO_I8:
2900 case OP_FCONV_TO_U8:
2901 g_assert_not_reached ();
2902 /* Implemented as helper calls */
2904 case OP_LCONV_TO_R_UN:
2905 g_assert_not_reached ();
2906 /* Implemented as helper calls */
2908 case OP_LCONV_TO_OVF_I: {
2909 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2910 // Check if its negative
2911 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2912 negative_branch = code;
2913 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2914 // Its positive msword == 0
2915 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2916 msword_positive_branch = code;
2917 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2919 ovf_ex_target = code;
2920 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2922 ppc_patch (negative_branch, code);
2923 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2924 msword_negative_branch = code;
2925 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2926 ppc_patch (msword_negative_branch, ovf_ex_target);
2928 ppc_patch (msword_positive_branch, code);
2929 if (ins->dreg != ins->sreg1)
2930 ppc_mr (code, ins->dreg, ins->sreg1);
2934 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2937 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2940 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2943 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2946 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2949 ppc_fneg (code, ins->dreg, ins->sreg1);
2953 g_assert_not_reached ();
2956 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2959 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2960 ppc_li (code, ins->dreg, 0);
2961 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2962 ppc_li (code, ins->dreg, 1);
2965 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2966 ppc_li (code, ins->dreg, 1);
2967 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2968 ppc_li (code, ins->dreg, 0);
2971 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2972 ppc_li (code, ins->dreg, 1);
2973 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2974 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2975 ppc_li (code, ins->dreg, 0);
2978 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2979 ppc_li (code, ins->dreg, 1);
2980 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2981 ppc_li (code, ins->dreg, 0);
2984 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2985 ppc_li (code, ins->dreg, 1);
2986 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2987 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2988 ppc_li (code, ins->dreg, 0);
2991 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2994 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2997 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2998 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3001 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3002 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3005 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3006 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3009 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3010 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3013 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3014 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3017 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3020 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3021 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3024 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3027 g_assert_not_reached ();
3028 case OP_CHECK_FINITE: {
3029 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3030 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3031 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3032 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3036 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3037 g_assert_not_reached ();
3040 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3041 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3042 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3043 g_assert_not_reached ();
3048 last_offset = offset;
3051 cfg->code_len = code - cfg->native_code;
3055 mono_arch_register_lowlevel_calls (void)
3059 #define patch_lis_ori(ip,val) do {\
3060 guint16 *__lis_ori = (guint16*)(ip); \
3061 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3062 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3066 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3068 MonoJumpInfo *patch_info;
3070 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3071 unsigned char *ip = patch_info->ip.i + code;
3072 const unsigned char *target;
3074 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3076 switch (patch_info->type) {
3077 case MONO_PATCH_INFO_IP:
3078 patch_lis_ori (ip, ip);
3080 case MONO_PATCH_INFO_METHOD_REL:
3081 g_assert_not_reached ();
3082 *((gpointer *)(ip)) = code + patch_info->data.offset;
3084 case MONO_PATCH_INFO_SWITCH: {
3085 gpointer *table = (gpointer *)patch_info->data.table->table;
3088 patch_lis_ori (ip, table);
3090 for (i = 0; i < patch_info->data.table->table_size; i++) {
3091 table [i] = (int)patch_info->data.table->table [i] + code;
3093 /* we put into the table the absolute address, no need for ppc_patch in this case */
3096 case MONO_PATCH_INFO_METHODCONST:
3097 case MONO_PATCH_INFO_CLASS:
3098 case MONO_PATCH_INFO_IMAGE:
3099 case MONO_PATCH_INFO_FIELD:
3100 case MONO_PATCH_INFO_VTABLE:
3101 case MONO_PATCH_INFO_IID:
3102 case MONO_PATCH_INFO_SFLDA:
3103 case MONO_PATCH_INFO_LDSTR:
3104 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3105 case MONO_PATCH_INFO_LDTOKEN:
3106 /* from OP_AOTCONST : lis + ori */
3107 patch_lis_ori (ip, target);
3109 case MONO_PATCH_INFO_R4:
3110 case MONO_PATCH_INFO_R8:
3111 g_assert_not_reached ();
3112 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3114 case MONO_PATCH_INFO_EXC_NAME:
3115 g_assert_not_reached ();
3116 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3118 case MONO_PATCH_INFO_NONE:
3119 case MONO_PATCH_INFO_BB_OVF:
3120 case MONO_PATCH_INFO_EXC_OVF:
3121 /* everything is dealt with at epilog output time */
3126 ppc_patch (ip, target);
3131 * Stack frame layout:
3133 * ------------------- sp
3134 * MonoLMF structure or saved registers
3135 * -------------------
3137 * -------------------
3139 * -------------------
3140 * optional 8 bytes for tracing
3141 * -------------------
3142 * param area size is cfg->param_area
3143 * -------------------
3144 * linkage area size is PPC_STACK_PARAM_OFFSET
3145 * ------------------- sp
3149 mono_arch_emit_prolog (MonoCompile *cfg)
3151 MonoMethod *method = cfg->method;
3153 MonoMethodSignature *sig;
3155 int alloc_size, pos, max_offset, i;
3161 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3164 sig = mono_method_signature (method);
3165 cfg->code_size = 256 + sig->param_count * 20;
3166 code = cfg->native_code = g_malloc (cfg->code_size);
3168 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3169 ppc_mflr (code, ppc_r0);
3170 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3173 alloc_size = cfg->stack_offset;
3176 if (!method->save_lmf) {
3177 /*for (i = 31; i >= 14; --i) {
3178 if (cfg->used_float_regs & (1 << i)) {
3179 pos += sizeof (gdouble);
3180 ppc_stfd (code, i, -pos, ppc_sp);
3183 for (i = 31; i >= 13; --i) {
3184 if (cfg->used_int_regs & (1 << i)) {
3185 pos += sizeof (gulong);
3186 ppc_stw (code, i, -pos, ppc_sp);
3191 pos += sizeof (MonoLMF);
3193 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3194 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3195 for (i = 14; i < 32; i++) {
3196 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3200 // align to PPC_STACK_ALIGNMENT bytes
3201 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3202 alloc_size += PPC_STACK_ALIGNMENT - 1;
3203 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3206 cfg->stack_usage = alloc_size;
3207 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3209 if (ppc_is_imm16 (-alloc_size)) {
3210 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3212 ppc_load (code, ppc_r11, -alloc_size);
3213 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3216 if (cfg->frame_reg != ppc_sp)
3217 ppc_mr (code, cfg->frame_reg, ppc_sp);
3219 /* compute max_offset in order to use short forward jumps
3220 * we always do it on ppc because the immediate displacement
3221 * for jumps is too small
3224 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3226 bb->max_offset = max_offset;
3228 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3231 MONO_BB_FOR_EACH_INS (bb, ins)
3232 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3235 /* load arguments allocated to register from the stack */
3238 cinfo = calculate_sizes (sig, sig->pinvoke);
3240 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3241 ArgInfo *ainfo = &cinfo->ret;
3243 if (ppc_is_imm16 (inst->inst_offset)) {
3244 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3246 ppc_load (code, ppc_r11, inst->inst_offset);
3247 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3250 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3251 ArgInfo *ainfo = cinfo->args + i;
3252 inst = cfg->args [pos];
3254 if (cfg->verbose_level > 2)
3255 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3256 if (inst->opcode == OP_REGVAR) {
3257 if (ainfo->regtype == RegTypeGeneral)
3258 ppc_mr (code, inst->dreg, ainfo->reg);
3259 else if (ainfo->regtype == RegTypeFP)
3260 ppc_fmr (code, inst->dreg, ainfo->reg);
3261 else if (ainfo->regtype == RegTypeBase) {
3262 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3263 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3265 g_assert_not_reached ();
3267 if (cfg->verbose_level > 2)
3268 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3270 /* the argument should be put on the stack: FIXME handle size != word */
3271 if (ainfo->regtype == RegTypeGeneral) {
3272 switch (ainfo->size) {
3274 if (ppc_is_imm16 (inst->inst_offset)) {
3275 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3277 ppc_load (code, ppc_r11, inst->inst_offset);
3278 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3282 if (ppc_is_imm16 (inst->inst_offset)) {
3283 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3285 ppc_load (code, ppc_r11, inst->inst_offset);
3286 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3290 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3291 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3292 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3294 ppc_load (code, ppc_r11, inst->inst_offset);
3295 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3296 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3297 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3301 if (ppc_is_imm16 (inst->inst_offset)) {
3302 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3304 ppc_load (code, ppc_r11, inst->inst_offset);
3305 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3309 } else if (ainfo->regtype == RegTypeBase) {
3310 /* load the previous stack pointer in r11 */
3311 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3312 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3313 switch (ainfo->size) {
3315 if (ppc_is_imm16 (inst->inst_offset)) {
3316 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3318 ppc_load (code, ppc_r11, inst->inst_offset);
3319 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3323 if (ppc_is_imm16 (inst->inst_offset)) {
3324 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3326 ppc_load (code, ppc_r11, inst->inst_offset);
3327 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3331 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3332 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3333 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3334 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3337 g_assert_not_reached ();
3341 if (ppc_is_imm16 (inst->inst_offset)) {
3342 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3344 ppc_load (code, ppc_r11, inst->inst_offset);
3345 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3349 } else if (ainfo->regtype == RegTypeFP) {
3350 g_assert (ppc_is_imm16 (inst->inst_offset));
3351 if (ainfo->size == 8)
3352 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3353 else if (ainfo->size == 4)
3354 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3356 g_assert_not_reached ();
3357 } else if (ainfo->regtype == RegTypeStructByVal) {
3358 int doffset = inst->inst_offset;
3362 g_assert (ppc_is_imm16 (inst->inst_offset));
3363 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3364 if (mono_class_from_mono_type (inst->inst_vtype))
3365 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3366 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3368 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3369 register. Should this case include linux/ppc?
3373 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3375 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3378 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3379 soffset += sizeof (gpointer);
3380 doffset += sizeof (gpointer);
3382 if (ainfo->vtsize) {
3383 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3384 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3385 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3386 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3388 } else if (ainfo->regtype == RegTypeStructByAddr) {
3389 /* if it was originally a RegTypeBase */
3390 if (ainfo->offset) {
3391 /* load the previous stack pointer in r11 */
3392 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3393 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3395 ppc_mr (code, ppc_r11, ainfo->reg);
3397 g_assert (ppc_is_imm16 (inst->inst_offset));
3398 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3399 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3401 g_assert_not_reached ();
3406 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3407 ppc_load (code, ppc_r3, cfg->domain);
3408 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3409 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3410 ppc_lis (code, ppc_r0, 0);
3411 ppc_ori (code, ppc_r0, ppc_r0, 0);
3412 ppc_mtlr (code, ppc_r0);
3419 if (method->save_lmf) {
3420 if (lmf_pthread_key != -1) {
3421 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3422 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3423 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3425 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3426 (gpointer)"mono_get_lmf_addr");
3427 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3428 ppc_lis (code, ppc_r0, 0);
3429 ppc_ori (code, ppc_r0, ppc_r0, 0);
3430 ppc_mtlr (code, ppc_r0);
3436 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3437 /* lmf_offset is the offset from the previous stack pointer,
3438 * alloc_size is the total stack space allocated, so the offset
3439 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3440 * The pointer to the struct is put in ppc_r11 (new_lmf).
3441 * The callee-saved registers are already in the MonoLMF structure
3443 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3444 /* ppc_r3 is the result from mono_get_lmf_addr () */
3445 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3446 /* new_lmf->previous_lmf = *lmf_addr */
3447 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3448 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3449 /* *(lmf_addr) = r11 */
3450 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3451 /* save method info */
3452 ppc_load (code, ppc_r0, method);
3453 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3454 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3455 /* save the current IP */
3456 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3457 ppc_load (code, ppc_r0, 0x01010101);
3458 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3462 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3464 cfg->code_len = code - cfg->native_code;
3465 g_assert (cfg->code_len < cfg->code_size);
3472 mono_arch_emit_epilog (MonoCompile *cfg)
3474 MonoJumpInfo *patch_info;
3475 MonoMethod *method = cfg->method;
3477 int max_epilog_size = 16 + 20*4;
3480 if (cfg->method->save_lmf)
3481 max_epilog_size += 128;
3483 if (mono_jit_trace_calls != NULL)
3484 max_epilog_size += 50;
3486 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3487 max_epilog_size += 50;
3489 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3490 cfg->code_size *= 2;
3491 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3492 mono_jit_stats.code_reallocs++;
3496 * Keep in sync with OP_JMP
3498 code = cfg->native_code + cfg->code_len;
3500 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3501 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3505 if (method->save_lmf) {
3507 pos += sizeof (MonoLMF);
3509 /* save the frame reg in r8 */
3510 ppc_mr (code, ppc_r8, cfg->frame_reg);
3511 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3512 /* r5 = previous_lmf */
3513 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3515 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3516 /* *(lmf_addr) = previous_lmf */
3517 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3518 /* FIXME: speedup: there is no actual need to restore the registers if
3519 * we didn't actually change them (idea from Zoltan).
3522 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3524 /*for (i = 14; i < 32; i++) {
3525 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3527 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3528 /* use the saved copy of the frame reg in r8 */
3529 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3530 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3531 ppc_mtlr (code, ppc_r0);
3533 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3535 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3536 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3537 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3539 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3540 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3542 ppc_mtlr (code, ppc_r0);
3544 if (ppc_is_imm16 (cfg->stack_usage)) {
3545 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3547 ppc_load (code, ppc_r11, cfg->stack_usage);
3548 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3551 /*for (i = 31; i >= 14; --i) {
3552 if (cfg->used_float_regs & (1 << i)) {
3553 pos += sizeof (double);
3554 ppc_lfd (code, i, -pos, ppc_sp);
3557 for (i = 31; i >= 13; --i) {
3558 if (cfg->used_int_regs & (1 << i)) {
3559 pos += sizeof (gulong);
3560 ppc_lwz (code, i, -pos, ppc_sp);
3566 cfg->code_len = code - cfg->native_code;
3568 g_assert (cfg->code_len < cfg->code_size);
3572 /* remove once throw_exception_by_name is eliminated */
3574 exception_id_by_name (const char *name)
3576 if (strcmp (name, "IndexOutOfRangeException") == 0)
3577 return MONO_EXC_INDEX_OUT_OF_RANGE;
3578 if (strcmp (name, "OverflowException") == 0)
3579 return MONO_EXC_OVERFLOW;
3580 if (strcmp (name, "ArithmeticException") == 0)
3581 return MONO_EXC_ARITHMETIC;
3582 if (strcmp (name, "DivideByZeroException") == 0)
3583 return MONO_EXC_DIVIDE_BY_ZERO;
3584 if (strcmp (name, "InvalidCastException") == 0)
3585 return MONO_EXC_INVALID_CAST;
3586 if (strcmp (name, "NullReferenceException") == 0)
3587 return MONO_EXC_NULL_REF;
3588 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3589 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3590 g_error ("Unknown intrinsic exception %s\n", name);
3595 mono_arch_emit_exceptions (MonoCompile *cfg)
3597 MonoJumpInfo *patch_info;
3600 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3601 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3604 int max_epilog_size = 50;
3606 /* count the number of exception infos */
3609 * make sure we have enough space for exceptions
3610 * 24 is the simulated call to throw_exception_by_name
3612 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3613 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3614 i = exception_id_by_name (patch_info->data.target);
3615 if (!exc_throw_found [i]) {
3616 max_epilog_size += 24;
3617 exc_throw_found [i] = TRUE;
3619 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3620 max_epilog_size += 12;
3621 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3622 MonoOvfJump *ovfj = patch_info->data.target;
3623 i = exception_id_by_name (ovfj->data.exception);
3624 if (!exc_throw_found [i]) {
3625 max_epilog_size += 24;
3626 exc_throw_found [i] = TRUE;
3628 max_epilog_size += 8;
3632 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3633 cfg->code_size *= 2;
3634 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3635 mono_jit_stats.code_reallocs++;
3638 code = cfg->native_code + cfg->code_len;
3640 /* add code to raise exceptions */
3641 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3642 switch (patch_info->type) {
3643 case MONO_PATCH_INFO_BB_OVF: {
3644 MonoOvfJump *ovfj = patch_info->data.target;
3645 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3646 /* patch the initial jump */
3647 ppc_patch (ip, code);
3648 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3650 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3651 /* jump back to the true target */
3653 ip = ovfj->data.bb->native_offset + cfg->native_code;
3654 ppc_patch (code - 4, ip);
3657 case MONO_PATCH_INFO_EXC_OVF: {
3658 MonoOvfJump *ovfj = patch_info->data.target;
3659 MonoJumpInfo *newji;
3660 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3661 unsigned char *bcl = code;
3662 /* patch the initial jump: we arrived here with a call */
3663 ppc_patch (ip, code);
3664 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3666 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3667 /* patch the conditional jump to the right handler */
3668 /* make it processed next */
3669 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3670 newji->type = MONO_PATCH_INFO_EXC;
3671 newji->ip.i = bcl - cfg->native_code;
3672 newji->data.target = ovfj->data.exception;
3673 newji->next = patch_info->next;
3674 patch_info->next = newji;
3677 case MONO_PATCH_INFO_EXC: {
3678 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3679 i = exception_id_by_name (patch_info->data.target);
3680 if (exc_throw_pos [i]) {
3681 ppc_patch (ip, exc_throw_pos [i]);
3682 patch_info->type = MONO_PATCH_INFO_NONE;
3685 exc_throw_pos [i] = code;
3687 ppc_patch (ip, code);
3688 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3689 ppc_load (code, ppc_r3, patch_info->data.target);
3690 /* we got here from a conditional call, so the calling ip is set in lr already */
3691 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3692 patch_info->data.name = "mono_arch_throw_exception_by_name";
3693 patch_info->ip.i = code - cfg->native_code;
3694 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3695 ppc_lis (code, ppc_r0, 0);
3696 ppc_ori (code, ppc_r0, ppc_r0, 0);
3697 ppc_mtctr (code, ppc_r0);
3698 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3710 cfg->code_len = code - cfg->native_code;
3712 g_assert (cfg->code_len < cfg->code_size);
3717 try_offset_access (void *value, guint32 idx)
3719 register void* me __asm__ ("r2");
3720 void ***p = (void***)((char*)me + 284);
3721 int idx1 = idx / 32;
3722 int idx2 = idx % 32;
3725 if (value != p[idx1][idx2])
3731 setup_tls_access (void)
3734 guint32 *ins, *code;
3735 guint32 cmplwi_1023, li_0x48, blr_ins;
3736 if (tls_mode == TLS_MODE_FAILED)
3739 if (g_getenv ("MONO_NO_TLS")) {
3740 tls_mode = TLS_MODE_FAILED;
3744 if (tls_mode == TLS_MODE_DETECT) {
3745 ins = (guint32*)pthread_getspecific;
3746 /* uncond branch to the real method */
3747 if ((*ins >> 26) == 18) {
3749 val = (*ins & ~3) << 6;
3753 ins = (guint32*)val;
3755 ins = (guint32*) ((char*)ins + val);
3758 code = &cmplwi_1023;
3759 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3761 ppc_li (code, ppc_r4, 0x48);
3764 if (*ins == cmplwi_1023) {
3765 int found_lwz_284 = 0;
3766 for (ptk = 0; ptk < 20; ++ptk) {
3768 if (!*ins || *ins == blr_ins)
3770 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3775 if (!found_lwz_284) {
3776 tls_mode = TLS_MODE_FAILED;
3779 tls_mode = TLS_MODE_LTHREADS;
3780 } else if (*ins == li_0x48) {
3782 /* uncond branch to the real method */
3783 if ((*ins >> 26) == 18) {
3785 val = (*ins & ~3) << 6;
3789 ins = (guint32*)val;
3791 ins = (guint32*) ((char*)ins + val);
3794 ppc_li (code, ppc_r0, 0x7FF2);
3795 if (ins [1] == val) {
3796 /* Darwin on G4, implement */
3797 tls_mode = TLS_MODE_FAILED;
3801 ppc_mfspr (code, ppc_r3, 104);
3802 if (ins [1] != val) {
3803 tls_mode = TLS_MODE_FAILED;
3806 tls_mode = TLS_MODE_DARWIN_G5;
3809 tls_mode = TLS_MODE_FAILED;
3813 tls_mode = TLS_MODE_FAILED;
3817 if (monodomain_key == -1) {
3818 ptk = mono_domain_get_tls_key ();
3820 ptk = mono_pthread_key_for_tls (ptk);
3822 monodomain_key = ptk;
3826 if (lmf_pthread_key == -1) {
3827 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3829 /*g_print ("MonoLMF at: %d\n", ptk);*/
3830 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3831 init_tls_failed = 1;
3834 lmf_pthread_key = ptk;
3837 if (monothread_key == -1) {
3838 ptk = mono_thread_get_tls_key ();
3840 ptk = mono_pthread_key_for_tls (ptk);
3842 monothread_key = ptk;
3843 /*g_print ("thread inited: %d\n", ptk);*/
3846 /*g_print ("thread not inited yet %d\n", ptk);*/
3852 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3854 setup_tls_access ();
3858 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3863 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3865 int this_dreg = ppc_r3;
3870 /* add the this argument */
3871 if (this_reg != -1) {
3873 MONO_INST_NEW (cfg, this, OP_MOVE);
3874 this->type = this_type;
3875 this->sreg1 = this_reg;
3876 this->dreg = mono_regstate_next_int (cfg->rs);
3877 mono_bblock_add_inst (cfg->cbb, this);
3878 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3883 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3884 vtarg->type = STACK_MP;
3885 vtarg->sreg1 = vt_reg;
3886 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3887 mono_bblock_add_inst (cfg->cbb, vtarg);
3888 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3892 #ifdef MONO_ARCH_HAVE_IMT
3896 #define JUMP_IMM_SIZE 12
3897 #define ENABLE_WRONG_METHOD_CHECK 0
3900 * LOCKING: called with the domain lock held
3903 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3907 guint8 *code, *start;
3909 for (i = 0; i < count; ++i) {
3910 MonoIMTCheckItem *item = imt_entries [i];
3911 if (item->is_equals) {
3912 if (item->check_target_idx) {
3913 if (!item->compare_done)
3914 item->chunk_size += CMP_SIZE;
3915 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
3917 item->chunk_size += JUMP_IMM_SIZE;
3918 #if ENABLE_WRONG_METHOD_CHECK
3919 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
3923 item->chunk_size += CMP_SIZE + BR_SIZE;
3924 imt_entries [item->check_target_idx]->compare_done = TRUE;
3926 size += item->chunk_size;
3928 /* the initial load of the vtable address */
3930 code = mono_code_manager_reserve (domain->code_mp, size);
3932 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
3933 for (i = 0; i < count; ++i) {
3934 MonoIMTCheckItem *item = imt_entries [i];
3935 item->code_target = code;
3936 if (item->is_equals) {
3937 if (item->check_target_idx) {
3938 if (!item->compare_done) {
3939 ppc_load (code, ppc_r0, (guint32)item->method);
3940 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3942 item->jmp_code = code;
3943 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3944 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3945 ppc_mtctr (code, ppc_r0);
3946 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3948 /* enable the commented code to assert on wrong method */
3949 #if ENABLE_WRONG_METHOD_CHECK
3950 ppc_load (code, ppc_r0, (guint32)item->method);
3951 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3952 item->jmp_code = code;
3953 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3955 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3956 ppc_mtctr (code, ppc_r0);
3957 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3958 #if ENABLE_WRONG_METHOD_CHECK
3959 ppc_patch (item->jmp_code, code);
3961 item->jmp_code = NULL;
3965 ppc_load (code, ppc_r0, (guint32)item->method);
3966 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3967 item->jmp_code = code;
3968 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
3971 /* patch the branches to get to the target items */
3972 for (i = 0; i < count; ++i) {
3973 MonoIMTCheckItem *item = imt_entries [i];
3974 if (item->jmp_code) {
3975 if (item->check_target_idx) {
3976 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
3981 mono_stats.imt_thunks_size += code - start;
3982 g_assert (code - start <= size);
3983 mono_arch_flush_icache (start, size);
3988 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
3990 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
3994 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
3996 return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
4001 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4003 MonoInst *ins = NULL;
4005 /*if (cmethod->klass == mono_defaults.math_class) {
4006 if (strcmp (cmethod->name, "Sqrt") == 0) {
4007 MONO_INST_NEW (cfg, ins, OP_SQRT);
4008 ins->inst_i0 = args [0];
4015 mono_arch_print_tree (MonoInst *tree, int arity)
4020 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4024 setup_tls_access ();
4025 if (monodomain_key == -1)
4028 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4029 ins->inst_offset = monodomain_key;
4034 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4038 setup_tls_access ();
4039 if (monothread_key == -1)
4042 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4043 ins->inst_offset = monothread_key;
4048 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4050 /* FIXME: implement */
4051 g_assert_not_reached ();