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 (code, 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 (code, 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");
561 #define NOT_IMPLEMENTED(x) \
562 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
565 #define ALWAYS_ON_STACK(s) s
566 #define FP_ALSO_IN_REG(s) s
568 #define ALWAYS_ON_STACK(s)
569 #define FP_ALSO_IN_REG(s)
570 #define ALIGN_DOUBLES
583 guint32 vtsize; /* in param area */
585 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
586 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
601 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
604 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
605 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
606 ainfo->reg = ppc_sp; /* in the caller */
607 ainfo->regtype = RegTypeBase;
610 ALWAYS_ON_STACK (*stack_size += 4);
614 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
616 //*stack_size += (*stack_size % 8);
618 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
619 ainfo->reg = ppc_sp; /* in the caller */
620 ainfo->regtype = RegTypeBase;
627 ALWAYS_ON_STACK (*stack_size += 8);
636 /* size == 4 is checked already */
638 has_only_a_r4_field (MonoClass *klass)
643 while ((f = mono_class_get_fields (klass, &iter))) {
644 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
645 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
655 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
658 int n = sig->hasthis + sig->param_count;
660 guint32 stack_size = 0;
661 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
663 fr = PPC_FIRST_FPARG_REG;
664 gr = PPC_FIRST_ARG_REG;
666 /* FIXME: handle returning a struct */
667 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
668 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
669 cinfo->struct_ret = PPC_FIRST_ARG_REG;
674 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
677 DEBUG(printf("params: %d\n", sig->param_count));
678 for (i = 0; i < sig->param_count; ++i) {
679 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
680 /* Prevent implicit arguments and sig_cookie from
681 being passed in registers */
682 gr = PPC_LAST_ARG_REG + 1;
683 /* Emit the signature cookie just before the implicit arguments */
684 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
686 DEBUG(printf("param %d: ", i));
687 if (sig->params [i]->byref) {
688 DEBUG(printf("byref\n"));
689 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
693 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
694 switch (simpletype) {
695 case MONO_TYPE_BOOLEAN:
698 cinfo->args [n].size = 1;
699 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
705 cinfo->args [n].size = 2;
706 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
711 cinfo->args [n].size = 4;
712 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
718 case MONO_TYPE_FNPTR:
719 case MONO_TYPE_CLASS:
720 case MONO_TYPE_OBJECT:
721 case MONO_TYPE_STRING:
722 case MONO_TYPE_SZARRAY:
723 case MONO_TYPE_ARRAY:
724 cinfo->args [n].size = sizeof (gpointer);
725 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
728 case MONO_TYPE_GENERICINST:
729 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
730 cinfo->args [n].size = sizeof (gpointer);
731 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
736 case MONO_TYPE_VALUETYPE: {
739 klass = mono_class_from_mono_type (sig->params [i]);
741 size = mono_class_native_size (klass, NULL);
743 size = mono_class_value_size (klass, NULL);
745 if (size == 4 && has_only_a_r4_field (klass)) {
746 cinfo->args [n].size = 4;
748 /* It was 7, now it is 8 in LinuxPPC */
749 if (fr <= PPC_LAST_FPARG_REG) {
750 cinfo->args [n].regtype = RegTypeFP;
751 cinfo->args [n].reg = fr;
753 FP_ALSO_IN_REG (gr ++);
754 ALWAYS_ON_STACK (stack_size += 4);
756 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
757 cinfo->args [n].regtype = RegTypeBase;
758 cinfo->args [n].reg = ppc_sp; /* in the caller*/
765 DEBUG(printf ("load %d bytes struct\n",
766 mono_class_native_size (sig->params [i]->data.klass, NULL)));
767 #if PPC_PASS_STRUCTS_BY_VALUE
769 int align_size = size;
771 align_size += (sizeof (gpointer) - 1);
772 align_size &= ~(sizeof (gpointer) - 1);
773 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
774 cinfo->args [n].regtype = RegTypeStructByVal;
775 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
776 cinfo->args [n].size = 0;
777 cinfo->args [n].vtsize = nwords;
779 int rest = PPC_LAST_ARG_REG - gr + 1;
780 int n_in_regs = rest >= nwords? nwords: rest;
781 cinfo->args [n].size = n_in_regs;
782 cinfo->args [n].vtsize = nwords - n_in_regs;
783 cinfo->args [n].reg = gr;
786 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
787 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
788 stack_size += nwords * sizeof (gpointer);
791 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
792 cinfo->args [n].regtype = RegTypeStructByAddr;
793 cinfo->args [n].vtsize = size;
798 case MONO_TYPE_TYPEDBYREF: {
799 int size = sizeof (MonoTypedRef);
800 /* keep in sync or merge with the valuetype case */
801 #if PPC_PASS_STRUCTS_BY_VALUE
803 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
804 cinfo->args [n].regtype = RegTypeStructByVal;
805 if (gr <= PPC_LAST_ARG_REG) {
806 int rest = PPC_LAST_ARG_REG - gr + 1;
807 int n_in_regs = rest >= nwords? nwords: rest;
808 cinfo->args [n].size = n_in_regs;
809 cinfo->args [n].vtsize = nwords - n_in_regs;
810 cinfo->args [n].reg = gr;
813 cinfo->args [n].size = 0;
814 cinfo->args [n].vtsize = nwords;
816 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
817 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
818 stack_size += nwords * sizeof (gpointer);
821 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
822 cinfo->args [n].regtype = RegTypeStructByAddr;
823 cinfo->args [n].vtsize = size;
830 cinfo->args [n].size = 8;
831 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
835 cinfo->args [n].size = 4;
837 /* It was 7, now it is 8 in LinuxPPC */
838 if (fr <= PPC_LAST_FPARG_REG) {
839 cinfo->args [n].regtype = RegTypeFP;
840 cinfo->args [n].reg = fr;
842 FP_ALSO_IN_REG (gr ++);
843 ALWAYS_ON_STACK (stack_size += 4);
845 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
846 cinfo->args [n].regtype = RegTypeBase;
847 cinfo->args [n].reg = ppc_sp; /* in the caller*/
853 cinfo->args [n].size = 8;
854 /* It was 7, now it is 8 in LinuxPPC */
855 if (fr <= PPC_LAST_FPARG_REG) {
856 cinfo->args [n].regtype = RegTypeFP;
857 cinfo->args [n].reg = fr;
859 FP_ALSO_IN_REG (gr += 2);
860 ALWAYS_ON_STACK (stack_size += 8);
862 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
863 cinfo->args [n].regtype = RegTypeBase;
864 cinfo->args [n].reg = ppc_sp; /* in the caller*/
870 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
875 simpletype = mono_type_get_underlying_type (sig->ret)->type;
876 switch (simpletype) {
877 case MONO_TYPE_BOOLEAN:
888 case MONO_TYPE_FNPTR:
889 case MONO_TYPE_CLASS:
890 case MONO_TYPE_OBJECT:
891 case MONO_TYPE_SZARRAY:
892 case MONO_TYPE_ARRAY:
893 case MONO_TYPE_STRING:
894 cinfo->ret.reg = ppc_r3;
898 cinfo->ret.reg = ppc_r3;
902 cinfo->ret.reg = ppc_f1;
903 cinfo->ret.regtype = RegTypeFP;
905 case MONO_TYPE_GENERICINST:
906 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
907 cinfo->ret.reg = ppc_r3;
911 case MONO_TYPE_VALUETYPE:
913 case MONO_TYPE_TYPEDBYREF:
917 g_error ("Can't handle as return value 0x%x", sig->ret->type);
921 /* align stack size to 16 */
922 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
923 stack_size = (stack_size + 15) & ~15;
925 cinfo->stack_usage = stack_size;
931 * Set var information according to the calling convention. ppc version.
932 * The locals var stuff should most likely be split in another method.
935 mono_arch_allocate_vars (MonoCompile *m)
937 MonoMethodSignature *sig;
938 MonoMethodHeader *header;
940 int i, offset, size, align, curinst;
941 int frame_reg = ppc_sp;
943 m->flags |= MONO_CFG_HAS_SPILLUP;
945 /* allow room for the vararg method args: void* and long/double */
946 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
947 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
948 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
949 * call convs needs to be handled this way.
951 if (m->flags & MONO_CFG_HAS_VARARGS)
952 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
953 /* gtk-sharp and other broken code will dllimport vararg functions even with
954 * non-varargs signatures. Since there is little hope people will get this right
955 * we assume they won't.
957 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
958 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
960 header = mono_method_get_header (m->method);
963 * We use the frame register also for any method that has
964 * exception clauses. This way, when the handlers are called,
965 * the code will reference local variables using the frame reg instead of
966 * the stack pointer: if we had to restore the stack pointer, we'd
967 * corrupt the method frames that are already on the stack (since
968 * filters get called before stack unwinding happens) when the filter
969 * code would call any method (this also applies to finally etc.).
971 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
973 m->frame_reg = frame_reg;
974 if (frame_reg != ppc_sp) {
975 m->used_int_regs |= 1 << frame_reg;
978 sig = mono_method_signature (m->method);
982 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
983 m->ret->opcode = OP_REGVAR;
984 m->ret->inst_c0 = ppc_r3;
986 /* FIXME: handle long and FP values */
987 switch (mono_type_get_underlying_type (sig->ret)->type) {
991 m->ret->opcode = OP_REGVAR;
992 m->ret->inst_c0 = ppc_r3;
996 /* local vars are at a positive offset from the stack pointer */
998 * also note that if the function uses alloca, we use ppc_r31
999 * to point at the local variables.
1001 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1002 /* align the offset to 16 bytes: not sure this is needed here */
1004 //offset &= ~(16 - 1);
1006 /* add parameter area size for called functions */
1007 offset += m->param_area;
1009 offset &= ~(16 - 1);
1011 /* allow room to save the return value */
1012 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1015 /* the MonoLMF structure is stored just below the stack pointer */
1018 /* this stuff should not be needed on ppc and the new jit,
1019 * because a call on ppc to the handlers doesn't change the
1020 * stack pointer and the jist doesn't manipulate the stack pointer
1021 * for operations involving valuetypes.
1023 /* reserve space to store the esp */
1024 offset += sizeof (gpointer);
1026 /* this is a global constant */
1027 mono_exc_esp_offset = offset;
1029 if (sig->call_convention == MONO_CALL_VARARG) {
1030 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1033 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1035 offset += sizeof(gpointer) - 1;
1036 offset &= ~(sizeof(gpointer) - 1);
1037 inst->inst_offset = offset;
1038 inst->opcode = OP_REGOFFSET;
1039 inst->inst_basereg = frame_reg;
1040 offset += sizeof(gpointer);
1041 if (sig->call_convention == MONO_CALL_VARARG)
1042 m->sig_cookie += sizeof (gpointer);
1045 curinst = m->locals_start;
1046 for (i = curinst; i < m->num_varinfo; ++i) {
1047 inst = m->varinfo [i];
1048 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1051 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1052 * pinvoke wrappers when they call functions returning structure */
1053 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1054 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1056 size = mono_type_size (inst->inst_vtype, &align);
1058 offset += align - 1;
1059 offset &= ~(align - 1);
1060 inst->inst_offset = offset;
1061 inst->opcode = OP_REGOFFSET;
1062 inst->inst_basereg = frame_reg;
1064 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1069 inst = m->args [curinst];
1070 if (inst->opcode != OP_REGVAR) {
1071 inst->opcode = OP_REGOFFSET;
1072 inst->inst_basereg = frame_reg;
1073 offset += sizeof (gpointer) - 1;
1074 offset &= ~(sizeof (gpointer) - 1);
1075 inst->inst_offset = offset;
1076 offset += sizeof (gpointer);
1077 if (sig->call_convention == MONO_CALL_VARARG)
1078 m->sig_cookie += sizeof (gpointer);
1083 for (i = 0; i < sig->param_count; ++i) {
1084 inst = m->args [curinst];
1085 if (inst->opcode != OP_REGVAR) {
1086 inst->opcode = OP_REGOFFSET;
1087 inst->inst_basereg = frame_reg;
1088 size = mono_type_size (sig->params [i], &align);
1089 offset += align - 1;
1090 offset &= ~(align - 1);
1091 inst->inst_offset = offset;
1093 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1094 m->sig_cookie += size;
1099 /* align the offset to 16 bytes */
1101 offset &= ~(16 - 1);
1104 m->stack_offset = offset;
1108 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1109 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1113 * take the arguments and generate the arch-specific
1114 * instructions to properly call the function in call.
1115 * This includes pushing, moving arguments to the right register
1117 * Issue: who does the spilling if needed, and when?
1120 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1122 MonoMethodSignature *sig;
1127 sig = call->signature;
1128 n = sig->param_count + sig->hasthis;
1130 cinfo = calculate_sizes (sig, sig->pinvoke);
1131 if (cinfo->struct_ret)
1132 call->used_iregs |= 1 << cinfo->struct_ret;
1134 for (i = 0; i < n; ++i) {
1135 ainfo = cinfo->args + i;
1136 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1138 cfg->disable_aot = TRUE;
1140 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1141 sig_arg->inst_p0 = call->signature;
1143 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1144 arg->inst_imm = cinfo->sig_cookie.offset;
1145 arg->inst_left = sig_arg;
1147 /* prepend, so they get reversed */
1148 arg->next = call->out_args;
1149 call->out_args = arg;
1151 if (is_virtual && i == 0) {
1152 /* the argument will be attached to the call instrucion */
1153 in = call->args [i];
1154 call->used_iregs |= 1 << ainfo->reg;
1156 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1157 in = call->args [i];
1158 arg->cil_code = in->cil_code;
1159 arg->inst_left = in;
1160 arg->inst_call = call;
1161 arg->type = in->type;
1162 /* prepend, we'll need to reverse them later */
1163 arg->next = call->out_args;
1164 call->out_args = arg;
1165 if (ainfo->regtype == RegTypeGeneral) {
1166 arg->backend.reg3 = ainfo->reg;
1167 call->used_iregs |= 1 << ainfo->reg;
1168 if (arg->type == STACK_I8)
1169 call->used_iregs |= 1 << (ainfo->reg + 1);
1170 } else if (ainfo->regtype == RegTypeStructByAddr) {
1171 if (ainfo->offset) {
1172 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1173 arg->opcode = OP_OUTARG_MEMBASE;
1174 ai->reg = ainfo->reg;
1175 ai->size = sizeof (gpointer);
1176 ai->offset = ainfo->offset;
1177 arg->backend.data = ai;
1179 arg->backend.reg3 = ainfo->reg;
1180 call->used_iregs |= 1 << ainfo->reg;
1182 } else if (ainfo->regtype == RegTypeStructByVal) {
1184 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1185 /* mark the used regs */
1186 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1187 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1189 arg->opcode = OP_OUTARG_VT;
1190 ai->reg = ainfo->reg;
1191 ai->size = ainfo->size;
1192 ai->vtsize = ainfo->vtsize;
1193 ai->offset = ainfo->offset;
1194 arg->backend.data = ai;
1195 } else if (ainfo->regtype == RegTypeBase) {
1196 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1197 arg->opcode = OP_OUTARG_MEMBASE;
1198 ai->reg = ainfo->reg;
1199 ai->size = ainfo->size;
1200 ai->offset = ainfo->offset;
1201 arg->backend.data = ai;
1202 } else if (ainfo->regtype == RegTypeFP) {
1203 arg->opcode = OP_OUTARG_R8;
1204 arg->backend.reg3 = ainfo->reg;
1205 call->used_fregs |= 1 << ainfo->reg;
1206 if (ainfo->size == 4) {
1207 arg->opcode = OP_OUTARG_R8;
1208 /* we reduce the precision */
1210 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1211 conv->inst_left = arg->inst_left;
1212 arg->inst_left = conv;*/
1215 g_assert_not_reached ();
1220 * Reverse the call->out_args list.
1223 MonoInst *prev = NULL, *list = call->out_args, *next;
1230 call->out_args = prev;
1232 call->stack_usage = cinfo->stack_usage;
1233 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1234 cfg->flags |= MONO_CFG_HAS_CALLS;
1236 * should set more info in call, such as the stack space
1237 * used by the args that needs to be added back to esp
1245 * Allow tracing to work with this interface (with an optional argument)
1249 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1253 ppc_load (code, ppc_r3, cfg->method);
1254 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1255 ppc_load (code, ppc_r0, func);
1256 ppc_mtlr (code, ppc_r0);
1270 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1273 int save_mode = SAVE_NONE;
1275 MonoMethod *method = cfg->method;
1276 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1277 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1281 offset = code - cfg->native_code;
1282 /* we need about 16 instructions */
1283 if (offset > (cfg->code_size - 16 * 4)) {
1284 cfg->code_size *= 2;
1285 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1286 code = cfg->native_code + offset;
1290 case MONO_TYPE_VOID:
1291 /* special case string .ctor icall */
1292 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1293 save_mode = SAVE_ONE;
1295 save_mode = SAVE_NONE;
1299 save_mode = SAVE_TWO;
1303 save_mode = SAVE_FP;
1305 case MONO_TYPE_VALUETYPE:
1306 save_mode = SAVE_STRUCT;
1309 save_mode = SAVE_ONE;
1313 switch (save_mode) {
1315 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1316 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1317 if (enable_arguments) {
1318 ppc_mr (code, ppc_r5, ppc_r4);
1319 ppc_mr (code, ppc_r4, ppc_r3);
1323 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1324 if (enable_arguments) {
1325 ppc_mr (code, ppc_r4, ppc_r3);
1329 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1330 if (enable_arguments) {
1331 /* FIXME: what reg? */
1332 ppc_fmr (code, ppc_f3, ppc_f1);
1333 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1334 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1338 if (enable_arguments) {
1339 /* FIXME: get the actual address */
1340 ppc_mr (code, ppc_r4, ppc_r3);
1348 ppc_load (code, ppc_r3, cfg->method);
1349 ppc_load (code, ppc_r0, func);
1350 ppc_mtlr (code, ppc_r0);
1353 switch (save_mode) {
1355 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1356 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1359 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1362 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1372 * Conditional branches have a small offset, so if it is likely overflowed,
1373 * we do a branch to the end of the method (uncond branches have much larger
1374 * offsets) where we perform the conditional and jump back unconditionally.
1375 * It's slightly slower, since we add two uncond branches, but it's very simple
1376 * with the current patch implementation and such large methods are likely not
1377 * going to be perf critical anyway.
1382 const char *exception;
1389 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1390 if (ins->flags & MONO_INST_BRLABEL) { \
1391 if (0 && ins->inst_i0->inst_c0) { \
1392 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1394 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1395 ppc_bc (code, (b0), (b1), 0); \
1398 if (0 && ins->inst_true_bb->native_offset) { \
1399 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1401 int br_disp = ins->inst_true_bb->max_offset - offset; \
1402 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1403 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1404 ovfj->data.bb = ins->inst_true_bb; \
1405 ovfj->ip_offset = 0; \
1406 ovfj->b0_cond = (b0); \
1407 ovfj->b1_cond = (b1); \
1408 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1411 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1412 ppc_bc (code, (b0), (b1), 0); \
1417 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1419 /* emit an exception if condition is fail
1421 * We assign the extra code used to throw the implicit exceptions
1422 * to cfg->bb_exit as far as the big branch handling is concerned
1424 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1426 int br_disp = cfg->bb_exit->max_offset - offset; \
1427 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1428 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1429 ovfj->data.exception = (exc_name); \
1430 ovfj->ip_offset = code - cfg->native_code; \
1431 ovfj->b0_cond = (b0); \
1432 ovfj->b1_cond = (b1); \
1433 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1435 cfg->bb_exit->max_offset += 24; \
1437 mono_add_patch_info (cfg, code - cfg->native_code, \
1438 MONO_PATCH_INFO_EXC, exc_name); \
1439 ppc_bcl (code, (b0), (b1), 0); \
1443 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1446 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1448 MonoInst *ins, *last_ins = NULL;
1453 switch (ins->opcode) {
1455 /* remove unnecessary multiplication with 1 */
1456 if (ins->inst_imm == 1) {
1457 if (ins->dreg != ins->sreg1) {
1458 ins->opcode = OP_MOVE;
1460 last_ins->next = ins->next;
1465 int power2 = mono_is_power_of_two (ins->inst_imm);
1467 ins->opcode = OP_SHL_IMM;
1468 ins->inst_imm = power2;
1472 case OP_LOAD_MEMBASE:
1473 case OP_LOADI4_MEMBASE:
1475 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1476 * OP_LOAD_MEMBASE offset(basereg), reg
1478 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1479 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1480 ins->inst_basereg == last_ins->inst_destbasereg &&
1481 ins->inst_offset == last_ins->inst_offset) {
1482 if (ins->dreg == last_ins->sreg1) {
1483 last_ins->next = ins->next;
1487 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1488 ins->opcode = OP_MOVE;
1489 ins->sreg1 = last_ins->sreg1;
1493 * Note: reg1 must be different from the basereg in the second load
1494 * OP_LOAD_MEMBASE offset(basereg), reg1
1495 * OP_LOAD_MEMBASE offset(basereg), reg2
1497 * OP_LOAD_MEMBASE offset(basereg), reg1
1498 * OP_MOVE reg1, reg2
1500 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1501 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1502 ins->inst_basereg != last_ins->dreg &&
1503 ins->inst_basereg == last_ins->inst_basereg &&
1504 ins->inst_offset == last_ins->inst_offset) {
1506 if (ins->dreg == last_ins->dreg) {
1507 last_ins->next = ins->next;
1511 ins->opcode = OP_MOVE;
1512 ins->sreg1 = last_ins->dreg;
1515 //g_assert_not_reached ();
1519 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1520 * OP_LOAD_MEMBASE offset(basereg), reg
1522 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1523 * OP_ICONST reg, imm
1525 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1526 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1527 ins->inst_basereg == last_ins->inst_destbasereg &&
1528 ins->inst_offset == last_ins->inst_offset) {
1529 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1530 ins->opcode = OP_ICONST;
1531 ins->inst_c0 = last_ins->inst_imm;
1532 g_assert_not_reached (); // check this rule
1536 case OP_LOADU1_MEMBASE:
1537 case OP_LOADI1_MEMBASE:
1538 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1539 ins->inst_basereg == last_ins->inst_destbasereg &&
1540 ins->inst_offset == last_ins->inst_offset) {
1541 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1542 ins->sreg1 = last_ins->sreg1;
1545 case OP_LOADU2_MEMBASE:
1546 case OP_LOADI2_MEMBASE:
1547 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1548 ins->inst_basereg == last_ins->inst_destbasereg &&
1549 ins->inst_offset == last_ins->inst_offset) {
1550 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1551 ins->sreg1 = last_ins->sreg1;
1558 ins->opcode = OP_MOVE;
1562 if (ins->dreg == ins->sreg1) {
1564 last_ins->next = ins->next;
1569 * OP_MOVE sreg, dreg
1570 * OP_MOVE dreg, sreg
1572 if (last_ins && last_ins->opcode == OP_MOVE &&
1573 ins->sreg1 == last_ins->dreg &&
1574 ins->dreg == last_ins->sreg1) {
1575 last_ins->next = ins->next;
1584 bb->last_ins = last_ins;
1588 * the branch_b0_table should maintain the order of these
1602 branch_b0_table [] = {
1617 branch_b1_table [] = {
1632 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1636 bb->code = to_insert;
1637 to_insert->next = ins;
1639 to_insert->next = ins->next;
1640 ins->next = to_insert;
1644 #define NEW_INS(cfg,dest,op) do { \
1645 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1646 (dest)->opcode = (op); \
1647 insert_after_ins (bb, last_ins, (dest)); \
1651 map_to_reg_reg_op (int op)
1660 case OP_COMPARE_IMM:
1676 case OP_LOAD_MEMBASE:
1677 return OP_LOAD_MEMINDEX;
1678 case OP_LOADI4_MEMBASE:
1679 return OP_LOADI4_MEMINDEX;
1680 case OP_LOADU4_MEMBASE:
1681 return OP_LOADU4_MEMINDEX;
1682 case OP_LOADU1_MEMBASE:
1683 return OP_LOADU1_MEMINDEX;
1684 case OP_LOADI2_MEMBASE:
1685 return OP_LOADI2_MEMINDEX;
1686 case OP_LOADU2_MEMBASE:
1687 return OP_LOADU2_MEMINDEX;
1688 case OP_LOADI1_MEMBASE:
1689 return OP_LOADI1_MEMINDEX;
1690 case OP_LOADR4_MEMBASE:
1691 return OP_LOADR4_MEMINDEX;
1692 case OP_LOADR8_MEMBASE:
1693 return OP_LOADR8_MEMINDEX;
1694 case OP_STOREI1_MEMBASE_REG:
1695 return OP_STOREI1_MEMINDEX;
1696 case OP_STOREI2_MEMBASE_REG:
1697 return OP_STOREI2_MEMINDEX;
1698 case OP_STOREI4_MEMBASE_REG:
1699 return OP_STOREI4_MEMINDEX;
1700 case OP_STORE_MEMBASE_REG:
1701 return OP_STORE_MEMINDEX;
1702 case OP_STORER4_MEMBASE_REG:
1703 return OP_STORER4_MEMINDEX;
1704 case OP_STORER8_MEMBASE_REG:
1705 return OP_STORER8_MEMINDEX;
1706 case OP_STORE_MEMBASE_IMM:
1707 return OP_STORE_MEMBASE_REG;
1708 case OP_STOREI1_MEMBASE_IMM:
1709 return OP_STOREI1_MEMBASE_REG;
1710 case OP_STOREI2_MEMBASE_IMM:
1711 return OP_STOREI2_MEMBASE_REG;
1712 case OP_STOREI4_MEMBASE_IMM:
1713 return OP_STOREI4_MEMBASE_REG;
1715 g_assert_not_reached ();
1718 #define compare_opcode_is_unsigned(opcode) \
1719 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1720 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1721 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1723 * Remove from the instruction list the instructions that can't be
1724 * represented with very simple instructions with no register
1728 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1730 MonoInst *ins, *next, *temp, *last_ins = NULL;
1733 /* setup the virtual reg allocator */
1734 if (bb->max_vreg > cfg->rs->next_vreg)
1735 cfg->rs->next_vreg = bb->max_vreg;
1740 switch (ins->opcode) {
1743 if (!ppc_is_imm16 (ins->inst_imm)) {
1744 NEW_INS (cfg, temp, OP_ICONST);
1745 temp->inst_c0 = ins->inst_imm;
1746 temp->dreg = mono_regstate_next_int (cfg->rs);
1747 ins->sreg2 = temp->dreg;
1748 ins->opcode = map_to_reg_reg_op (ins->opcode);
1752 if (!ppc_is_imm16 (-ins->inst_imm)) {
1753 NEW_INS (cfg, temp, OP_ICONST);
1754 temp->inst_c0 = ins->inst_imm;
1755 temp->dreg = mono_regstate_next_int (cfg->rs);
1756 ins->sreg2 = temp->dreg;
1757 ins->opcode = map_to_reg_reg_op (ins->opcode);
1763 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1764 NEW_INS (cfg, temp, OP_ICONST);
1765 temp->inst_c0 = ins->inst_imm;
1766 temp->dreg = mono_regstate_next_int (cfg->rs);
1767 ins->sreg2 = temp->dreg;
1768 ins->opcode = map_to_reg_reg_op (ins->opcode);
1774 NEW_INS (cfg, temp, OP_ICONST);
1775 temp->inst_c0 = ins->inst_imm;
1776 temp->dreg = mono_regstate_next_int (cfg->rs);
1777 ins->sreg2 = temp->dreg;
1778 ins->opcode = map_to_reg_reg_op (ins->opcode);
1780 case OP_COMPARE_IMM:
1781 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1782 if (!ppc_is_uimm16 (ins->inst_imm)) {
1783 NEW_INS (cfg, temp, OP_ICONST);
1784 temp->inst_c0 = ins->inst_imm;
1785 temp->dreg = mono_regstate_next_int (cfg->rs);
1786 ins->sreg2 = temp->dreg;
1787 ins->opcode = map_to_reg_reg_op (ins->opcode);
1790 if (!ppc_is_imm16 (ins->inst_imm)) {
1791 NEW_INS (cfg, temp, OP_ICONST);
1792 temp->inst_c0 = ins->inst_imm;
1793 temp->dreg = mono_regstate_next_int (cfg->rs);
1794 ins->sreg2 = temp->dreg;
1795 ins->opcode = map_to_reg_reg_op (ins->opcode);
1800 if (ins->inst_imm == 1) {
1801 ins->opcode = OP_MOVE;
1804 if (ins->inst_imm == 0) {
1805 ins->opcode = OP_ICONST;
1809 imm = mono_is_power_of_two (ins->inst_imm);
1811 ins->opcode = OP_SHL_IMM;
1812 ins->inst_imm = imm;
1815 if (!ppc_is_imm16 (ins->inst_imm)) {
1816 NEW_INS (cfg, temp, OP_ICONST);
1817 temp->inst_c0 = ins->inst_imm;
1818 temp->dreg = mono_regstate_next_int (cfg->rs);
1819 ins->sreg2 = temp->dreg;
1820 ins->opcode = map_to_reg_reg_op (ins->opcode);
1823 case OP_LOAD_MEMBASE:
1824 case OP_LOADI4_MEMBASE:
1825 case OP_LOADU4_MEMBASE:
1826 case OP_LOADI2_MEMBASE:
1827 case OP_LOADU2_MEMBASE:
1828 case OP_LOADI1_MEMBASE:
1829 case OP_LOADU1_MEMBASE:
1830 case OP_LOADR4_MEMBASE:
1831 case OP_LOADR8_MEMBASE:
1832 case OP_STORE_MEMBASE_REG:
1833 case OP_STOREI4_MEMBASE_REG:
1834 case OP_STOREI2_MEMBASE_REG:
1835 case OP_STOREI1_MEMBASE_REG:
1836 case OP_STORER4_MEMBASE_REG:
1837 case OP_STORER8_MEMBASE_REG:
1838 /* we can do two things: load the immed in a register
1839 * and use an indexed load, or see if the immed can be
1840 * represented as an ad_imm + a load with a smaller offset
1841 * that fits. We just do the first for now, optimize later.
1843 if (ppc_is_imm16 (ins->inst_offset))
1845 NEW_INS (cfg, temp, OP_ICONST);
1846 temp->inst_c0 = ins->inst_offset;
1847 temp->dreg = mono_regstate_next_int (cfg->rs);
1848 ins->sreg2 = temp->dreg;
1849 ins->opcode = map_to_reg_reg_op (ins->opcode);
1851 case OP_STORE_MEMBASE_IMM:
1852 case OP_STOREI1_MEMBASE_IMM:
1853 case OP_STOREI2_MEMBASE_IMM:
1854 case OP_STOREI4_MEMBASE_IMM:
1855 NEW_INS (cfg, temp, OP_ICONST);
1856 temp->inst_c0 = ins->inst_imm;
1857 temp->dreg = mono_regstate_next_int (cfg->rs);
1858 ins->sreg1 = temp->dreg;
1859 ins->opcode = map_to_reg_reg_op (ins->opcode);
1861 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1864 NEW_INS (cfg, temp, OP_ICONST);
1865 temp->inst_c0 = ins->inst_p0;
1866 temp->dreg = mono_regstate_next_int (cfg->rs);
1867 ins->inst_basereg = temp->dreg;
1868 ins->inst_offset = 0;
1869 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
1871 /* make it handle the possibly big ins->inst_offset
1872 * later optimize to use lis + load_membase
1879 bb->last_ins = last_ins;
1880 bb->max_vreg = cfg->rs->next_vreg;
1885 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1889 mono_arch_lowering_pass (cfg, bb);
1890 mono_local_regalloc (cfg, bb);
1894 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1896 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1897 ppc_fctiwz (code, ppc_f0, sreg);
1898 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1899 ppc_lwz (code, dreg, -4, ppc_sp);
1902 ppc_andid (code, dreg, dreg, 0xff);
1904 ppc_andid (code, dreg, dreg, 0xffff);
1907 ppc_extsb (code, dreg, dreg);
1909 ppc_extsh (code, dreg, dreg);
1914 static unsigned char*
1915 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1918 int sreg = tree->sreg1;
1919 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1920 if (tree->flags & MONO_INST_INIT) {
1922 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1923 x86_push_reg (code, X86_EAX);
1926 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1927 x86_push_reg (code, X86_ECX);
1930 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1931 x86_push_reg (code, X86_EDI);
1935 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1936 if (sreg != X86_ECX)
1937 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1938 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1940 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1942 x86_prefix (code, X86_REP_PREFIX);
1945 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1946 x86_pop_reg (code, X86_EDI);
1947 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1948 x86_pop_reg (code, X86_ECX);
1949 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1950 x86_pop_reg (code, X86_EAX);
1963 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1966 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1967 PatchData *pdata = (PatchData*)user_data;
1968 guchar *code = data;
1969 guint32 *thunks = data;
1970 guint32 *endthunks = (guint32*)(code + bsize);
1974 int difflow, diffhigh;
1976 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1977 difflow = (char*)pdata->code - (char*)thunks;
1978 diffhigh = (char*)pdata->code - (char*)endthunks;
1979 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1982 templ = (guchar*)load;
1983 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1984 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1986 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1987 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1988 while (thunks < endthunks) {
1989 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1990 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1991 ppc_patch (pdata->code, (guchar*)thunks);
1992 mono_arch_flush_icache (pdata->code, 4);
1995 static int num_thunks = 0;
1997 if ((num_thunks % 20) == 0)
1998 g_print ("num_thunks lookup: %d\n", num_thunks);
2001 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2002 /* found a free slot instead: emit thunk */
2003 code = (guchar*)thunks;
2004 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2005 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2006 ppc_mtctr (code, ppc_r0);
2007 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2008 mono_arch_flush_icache ((guchar*)thunks, 16);
2010 ppc_patch (pdata->code, (guchar*)thunks);
2011 mono_arch_flush_icache (pdata->code, 4);
2014 static int num_thunks = 0;
2016 if ((num_thunks % 20) == 0)
2017 g_print ("num_thunks: %d\n", num_thunks);
2021 /* skip 16 bytes, the size of the thunk */
2025 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2031 handle_thunk (int absolute, guchar *code, guchar *target) {
2032 MonoDomain *domain = mono_domain_get ();
2036 pdata.target = target;
2037 pdata.absolute = absolute;
2040 mono_domain_lock (domain);
2041 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2044 /* this uses the first available slot */
2046 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2048 mono_domain_unlock (domain);
2050 if (pdata.found != 1)
2051 g_print ("thunk failed for %p from %p\n", target, code);
2052 g_assert (pdata.found == 1);
2056 ppc_patch (guchar *code, guchar *target)
2058 guint32 ins = *(guint32*)code;
2059 guint32 prim = ins >> 26;
2062 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2064 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2065 gint diff = target - code;
2067 if (diff <= 33554431){
2068 ins = (18 << 26) | (diff) | (ins & 1);
2069 *(guint32*)code = ins;
2073 /* diff between 0 and -33554432 */
2074 if (diff >= -33554432){
2075 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2076 *(guint32*)code = ins;
2081 if ((glong)target >= 0){
2082 if ((glong)target <= 33554431){
2083 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2084 *(guint32*)code = ins;
2088 if ((glong)target >= -33554432){
2089 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2090 *(guint32*)code = ins;
2095 handle_thunk (TRUE, code, target);
2098 g_assert_not_reached ();
2105 guint32 li = (guint32)target;
2106 ins = (ins & 0xffff0000) | (ins & 3);
2107 ovf = li & 0xffff0000;
2108 if (ovf != 0 && ovf != 0xffff0000)
2109 g_assert_not_reached ();
2112 // FIXME: assert the top bits of li are 0
2114 gint diff = target - code;
2115 ins = (ins & 0xffff0000) | (ins & 3);
2116 ovf = diff & 0xffff0000;
2117 if (ovf != 0 && ovf != 0xffff0000)
2118 g_assert_not_reached ();
2122 *(guint32*)code = ins;
2126 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2128 /* the trampoline code will try to patch the blrl, blr, bcctr */
2129 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2132 /* this is the lis/ori/mtlr/blrl sequence */
2133 seq = (guint32*)code;
2134 g_assert ((seq [0] >> 26) == 15);
2135 g_assert ((seq [1] >> 26) == 24);
2136 g_assert ((seq [2] >> 26) == 31);
2137 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2138 /* FIXME: make this thread safe */
2139 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2140 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2141 mono_arch_flush_icache (code - 8, 8);
2143 g_assert_not_reached ();
2145 // g_print ("patched with 0x%08x\n", ins);
2149 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2154 guint8 *code = cfg->native_code + cfg->code_len;
2155 MonoInst *last_ins = NULL;
2156 guint last_offset = 0;
2159 if (cfg->opt & MONO_OPT_PEEPHOLE)
2160 peephole_pass (cfg, bb);
2162 /* we don't align basic blocks of loops on ppc */
2164 if (cfg->verbose_level > 2)
2165 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2167 cpos = bb->max_offset;
2169 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2170 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2171 //g_assert (!mono_compile_aot);
2174 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2175 /* this is not thread save, but good enough */
2176 /* fixme: howto handle overflows? */
2177 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2182 offset = code - cfg->native_code;
2184 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2186 if (offset > (cfg->code_size - max_len - 16)) {
2187 cfg->code_size *= 2;
2188 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2189 code = cfg->native_code + offset;
2191 // if (ins->cil_code)
2192 // g_print ("cil code\n");
2193 mono_debug_record_line_number (cfg, ins, offset);
2195 switch (ins->opcode) {
2197 emit_tls_access (code, ins->dreg, ins->inst_offset);
2200 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2201 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2202 ppc_mr (code, ppc_r4, ppc_r0);
2205 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2206 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2207 ppc_mr (code, ppc_r4, ppc_r0);
2209 case OP_MEMORY_BARRIER:
2212 case OP_STOREI1_MEMBASE_REG:
2213 if (ppc_is_imm16 (ins->inst_offset)) {
2214 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2216 g_assert_not_reached ();
2219 case OP_STOREI2_MEMBASE_REG:
2220 if (ppc_is_imm16 (ins->inst_offset)) {
2221 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2223 g_assert_not_reached ();
2226 case OP_STORE_MEMBASE_REG:
2227 case OP_STOREI4_MEMBASE_REG:
2228 if (ppc_is_imm16 (ins->inst_offset)) {
2229 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2231 g_assert_not_reached ();
2234 case OP_STOREI1_MEMINDEX:
2235 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2237 case OP_STOREI2_MEMINDEX:
2238 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2240 case OP_STORE_MEMINDEX:
2241 case OP_STOREI4_MEMINDEX:
2242 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2247 g_assert_not_reached ();
2248 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2251 g_assert_not_reached ();
2253 case OP_LOAD_MEMBASE:
2254 case OP_LOADI4_MEMBASE:
2255 case OP_LOADU4_MEMBASE:
2256 if (ppc_is_imm16 (ins->inst_offset)) {
2257 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2259 g_assert_not_reached ();
2262 case OP_LOADI1_MEMBASE:
2263 case OP_LOADU1_MEMBASE:
2264 if (ppc_is_imm16 (ins->inst_offset)) {
2265 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2267 g_assert_not_reached ();
2269 if (ins->opcode == OP_LOADI1_MEMBASE)
2270 ppc_extsb (code, ins->dreg, ins->dreg);
2272 case OP_LOADU2_MEMBASE:
2273 if (ppc_is_imm16 (ins->inst_offset)) {
2274 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2276 g_assert_not_reached ();
2279 case OP_LOADI2_MEMBASE:
2280 if (ppc_is_imm16 (ins->inst_offset)) {
2281 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2283 g_assert_not_reached ();
2286 case OP_LOAD_MEMINDEX:
2287 case OP_LOADI4_MEMINDEX:
2288 case OP_LOADU4_MEMINDEX:
2289 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2291 case OP_LOADU2_MEMINDEX:
2292 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2294 case OP_LOADI2_MEMINDEX:
2295 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2297 case OP_LOADU1_MEMINDEX:
2298 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2300 case OP_LOADI1_MEMINDEX:
2301 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2302 ppc_extsb (code, ins->dreg, ins->dreg);
2305 ppc_extsb (code, ins->dreg, ins->sreg1);
2308 ppc_extsh (code, ins->dreg, ins->sreg1);
2311 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2314 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2317 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2318 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2320 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2322 case OP_COMPARE_IMM:
2323 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2324 if (ppc_is_uimm16 (ins->inst_imm)) {
2325 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2327 g_assert_not_reached ();
2330 if (ppc_is_imm16 (ins->inst_imm)) {
2331 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2333 g_assert_not_reached ();
2341 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2344 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2347 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2350 if (ppc_is_imm16 (ins->inst_imm)) {
2351 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2353 g_assert_not_reached ();
2357 if (ppc_is_imm16 (ins->inst_imm)) {
2358 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2360 g_assert_not_reached ();
2364 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2366 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2367 ppc_mfspr (code, ppc_r0, ppc_xer);
2368 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2369 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2371 case CEE_ADD_OVF_UN:
2372 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2374 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2375 ppc_mfspr (code, ppc_r0, ppc_xer);
2376 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2377 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2380 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2382 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2383 ppc_mfspr (code, ppc_r0, ppc_xer);
2384 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2385 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2387 case CEE_SUB_OVF_UN:
2388 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2390 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2391 ppc_mfspr (code, ppc_r0, ppc_xer);
2392 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2393 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2395 case OP_ADD_OVF_CARRY:
2396 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2398 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2399 ppc_mfspr (code, ppc_r0, ppc_xer);
2400 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2401 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2403 case OP_ADD_OVF_UN_CARRY:
2404 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2406 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2407 ppc_mfspr (code, ppc_r0, ppc_xer);
2408 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2409 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2411 case OP_SUB_OVF_CARRY:
2412 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2414 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2415 ppc_mfspr (code, ppc_r0, ppc_xer);
2416 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2417 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2419 case OP_SUB_OVF_UN_CARRY:
2420 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2422 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2423 ppc_mfspr (code, ppc_r0, ppc_xer);
2424 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2425 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2428 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2431 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2434 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2437 // we add the negated value
2438 if (ppc_is_imm16 (-ins->inst_imm))
2439 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2441 g_assert_not_reached ();
2445 g_assert (ppc_is_imm16 (ins->inst_imm));
2446 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2449 ppc_subfze (code, ins->dreg, ins->sreg1);
2452 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2453 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2456 if (!(ins->inst_imm & 0xffff0000)) {
2457 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2458 } else if (!(ins->inst_imm & 0xffff)) {
2459 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2461 g_assert_not_reached ();
2465 guint32 *divisor_is_m1;
2466 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2468 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2469 divisor_is_m1 = code;
2470 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2471 ppc_lis (code, ppc_r0, 0x8000);
2472 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2473 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2474 ppc_patch (divisor_is_m1, code);
2475 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2477 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2478 ppc_mfspr (code, ppc_r0, ppc_xer);
2479 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2480 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2484 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2485 ppc_mfspr (code, ppc_r0, ppc_xer);
2486 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2487 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2493 g_assert_not_reached ();
2495 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2498 if (!(ins->inst_imm & 0xffff0000)) {
2499 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2500 } else if (!(ins->inst_imm & 0xffff)) {
2501 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2503 g_assert_not_reached ();
2507 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2510 if (!(ins->inst_imm & 0xffff0000)) {
2511 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2512 } else if (!(ins->inst_imm & 0xffff)) {
2513 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2515 g_assert_not_reached ();
2519 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2522 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2525 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2528 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2532 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2534 ppc_mr (code, ins->dreg, ins->sreg1);
2537 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2540 ppc_not (code, ins->dreg, ins->sreg1);
2543 ppc_neg (code, ins->dreg, ins->sreg1);
2546 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2549 if (ppc_is_imm16 (ins->inst_imm)) {
2550 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2552 g_assert_not_reached ();
2556 /* we annot use mcrxr, since it's not implemented on some processors
2557 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2559 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2560 ppc_mfspr (code, ppc_r0, ppc_xer);
2561 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2562 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2564 case CEE_MUL_OVF_UN:
2565 /* we first multiply to get the high word and compare to 0
2566 * to set the flags, then the result is discarded and then
2567 * we multiply to get the lower * bits result
2569 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2570 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2571 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2572 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2576 ppc_load (code, ins->dreg, ins->inst_c0);
2579 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2580 ppc_lis (code, ins->dreg, 0);
2581 ppc_ori (code, ins->dreg, ins->dreg, 0);
2587 ppc_mr (code, ins->dreg, ins->sreg1);
2590 int saved = ins->sreg1;
2591 if (ins->sreg1 == ppc_r3) {
2592 ppc_mr (code, ppc_r0, ins->sreg1);
2595 if (ins->sreg2 != ppc_r3)
2596 ppc_mr (code, ppc_r3, ins->sreg2);
2597 if (saved != ppc_r4)
2598 ppc_mr (code, ppc_r4, saved);
2603 ppc_fmr (code, ins->dreg, ins->sreg1);
2605 case OP_FCONV_TO_R4:
2606 ppc_frsp (code, ins->dreg, ins->sreg1);
2612 * Keep in sync with mono_arch_emit_epilog
2614 g_assert (!cfg->method->save_lmf);
2616 * Note: we can use ppc_r11 here because it is dead anyway:
2617 * we're leaving the method.
2619 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2620 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2621 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2623 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2624 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2626 ppc_mtlr (code, ppc_r0);
2628 if (ppc_is_imm16 (cfg->stack_usage)) {
2629 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2631 ppc_load (code, ppc_r11, cfg->stack_usage);
2632 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2634 if (!cfg->method->save_lmf) {
2635 /*for (i = 31; i >= 14; --i) {
2636 if (cfg->used_float_regs & (1 << i)) {
2637 pos += sizeof (double);
2638 ppc_lfd (code, i, -pos, cfg->frame_reg);
2641 for (i = 31; i >= 13; --i) {
2642 if (cfg->used_int_regs & (1 << i)) {
2643 pos += sizeof (gulong);
2644 ppc_lwz (code, i, -pos, cfg->frame_reg);
2648 /* FIXME restore from MonoLMF: though this can't happen yet */
2650 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2655 /* ensure ins->sreg1 is not NULL */
2656 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2659 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2660 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2662 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
2663 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
2665 ppc_stw (code, ppc_r0, 0, ins->sreg1);
2673 call = (MonoCallInst*)ins;
2674 if (ins->flags & MONO_INST_HAS_METHOD)
2675 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2677 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2678 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2679 ppc_lis (code, ppc_r0, 0);
2680 ppc_ori (code, ppc_r0, ppc_r0, 0);
2681 ppc_mtlr (code, ppc_r0);
2690 case OP_VOIDCALL_REG:
2692 ppc_mtlr (code, ins->sreg1);
2695 case OP_FCALL_MEMBASE:
2696 case OP_LCALL_MEMBASE:
2697 case OP_VCALL_MEMBASE:
2698 case OP_VOIDCALL_MEMBASE:
2699 case OP_CALL_MEMBASE:
2700 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2701 ppc_mtlr (code, ppc_r0);
2705 g_assert_not_reached ();
2708 guint32 * zero_loop_jump, * zero_loop_start;
2709 /* keep alignment */
2710 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2711 int area_offset = alloca_waste;
2713 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2714 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2715 /* use ctr to store the number of words to 0 if needed */
2716 if (ins->flags & MONO_INST_INIT) {
2717 /* we zero 4 bytes at a time:
2718 * we add 7 instead of 3 so that we set the counter to
2719 * at least 1, otherwise the bdnz instruction will make
2720 * it negative and iterate billions of times.
2722 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2723 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2724 ppc_mtctr (code, ppc_r0);
2726 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2727 ppc_neg (code, ppc_r11, ppc_r11);
2728 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2730 if (ins->flags & MONO_INST_INIT) {
2731 /* adjust the dest reg by -4 so we can use stwu */
2732 /* we actually adjust -8 because we let the loop
2735 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2736 ppc_li (code, ppc_r11, 0);
2737 zero_loop_start = code;
2738 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2739 zero_loop_jump = code;
2740 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2741 ppc_patch (zero_loop_jump, zero_loop_start);
2743 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2751 ppc_mr (code, ppc_r3, ins->sreg1);
2752 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2753 (gpointer)"mono_arch_throw_exception");
2754 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2755 ppc_lis (code, ppc_r0, 0);
2756 ppc_ori (code, ppc_r0, ppc_r0, 0);
2757 ppc_mtlr (code, ppc_r0);
2766 ppc_mr (code, ppc_r3, ins->sreg1);
2767 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2768 (gpointer)"mono_arch_rethrow_exception");
2769 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2770 ppc_lis (code, ppc_r0, 0);
2771 ppc_ori (code, ppc_r0, ppc_r0, 0);
2772 ppc_mtlr (code, ppc_r0);
2779 case OP_START_HANDLER:
2780 ppc_mflr (code, ppc_r0);
2781 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2782 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2784 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2785 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2789 if (ins->sreg1 != ppc_r3)
2790 ppc_mr (code, ppc_r3, ins->sreg1);
2791 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2792 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2794 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2795 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2797 ppc_mtlr (code, ppc_r0);
2801 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2802 ppc_mtlr (code, ppc_r0);
2805 case OP_CALL_HANDLER:
2806 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2810 ins->inst_c0 = code - cfg->native_code;
2813 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2814 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2816 if (ins->flags & MONO_INST_BRLABEL) {
2817 /*if (ins->inst_i0->inst_c0) {
2819 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2821 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2825 /*if (ins->inst_target_bb->native_offset) {
2827 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2829 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2835 ppc_mtctr (code, ins->sreg1);
2836 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2839 ppc_li (code, ins->dreg, 0);
2840 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2841 ppc_li (code, ins->dreg, 1);
2845 ppc_li (code, ins->dreg, 1);
2846 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2847 ppc_li (code, ins->dreg, 0);
2851 ppc_li (code, ins->dreg, 1);
2852 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2853 ppc_li (code, ins->dreg, 0);
2855 case OP_COND_EXC_EQ:
2856 case OP_COND_EXC_NE_UN:
2857 case OP_COND_EXC_LT:
2858 case OP_COND_EXC_LT_UN:
2859 case OP_COND_EXC_GT:
2860 case OP_COND_EXC_GT_UN:
2861 case OP_COND_EXC_GE:
2862 case OP_COND_EXC_GE_UN:
2863 case OP_COND_EXC_LE:
2864 case OP_COND_EXC_LE_UN:
2865 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2868 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2870 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2871 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2872 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2874 case OP_COND_EXC_OV:
2875 /*ppc_mcrxr (code, 0);
2876 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2878 case OP_COND_EXC_NC:
2879 case OP_COND_EXC_NO:
2880 g_assert_not_reached ();
2892 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2895 /* floating point opcodes */
2898 g_assert_not_reached ();
2899 case OP_STORER8_MEMBASE_REG:
2900 if (ppc_is_imm16 (ins->inst_offset)) {
2901 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2903 g_assert_not_reached ();
2906 case OP_LOADR8_MEMBASE:
2907 if (ppc_is_imm16 (ins->inst_offset)) {
2908 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2910 g_assert_not_reached ();
2913 case OP_STORER4_MEMBASE_REG:
2914 ppc_frsp (code, ins->sreg1, ins->sreg1);
2915 if (ppc_is_imm16 (ins->inst_offset)) {
2916 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2918 g_assert_not_reached ();
2921 case OP_LOADR4_MEMBASE:
2922 if (ppc_is_imm16 (ins->inst_offset)) {
2923 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2925 g_assert_not_reached ();
2928 case OP_LOADR4_MEMINDEX:
2929 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2931 case OP_LOADR8_MEMINDEX:
2932 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2934 case OP_STORER4_MEMINDEX:
2935 ppc_frsp (code, ins->sreg1, ins->sreg1);
2936 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2938 case OP_STORER8_MEMINDEX:
2939 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2942 case CEE_CONV_R4: /* FIXME: change precision */
2944 g_assert_not_reached ();
2945 case OP_FCONV_TO_I1:
2946 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2948 case OP_FCONV_TO_U1:
2949 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2951 case OP_FCONV_TO_I2:
2952 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2954 case OP_FCONV_TO_U2:
2955 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2957 case OP_FCONV_TO_I4:
2959 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2961 case OP_FCONV_TO_U4:
2963 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2965 case OP_FCONV_TO_I8:
2966 case OP_FCONV_TO_U8:
2967 g_assert_not_reached ();
2968 /* Implemented as helper calls */
2970 case OP_LCONV_TO_R_UN:
2971 g_assert_not_reached ();
2972 /* Implemented as helper calls */
2974 case OP_LCONV_TO_OVF_I: {
2975 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2976 // Check if its negative
2977 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2978 negative_branch = code;
2979 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2980 // Its positive msword == 0
2981 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2982 msword_positive_branch = code;
2983 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2985 ovf_ex_target = code;
2986 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2988 ppc_patch (negative_branch, code);
2989 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2990 msword_negative_branch = code;
2991 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2992 ppc_patch (msword_negative_branch, ovf_ex_target);
2994 ppc_patch (msword_positive_branch, code);
2995 if (ins->dreg != ins->sreg1)
2996 ppc_mr (code, ins->dreg, ins->sreg1);
3000 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3003 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3006 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3009 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3012 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3015 ppc_fneg (code, ins->dreg, ins->sreg1);
3019 g_assert_not_reached ();
3022 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3025 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3026 ppc_li (code, ins->dreg, 0);
3027 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3028 ppc_li (code, ins->dreg, 1);
3031 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3032 ppc_li (code, ins->dreg, 1);
3033 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3034 ppc_li (code, ins->dreg, 0);
3037 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3038 ppc_li (code, ins->dreg, 1);
3039 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3040 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3041 ppc_li (code, ins->dreg, 0);
3044 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3045 ppc_li (code, ins->dreg, 1);
3046 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3047 ppc_li (code, ins->dreg, 0);
3050 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3051 ppc_li (code, ins->dreg, 1);
3052 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3053 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3054 ppc_li (code, ins->dreg, 0);
3057 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3060 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3063 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3064 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3067 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3068 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3071 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3072 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3075 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3076 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3079 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3080 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3083 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3086 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3087 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3090 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3093 g_assert_not_reached ();
3094 case OP_CHECK_FINITE: {
3095 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3096 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3097 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3098 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3102 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3103 g_assert_not_reached ();
3106 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3107 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3108 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3109 g_assert_not_reached ();
3115 last_offset = offset;
3120 cfg->code_len = code - cfg->native_code;
3124 mono_arch_register_lowlevel_calls (void)
3128 #define patch_lis_ori(ip,val) do {\
3129 guint16 *__lis_ori = (guint16*)(ip); \
3130 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3131 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3135 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3137 MonoJumpInfo *patch_info;
3139 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3140 unsigned char *ip = patch_info->ip.i + code;
3141 const unsigned char *target;
3143 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3145 switch (patch_info->type) {
3146 case MONO_PATCH_INFO_IP:
3147 patch_lis_ori (ip, ip);
3149 case MONO_PATCH_INFO_METHOD_REL:
3150 g_assert_not_reached ();
3151 *((gpointer *)(ip)) = code + patch_info->data.offset;
3153 case MONO_PATCH_INFO_SWITCH: {
3154 gpointer *table = (gpointer *)patch_info->data.table->table;
3157 patch_lis_ori (ip, table);
3159 for (i = 0; i < patch_info->data.table->table_size; i++) {
3160 table [i] = (int)patch_info->data.table->table [i] + code;
3162 /* we put into the table the absolute address, no need for ppc_patch in this case */
3165 case MONO_PATCH_INFO_METHODCONST:
3166 case MONO_PATCH_INFO_CLASS:
3167 case MONO_PATCH_INFO_IMAGE:
3168 case MONO_PATCH_INFO_FIELD:
3169 case MONO_PATCH_INFO_VTABLE:
3170 case MONO_PATCH_INFO_IID:
3171 case MONO_PATCH_INFO_SFLDA:
3172 case MONO_PATCH_INFO_LDSTR:
3173 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3174 case MONO_PATCH_INFO_LDTOKEN:
3175 /* from OP_AOTCONST : lis + ori */
3176 patch_lis_ori (ip, target);
3178 case MONO_PATCH_INFO_R4:
3179 case MONO_PATCH_INFO_R8:
3180 g_assert_not_reached ();
3181 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3183 case MONO_PATCH_INFO_EXC_NAME:
3184 g_assert_not_reached ();
3185 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3187 case MONO_PATCH_INFO_NONE:
3188 case MONO_PATCH_INFO_BB_OVF:
3189 case MONO_PATCH_INFO_EXC_OVF:
3190 /* everything is dealt with at epilog output time */
3195 ppc_patch (ip, target);
3200 * Stack frame layout:
3202 * ------------------- sp
3203 * MonoLMF structure or saved registers
3204 * -------------------
3206 * -------------------
3208 * -------------------
3209 * optional 8 bytes for tracing
3210 * -------------------
3211 * param area size is cfg->param_area
3212 * -------------------
3213 * linkage area size is PPC_STACK_PARAM_OFFSET
3214 * ------------------- sp
3218 mono_arch_emit_prolog (MonoCompile *cfg)
3220 MonoMethod *method = cfg->method;
3222 MonoMethodSignature *sig;
3224 int alloc_size, pos, max_offset, i;
3230 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3233 sig = mono_method_signature (method);
3234 cfg->code_size = 256 + sig->param_count * 20;
3235 code = cfg->native_code = g_malloc (cfg->code_size);
3237 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3238 ppc_mflr (code, ppc_r0);
3239 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3242 alloc_size = cfg->stack_offset;
3245 if (!method->save_lmf) {
3246 /*for (i = 31; i >= 14; --i) {
3247 if (cfg->used_float_regs & (1 << i)) {
3248 pos += sizeof (gdouble);
3249 ppc_stfd (code, i, -pos, ppc_sp);
3252 for (i = 31; i >= 13; --i) {
3253 if (cfg->used_int_regs & (1 << i)) {
3254 pos += sizeof (gulong);
3255 ppc_stw (code, i, -pos, ppc_sp);
3260 pos += sizeof (MonoLMF);
3262 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3263 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3264 for (i = 14; i < 32; i++) {
3265 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3269 // align to PPC_STACK_ALIGNMENT bytes
3270 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3271 alloc_size += PPC_STACK_ALIGNMENT - 1;
3272 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3275 cfg->stack_usage = alloc_size;
3276 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3278 if (ppc_is_imm16 (-alloc_size)) {
3279 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3281 ppc_load (code, ppc_r11, -alloc_size);
3282 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3285 if (cfg->frame_reg != ppc_sp)
3286 ppc_mr (code, cfg->frame_reg, ppc_sp);
3288 /* compute max_offset in order to use short forward jumps
3289 * we always do it on ppc because the immediate displacement
3290 * for jumps is too small
3293 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3294 MonoInst *ins = bb->code;
3295 bb->max_offset = max_offset;
3297 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3301 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3306 /* load arguments allocated to register from the stack */
3309 cinfo = calculate_sizes (sig, sig->pinvoke);
3311 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3312 ArgInfo *ainfo = &cinfo->ret;
3314 if (ppc_is_imm16 (inst->inst_offset)) {
3315 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3317 ppc_load (code, ppc_r11, inst->inst_offset);
3318 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3321 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3322 ArgInfo *ainfo = cinfo->args + i;
3323 inst = cfg->args [pos];
3325 if (cfg->verbose_level > 2)
3326 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3327 if (inst->opcode == OP_REGVAR) {
3328 if (ainfo->regtype == RegTypeGeneral)
3329 ppc_mr (code, inst->dreg, ainfo->reg);
3330 else if (ainfo->regtype == RegTypeFP)
3331 ppc_fmr (code, inst->dreg, ainfo->reg);
3332 else if (ainfo->regtype == RegTypeBase) {
3333 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3334 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3336 g_assert_not_reached ();
3338 if (cfg->verbose_level > 2)
3339 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3341 /* the argument should be put on the stack: FIXME handle size != word */
3342 if (ainfo->regtype == RegTypeGeneral) {
3343 switch (ainfo->size) {
3345 if (ppc_is_imm16 (inst->inst_offset)) {
3346 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3348 ppc_load (code, ppc_r11, inst->inst_offset);
3349 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3353 if (ppc_is_imm16 (inst->inst_offset)) {
3354 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3356 ppc_load (code, ppc_r11, inst->inst_offset);
3357 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3361 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3362 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3363 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3365 ppc_load (code, ppc_r11, inst->inst_offset);
3366 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3367 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3368 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3372 if (ppc_is_imm16 (inst->inst_offset)) {
3373 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3375 ppc_load (code, ppc_r11, inst->inst_offset);
3376 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3380 } else if (ainfo->regtype == RegTypeBase) {
3381 /* load the previous stack pointer in r11 */
3382 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3383 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3384 switch (ainfo->size) {
3386 if (ppc_is_imm16 (inst->inst_offset)) {
3387 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3389 ppc_load (code, ppc_r11, inst->inst_offset);
3390 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3394 if (ppc_is_imm16 (inst->inst_offset)) {
3395 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3397 ppc_load (code, ppc_r11, inst->inst_offset);
3398 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3402 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3403 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3404 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3405 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3408 g_assert_not_reached ();
3412 if (ppc_is_imm16 (inst->inst_offset)) {
3413 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3415 ppc_load (code, ppc_r11, inst->inst_offset);
3416 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3420 } else if (ainfo->regtype == RegTypeFP) {
3421 g_assert (ppc_is_imm16 (inst->inst_offset));
3422 if (ainfo->size == 8)
3423 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3424 else if (ainfo->size == 4)
3425 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3427 g_assert_not_reached ();
3428 } else if (ainfo->regtype == RegTypeStructByVal) {
3429 int doffset = inst->inst_offset;
3433 g_assert (ppc_is_imm16 (inst->inst_offset));
3434 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3435 if (mono_class_from_mono_type (inst->inst_vtype))
3436 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3437 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3439 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3440 register. Should this case include linux/ppc?
3444 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3446 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3449 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3450 soffset += sizeof (gpointer);
3451 doffset += sizeof (gpointer);
3453 if (ainfo->vtsize) {
3454 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3455 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3456 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3457 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3459 } else if (ainfo->regtype == RegTypeStructByAddr) {
3460 /* if it was originally a RegTypeBase */
3461 if (ainfo->offset) {
3462 /* load the previous stack pointer in r11 */
3463 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3464 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3466 ppc_mr (code, ppc_r11, ainfo->reg);
3468 g_assert (ppc_is_imm16 (inst->inst_offset));
3469 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3470 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3472 g_assert_not_reached ();
3477 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3478 ppc_load (code, ppc_r3, cfg->domain);
3479 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3480 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3481 ppc_lis (code, ppc_r0, 0);
3482 ppc_ori (code, ppc_r0, ppc_r0, 0);
3483 ppc_mtlr (code, ppc_r0);
3490 if (method->save_lmf) {
3491 if (lmf_pthread_key != -1) {
3492 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3493 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3494 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3496 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3497 (gpointer)"mono_get_lmf_addr");
3498 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3499 ppc_lis (code, ppc_r0, 0);
3500 ppc_ori (code, ppc_r0, ppc_r0, 0);
3501 ppc_mtlr (code, ppc_r0);
3507 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3508 /* lmf_offset is the offset from the previous stack pointer,
3509 * alloc_size is the total stack space allocated, so the offset
3510 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3511 * The pointer to the struct is put in ppc_r11 (new_lmf).
3512 * The callee-saved registers are already in the MonoLMF structure
3514 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3515 /* ppc_r3 is the result from mono_get_lmf_addr () */
3516 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3517 /* new_lmf->previous_lmf = *lmf_addr */
3518 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3519 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3520 /* *(lmf_addr) = r11 */
3521 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3522 /* save method info */
3523 ppc_load (code, ppc_r0, method);
3524 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3525 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3526 /* save the current IP */
3527 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3528 ppc_load (code, ppc_r0, 0x01010101);
3529 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3533 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3535 cfg->code_len = code - cfg->native_code;
3536 g_assert (cfg->code_len < cfg->code_size);
3543 mono_arch_emit_epilog (MonoCompile *cfg)
3545 MonoJumpInfo *patch_info;
3546 MonoMethod *method = cfg->method;
3548 int max_epilog_size = 16 + 20*4;
3551 if (cfg->method->save_lmf)
3552 max_epilog_size += 128;
3554 if (mono_jit_trace_calls != NULL)
3555 max_epilog_size += 50;
3557 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3558 max_epilog_size += 50;
3560 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3561 cfg->code_size *= 2;
3562 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3563 mono_jit_stats.code_reallocs++;
3567 * Keep in sync with OP_JMP
3569 code = cfg->native_code + cfg->code_len;
3571 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3572 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3576 if (method->save_lmf) {
3578 pos += sizeof (MonoLMF);
3580 /* save the frame reg in r8 */
3581 ppc_mr (code, ppc_r8, cfg->frame_reg);
3582 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3583 /* r5 = previous_lmf */
3584 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3586 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3587 /* *(lmf_addr) = previous_lmf */
3588 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3589 /* FIXME: speedup: there is no actual need to restore the registers if
3590 * we didn't actually change them (idea from Zoltan).
3593 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3595 /*for (i = 14; i < 32; i++) {
3596 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3598 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3599 /* use the saved copy of the frame reg in r8 */
3600 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3601 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3602 ppc_mtlr (code, ppc_r0);
3604 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3606 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3607 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3608 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3610 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3611 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3613 ppc_mtlr (code, ppc_r0);
3615 if (ppc_is_imm16 (cfg->stack_usage)) {
3616 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3618 ppc_load (code, ppc_r11, cfg->stack_usage);
3619 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3622 /*for (i = 31; i >= 14; --i) {
3623 if (cfg->used_float_regs & (1 << i)) {
3624 pos += sizeof (double);
3625 ppc_lfd (code, i, -pos, ppc_sp);
3628 for (i = 31; i >= 13; --i) {
3629 if (cfg->used_int_regs & (1 << i)) {
3630 pos += sizeof (gulong);
3631 ppc_lwz (code, i, -pos, ppc_sp);
3637 cfg->code_len = code - cfg->native_code;
3639 g_assert (cfg->code_len < cfg->code_size);
3643 /* remove once throw_exception_by_name is eliminated */
3645 exception_id_by_name (const char *name)
3647 if (strcmp (name, "IndexOutOfRangeException") == 0)
3648 return MONO_EXC_INDEX_OUT_OF_RANGE;
3649 if (strcmp (name, "OverflowException") == 0)
3650 return MONO_EXC_OVERFLOW;
3651 if (strcmp (name, "ArithmeticException") == 0)
3652 return MONO_EXC_ARITHMETIC;
3653 if (strcmp (name, "DivideByZeroException") == 0)
3654 return MONO_EXC_DIVIDE_BY_ZERO;
3655 if (strcmp (name, "InvalidCastException") == 0)
3656 return MONO_EXC_INVALID_CAST;
3657 if (strcmp (name, "NullReferenceException") == 0)
3658 return MONO_EXC_NULL_REF;
3659 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3660 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3661 g_error ("Unknown intrinsic exception %s\n", name);
3666 mono_arch_emit_exceptions (MonoCompile *cfg)
3668 MonoJumpInfo *patch_info;
3671 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3672 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3675 int max_epilog_size = 50;
3677 /* count the number of exception infos */
3680 * make sure we have enough space for exceptions
3681 * 24 is the simulated call to throw_exception_by_name
3683 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3684 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3685 i = exception_id_by_name (patch_info->data.target);
3686 if (!exc_throw_found [i]) {
3687 max_epilog_size += 24;
3688 exc_throw_found [i] = TRUE;
3690 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3691 max_epilog_size += 12;
3692 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3693 MonoOvfJump *ovfj = patch_info->data.target;
3694 i = exception_id_by_name (ovfj->data.exception);
3695 if (!exc_throw_found [i]) {
3696 max_epilog_size += 24;
3697 exc_throw_found [i] = TRUE;
3699 max_epilog_size += 8;
3703 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3704 cfg->code_size *= 2;
3705 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3706 mono_jit_stats.code_reallocs++;
3709 code = cfg->native_code + cfg->code_len;
3711 /* add code to raise exceptions */
3712 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3713 switch (patch_info->type) {
3714 case MONO_PATCH_INFO_BB_OVF: {
3715 MonoOvfJump *ovfj = patch_info->data.target;
3716 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3717 /* patch the initial jump */
3718 ppc_patch (ip, code);
3719 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3721 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3722 /* jump back to the true target */
3724 ip = ovfj->data.bb->native_offset + cfg->native_code;
3725 ppc_patch (code - 4, ip);
3728 case MONO_PATCH_INFO_EXC_OVF: {
3729 MonoOvfJump *ovfj = patch_info->data.target;
3730 MonoJumpInfo *newji;
3731 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3732 unsigned char *bcl = code;
3733 /* patch the initial jump: we arrived here with a call */
3734 ppc_patch (ip, code);
3735 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3737 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3738 /* patch the conditional jump to the right handler */
3739 /* make it processed next */
3740 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3741 newji->type = MONO_PATCH_INFO_EXC;
3742 newji->ip.i = bcl - cfg->native_code;
3743 newji->data.target = ovfj->data.exception;
3744 newji->next = patch_info->next;
3745 patch_info->next = newji;
3748 case MONO_PATCH_INFO_EXC: {
3749 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3750 i = exception_id_by_name (patch_info->data.target);
3751 if (exc_throw_pos [i]) {
3752 ppc_patch (ip, exc_throw_pos [i]);
3753 patch_info->type = MONO_PATCH_INFO_NONE;
3756 exc_throw_pos [i] = code;
3758 ppc_patch (ip, code);
3759 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3760 ppc_load (code, ppc_r3, patch_info->data.target);
3761 /* we got here from a conditional call, so the calling ip is set in lr already */
3762 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3763 patch_info->data.name = "mono_arch_throw_exception_by_name";
3764 patch_info->ip.i = code - cfg->native_code;
3765 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3766 ppc_lis (code, ppc_r0, 0);
3767 ppc_ori (code, ppc_r0, ppc_r0, 0);
3768 ppc_mtctr (code, ppc_r0);
3769 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3781 cfg->code_len = code - cfg->native_code;
3783 g_assert (cfg->code_len < cfg->code_size);
3788 try_offset_access (void *value, guint32 idx)
3790 register void* me __asm__ ("r2");
3791 void ***p = (void***)((char*)me + 284);
3792 int idx1 = idx / 32;
3793 int idx2 = idx % 32;
3796 if (value != p[idx1][idx2])
3802 setup_tls_access (void)
3805 guint32 *ins, *code;
3806 guint32 cmplwi_1023, li_0x48, blr_ins;
3807 if (tls_mode == TLS_MODE_FAILED)
3810 if (g_getenv ("MONO_NO_TLS")) {
3811 tls_mode = TLS_MODE_FAILED;
3815 if (tls_mode == TLS_MODE_DETECT) {
3816 ins = (guint32*)pthread_getspecific;
3817 /* uncond branch to the real method */
3818 if ((*ins >> 26) == 18) {
3820 val = (*ins & ~3) << 6;
3824 ins = (guint32*)val;
3826 ins = (guint32*) ((char*)ins + val);
3829 code = &cmplwi_1023;
3830 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3832 ppc_li (code, ppc_r4, 0x48);
3835 if (*ins == cmplwi_1023) {
3836 int found_lwz_284 = 0;
3837 for (ptk = 0; ptk < 20; ++ptk) {
3839 if (!*ins || *ins == blr_ins)
3841 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3846 if (!found_lwz_284) {
3847 tls_mode = TLS_MODE_FAILED;
3850 tls_mode = TLS_MODE_LTHREADS;
3851 } else if (*ins == li_0x48) {
3853 /* uncond branch to the real method */
3854 if ((*ins >> 26) == 18) {
3856 val = (*ins & ~3) << 6;
3860 ins = (guint32*)val;
3862 ins = (guint32*) ((char*)ins + val);
3865 ppc_li (code, ppc_r0, 0x7FF2);
3866 if (ins [1] == val) {
3867 /* Darwin on G4, implement */
3868 tls_mode = TLS_MODE_FAILED;
3872 ppc_mfspr (code, ppc_r3, 104);
3873 if (ins [1] != val) {
3874 tls_mode = TLS_MODE_FAILED;
3877 tls_mode = TLS_MODE_DARWIN_G5;
3880 tls_mode = TLS_MODE_FAILED;
3884 tls_mode = TLS_MODE_FAILED;
3888 if (monodomain_key == -1) {
3889 ptk = mono_domain_get_tls_key ();
3891 ptk = mono_pthread_key_for_tls (ptk);
3893 monodomain_key = ptk;
3897 if (lmf_pthread_key == -1) {
3898 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3900 /*g_print ("MonoLMF at: %d\n", ptk);*/
3901 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3902 init_tls_failed = 1;
3905 lmf_pthread_key = ptk;
3908 if (monothread_key == -1) {
3909 ptk = mono_thread_get_tls_key ();
3911 ptk = mono_pthread_key_for_tls (ptk);
3913 monothread_key = ptk;
3914 /*g_print ("thread inited: %d\n", ptk);*/
3917 /*g_print ("thread not inited yet %d\n", ptk);*/
3923 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3925 setup_tls_access ();
3929 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3934 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3936 int this_dreg = ppc_r3;
3941 /* add the this argument */
3942 if (this_reg != -1) {
3944 MONO_INST_NEW (cfg, this, OP_SETREG);
3945 this->type = this_type;
3946 this->sreg1 = this_reg;
3947 this->dreg = mono_regstate_next_int (cfg->rs);
3948 mono_bblock_add_inst (cfg->cbb, this);
3949 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3954 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3955 vtarg->type = STACK_MP;
3956 vtarg->sreg1 = vt_reg;
3957 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3958 mono_bblock_add_inst (cfg->cbb, vtarg);
3959 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3963 #ifdef MONO_ARCH_HAVE_IMT
3967 #define JUMP_IMM_SIZE 12
3968 #define ENABLE_WRONG_METHOD_CHECK 0
3971 * LOCKING: called with the domain lock held
3974 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3978 guint8 *code, *start;
3980 for (i = 0; i < count; ++i) {
3981 MonoIMTCheckItem *item = imt_entries [i];
3982 if (item->is_equals) {
3983 if (item->check_target_idx) {
3984 if (!item->compare_done)
3985 item->chunk_size += CMP_SIZE;
3986 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
3988 item->chunk_size += JUMP_IMM_SIZE;
3989 #if ENABLE_WRONG_METHOD_CHECK
3990 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
3994 item->chunk_size += CMP_SIZE + BR_SIZE;
3995 imt_entries [item->check_target_idx]->compare_done = TRUE;
3997 size += item->chunk_size;
3999 /* the initial load of the vtable address */
4001 code = mono_code_manager_reserve (domain->code_mp, size);
4003 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4004 for (i = 0; i < count; ++i) {
4005 MonoIMTCheckItem *item = imt_entries [i];
4006 item->code_target = code;
4007 if (item->is_equals) {
4008 if (item->check_target_idx) {
4009 if (!item->compare_done) {
4010 ppc_load (code, ppc_r0, (guint32)item->method);
4011 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4013 item->jmp_code = code;
4014 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4015 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4016 ppc_mtctr (code, ppc_r0);
4017 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4019 /* enable the commented code to assert on wrong method */
4020 #if ENABLE_WRONG_METHOD_CHECK
4021 ppc_load (code, ppc_r0, (guint32)item->method);
4022 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4023 item->jmp_code = code;
4024 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4026 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4027 ppc_mtctr (code, ppc_r0);
4028 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4029 #if ENABLE_WRONG_METHOD_CHECK
4030 ppc_patch (item->jmp_code, code);
4032 item->jmp_code = NULL;
4036 ppc_load (code, ppc_r0, (guint32)item->method);
4037 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4038 item->jmp_code = code;
4039 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4042 /* patch the branches to get to the target items */
4043 for (i = 0; i < count; ++i) {
4044 MonoIMTCheckItem *item = imt_entries [i];
4045 if (item->jmp_code) {
4046 if (item->check_target_idx) {
4047 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4052 mono_stats.imt_thunks_size += code - start;
4053 g_assert (code - start <= size);
4054 mono_arch_flush_icache (start, size);
4059 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4061 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4065 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4067 return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
4072 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4074 MonoInst *ins = NULL;
4076 if (cmethod->klass == mono_defaults.thread_class &&
4077 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4078 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4080 /*if (cmethod->klass == mono_defaults.math_class) {
4081 if (strcmp (cmethod->name, "Sqrt") == 0) {
4082 MONO_INST_NEW (cfg, ins, OP_SQRT);
4083 ins->inst_i0 = args [0];
4090 mono_arch_print_tree (MonoInst *tree, int arity)
4095 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4099 setup_tls_access ();
4100 if (monodomain_key == -1)
4103 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4104 ins->inst_offset = monodomain_key;
4109 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4113 setup_tls_access ();
4114 if (monothread_key == -1)
4117 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4118 ins->inst_offset = monothread_key;