2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 #include <sys/sysctl.h>
24 #define FORCE_INDIR_CALL 1
35 /* This mutex protects architecture specific caches */
36 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
37 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
38 static CRITICAL_SECTION mini_arch_mutex;
40 int mono_exc_esp_offset = 0;
41 static int tls_mode = TLS_MODE_DETECT;
42 static int lmf_pthread_key = -1;
43 static int monothread_key = -1;
44 static int monodomain_key = -1;
47 offsets_from_pthread_key (guint32 key, int *offset2)
51 *offset2 = idx2 * sizeof (gpointer);
52 return 284 + idx1 * sizeof (gpointer);
55 #define emit_linuxthreads_tls(code,dreg,key) do {\
57 off1 = offsets_from_pthread_key ((key), &off2); \
58 ppc_lwz ((code), (dreg), off1, ppc_r2); \
59 ppc_lwz ((code), (dreg), off2, (dreg)); \
62 #define emit_darwing5_tls(code,dreg,key) do {\
63 int off1 = 0x48 + key * sizeof (gpointer); \
64 ppc_mfspr ((code), (dreg), 104); \
65 ppc_lwz ((code), (dreg), off1, (dreg)); \
68 /* FIXME: ensure the sc call preserves all but r3 */
69 #define emit_darwing4_tls(code,dreg,key) do {\
70 int off1 = 0x48 + key * sizeof (gpointer); \
71 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
72 ppc_li ((code), ppc_r0, 0x7FF2); \
74 ppc_lwz ((code), (dreg), off1, ppc_r3); \
75 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
78 #define emit_tls_access(code,dreg,key) do { \
80 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
81 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
82 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
83 default: g_assert_not_reached (); \
88 mono_arch_regname (int reg) {
89 static const char rnames[][4] = {
90 "r0", "sp", "r2", "r3", "r4",
91 "r5", "r6", "r7", "r8", "r9",
92 "r10", "r11", "r12", "r13", "r14",
93 "r15", "r16", "r17", "r18", "r19",
94 "r20", "r21", "r22", "r23", "r24",
95 "r25", "r26", "r27", "r28", "r29",
98 if (reg >= 0 && reg < 32)
104 mono_arch_fregname (int reg) {
105 static const char rnames[][4] = {
106 "f0", "f1", "f2", "f3", "f4",
107 "f5", "f6", "f7", "f8", "f9",
108 "f10", "f11", "f12", "f13", "f14",
109 "f15", "f16", "f17", "f18", "f19",
110 "f20", "f21", "f22", "f23", "f24",
111 "f25", "f26", "f27", "f28", "f29",
114 if (reg >= 0 && reg < 32)
119 /* this function overwrites r0, r11, r12 */
121 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
123 /* unrolled, use the counter in big */
124 if (size > sizeof (gpointer) * 5) {
125 int shifted = size >> 2;
126 guint8 *copy_loop_start, *copy_loop_jump;
128 ppc_load (code, ppc_r0, shifted);
129 ppc_mtctr (code, ppc_r0);
130 g_assert (sreg == ppc_r11);
131 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
132 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
133 copy_loop_start = code;
134 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
135 ppc_stwu (code, ppc_r0, 4, ppc_r12);
136 copy_loop_jump = code;
137 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
138 ppc_patch (copy_loop_jump, copy_loop_start);
140 doffset = soffset = 0;
144 ppc_lwz (code, ppc_r0, soffset, sreg);
145 ppc_stw (code, ppc_r0, doffset, dreg);
151 ppc_lhz (code, ppc_r0, soffset, sreg);
152 ppc_sth (code, ppc_r0, doffset, dreg);
158 ppc_lbz (code, ppc_r0, soffset, sreg);
159 ppc_stb (code, ppc_r0, doffset, dreg);
168 * mono_arch_get_argument_info:
169 * @csig: a method signature
170 * @param_count: the number of parameters to consider
171 * @arg_info: an array to store the result infos
173 * Gathers information on parameters such as size, alignment and
174 * padding. arg_info should be large enought to hold param_count + 1 entries.
176 * Returns the size of the activation frame.
179 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
181 int k, frame_size = 0;
182 int size, align, pad;
185 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
186 frame_size += sizeof (gpointer);
190 arg_info [0].offset = offset;
193 frame_size += sizeof (gpointer);
197 arg_info [0].size = frame_size;
199 for (k = 0; k < param_count; k++) {
202 size = mono_type_native_stack_size (csig->params [k], &align);
204 size = mini_type_stack_size (NULL, csig->params [k], &align);
206 /* ignore alignment for now */
209 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
210 arg_info [k].pad = pad;
212 arg_info [k + 1].pad = 0;
213 arg_info [k + 1].size = size;
215 arg_info [k + 1].offset = offset;
219 align = MONO_ARCH_FRAME_ALIGNMENT;
220 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
221 arg_info [k].pad = pad;
227 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
231 guint32* code = (guint32*)code_ptr;
235 /* This is the 'blrl' instruction */
238 /* Sanity check: instruction must be 'blrl' */
239 if (*code != 0x4e800021)
242 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
243 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
247 /* OK, we're now at the 'blrl' instruction. Now walk backwards
248 till we get to a 'mtlr rA' */
250 if((*code & 0x7c0803a6) == 0x7c0803a6) {
252 /* Here we are: we reached the 'mtlr rA'.
253 Extract the register from the instruction */
254 reg = (*code & 0x03e00000) >> 21;
256 /* ok, this is a lwz reg, offset (vtreg)
257 * it is emitted with:
258 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
260 soff = (*code & 0xffff);
262 reg = (*code >> 16) & 0x1f;
263 g_assert (reg != ppc_r1);
264 /*g_print ("patching reg is %d\n", reg);*/
266 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
267 /* saved in the MonoLMF structure */
268 o = (gpointer)lmf->iregs [reg - 13];
275 *displacement = offset;
280 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
284 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
287 return (gpointer*)((char*)vt + displacement);
290 #define MAX_ARCH_DELEGATE_PARAMS 7
293 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
295 guint8 *code, *start;
297 /* FIXME: Support more cases */
298 if (MONO_TYPE_ISSTRUCT (sig->ret))
302 static guint8* cached = NULL;
303 mono_mini_arch_lock ();
305 mono_mini_arch_unlock ();
309 start = code = mono_global_codeman_reserve (16);
311 /* Replace the this argument with the target */
312 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
313 ppc_mtctr (code, ppc_r0);
314 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
315 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
317 g_assert ((code - start) <= 16);
319 mono_arch_flush_icache (start, 16);
321 mono_mini_arch_unlock ();
324 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
327 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
329 for (i = 0; i < sig->param_count; ++i)
330 if (!mono_is_regsize_var (sig->params [i]))
333 mono_mini_arch_lock ();
334 code = cache [sig->param_count];
336 mono_mini_arch_unlock ();
340 size = 12 + sig->param_count * 4;
341 start = code = mono_global_codeman_reserve (size);
343 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
344 ppc_mtctr (code, ppc_r0);
345 /* slide down the arguments */
346 for (i = 0; i < sig->param_count; ++i) {
347 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
349 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
351 g_assert ((code - start) <= size);
353 mono_arch_flush_icache (start, size);
354 cache [sig->param_count] = start;
355 mono_mini_arch_unlock ();
362 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
364 /* FIXME: handle returning a struct */
365 if (MONO_TYPE_ISSTRUCT (sig->ret))
366 return (gpointer)regs [ppc_r4];
367 return (gpointer)regs [ppc_r3];
371 * Initialize the cpu to execute managed code.
374 mono_arch_cpu_init (void)
379 * Initialize architecture specific code.
382 mono_arch_init (void)
384 InitializeCriticalSection (&mini_arch_mutex);
388 * Cleanup architecture specific code.
391 mono_arch_cleanup (void)
393 DeleteCriticalSection (&mini_arch_mutex);
397 * This function returns the optimizations supported on this cpu.
400 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
404 /* no ppc-specific optimizations yet */
410 is_regsize_var (MonoType *t) {
413 t = mono_type_get_underlying_type (t);
420 case MONO_TYPE_FNPTR:
422 case MONO_TYPE_OBJECT:
423 case MONO_TYPE_STRING:
424 case MONO_TYPE_CLASS:
425 case MONO_TYPE_SZARRAY:
426 case MONO_TYPE_ARRAY:
428 case MONO_TYPE_GENERICINST:
429 if (!mono_type_generic_inst_is_valuetype (t))
432 case MONO_TYPE_VALUETYPE:
439 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
444 for (i = 0; i < cfg->num_varinfo; i++) {
445 MonoInst *ins = cfg->varinfo [i];
446 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
449 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
452 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
455 /* we can only allocate 32 bit values */
456 if (is_regsize_var (ins->inst_vtype)) {
457 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
458 g_assert (i == vmv->idx);
459 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
467 mono_arch_get_global_int_regs (MonoCompile *cfg)
471 if (cfg->frame_reg != ppc_sp)
473 /* ppc_r13 is used by the system on PPC EABI */
474 for (i = 14; i < top; ++i)
475 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
481 * mono_arch_regalloc_cost:
483 * Return the cost, in number of memory references, of the action of
484 * allocating the variable VMV into a register during global register
488 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
500 mono_arch_flush_icache (guint8 *code, gint size)
502 guint8 *p, *endp, *start;
503 static int cachelinesize = 0;
504 static int cachelineinc = 16;
506 if (!cachelinesize) {
510 mib [1] = HW_CACHELINE;
511 len = sizeof (cachelinesize);
512 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
516 cachelineinc = cachelinesize;
517 /*g_print ("setting cl size to %d\n", cachelinesize);*/
519 #elif defined(__linux__)
520 /* sadly this will work only with 2.6 kernels... */
521 FILE* f = fopen ("/proc/self/auxv", "rb");
524 while (fread (&vec, sizeof (vec), 1, f) == 1) {
525 if (vec.type == 19) {
526 cachelinesize = vec.value;
535 #warning Need a way to get cache line size
541 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
542 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
544 for (p = start; p < endp; p += cachelineinc) {
545 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
548 for (p = start; p < endp; p += cachelineinc) {
549 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
554 for (p = start; p < endp; p += cachelineinc) {
555 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
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;
1146 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1148 if (is_virtual && i == 0) {
1149 /* the argument will be attached to the call instrucion */
1150 in = call->args [i];
1151 call->used_iregs |= 1 << ainfo->reg;
1153 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1154 in = call->args [i];
1155 arg->cil_code = in->cil_code;
1156 arg->inst_left = in;
1157 arg->inst_call = call;
1158 arg->type = in->type;
1159 MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1160 if (ainfo->regtype == RegTypeGeneral) {
1161 arg->backend.reg3 = ainfo->reg;
1162 call->used_iregs |= 1 << ainfo->reg;
1163 if (arg->type == STACK_I8)
1164 call->used_iregs |= 1 << (ainfo->reg + 1);
1165 } else if (ainfo->regtype == RegTypeStructByAddr) {
1166 if (ainfo->offset) {
1167 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1168 arg->opcode = OP_OUTARG_MEMBASE;
1169 ai->reg = ainfo->reg;
1170 ai->size = sizeof (gpointer);
1171 ai->offset = ainfo->offset;
1172 arg->backend.data = ai;
1174 arg->backend.reg3 = ainfo->reg;
1175 call->used_iregs |= 1 << ainfo->reg;
1177 } else if (ainfo->regtype == RegTypeStructByVal) {
1179 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1180 /* mark the used regs */
1181 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1182 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1184 arg->opcode = OP_OUTARG_VT;
1185 ai->reg = ainfo->reg;
1186 ai->size = ainfo->size;
1187 ai->vtsize = ainfo->vtsize;
1188 ai->offset = ainfo->offset;
1189 arg->backend.data = ai;
1190 } else if (ainfo->regtype == RegTypeBase) {
1191 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1192 arg->opcode = OP_OUTARG_MEMBASE;
1193 ai->reg = ainfo->reg;
1194 ai->size = ainfo->size;
1195 ai->offset = ainfo->offset;
1196 arg->backend.data = ai;
1197 } else if (ainfo->regtype == RegTypeFP) {
1198 arg->opcode = OP_OUTARG_R8;
1199 arg->backend.reg3 = ainfo->reg;
1200 call->used_fregs |= 1 << ainfo->reg;
1201 if (ainfo->size == 4) {
1202 arg->opcode = OP_OUTARG_R8;
1203 /* we reduce the precision */
1205 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1206 conv->inst_left = arg->inst_left;
1207 arg->inst_left = conv;*/
1210 g_assert_not_reached ();
1214 call->stack_usage = cinfo->stack_usage;
1215 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1216 cfg->flags |= MONO_CFG_HAS_CALLS;
1218 * should set more info in call, such as the stack space
1219 * used by the args that needs to be added back to esp
1227 * Allow tracing to work with this interface (with an optional argument)
1231 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1235 ppc_load (code, ppc_r3, cfg->method);
1236 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1237 ppc_load (code, ppc_r0, func);
1238 ppc_mtlr (code, ppc_r0);
1252 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1255 int save_mode = SAVE_NONE;
1257 MonoMethod *method = cfg->method;
1258 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1259 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1263 offset = code - cfg->native_code;
1264 /* we need about 16 instructions */
1265 if (offset > (cfg->code_size - 16 * 4)) {
1266 cfg->code_size *= 2;
1267 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1268 code = cfg->native_code + offset;
1272 case MONO_TYPE_VOID:
1273 /* special case string .ctor icall */
1274 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1275 save_mode = SAVE_ONE;
1277 save_mode = SAVE_NONE;
1281 save_mode = SAVE_TWO;
1285 save_mode = SAVE_FP;
1287 case MONO_TYPE_VALUETYPE:
1288 save_mode = SAVE_STRUCT;
1291 save_mode = SAVE_ONE;
1295 switch (save_mode) {
1297 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1298 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1299 if (enable_arguments) {
1300 ppc_mr (code, ppc_r5, ppc_r4);
1301 ppc_mr (code, ppc_r4, ppc_r3);
1305 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1306 if (enable_arguments) {
1307 ppc_mr (code, ppc_r4, ppc_r3);
1311 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1312 if (enable_arguments) {
1313 /* FIXME: what reg? */
1314 ppc_fmr (code, ppc_f3, ppc_f1);
1315 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1316 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1320 if (enable_arguments) {
1321 /* FIXME: get the actual address */
1322 ppc_mr (code, ppc_r4, ppc_r3);
1330 ppc_load (code, ppc_r3, cfg->method);
1331 ppc_load (code, ppc_r0, func);
1332 ppc_mtlr (code, ppc_r0);
1335 switch (save_mode) {
1337 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1338 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1341 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1344 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1354 * Conditional branches have a small offset, so if it is likely overflowed,
1355 * we do a branch to the end of the method (uncond branches have much larger
1356 * offsets) where we perform the conditional and jump back unconditionally.
1357 * It's slightly slower, since we add two uncond branches, but it's very simple
1358 * with the current patch implementation and such large methods are likely not
1359 * going to be perf critical anyway.
1364 const char *exception;
1371 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1372 if (ins->flags & MONO_INST_BRLABEL) { \
1373 if (0 && ins->inst_i0->inst_c0) { \
1374 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1376 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1377 ppc_bc (code, (b0), (b1), 0); \
1380 if (0 && ins->inst_true_bb->native_offset) { \
1381 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1383 int br_disp = ins->inst_true_bb->max_offset - offset; \
1384 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1385 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1386 ovfj->data.bb = ins->inst_true_bb; \
1387 ovfj->ip_offset = 0; \
1388 ovfj->b0_cond = (b0); \
1389 ovfj->b1_cond = (b1); \
1390 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1393 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1394 ppc_bc (code, (b0), (b1), 0); \
1399 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1401 /* emit an exception if condition is fail
1403 * We assign the extra code used to throw the implicit exceptions
1404 * to cfg->bb_exit as far as the big branch handling is concerned
1406 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1408 int br_disp = cfg->bb_exit->max_offset - offset; \
1409 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1410 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1411 ovfj->data.exception = (exc_name); \
1412 ovfj->ip_offset = code - cfg->native_code; \
1413 ovfj->b0_cond = (b0); \
1414 ovfj->b1_cond = (b1); \
1415 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1417 cfg->bb_exit->max_offset += 24; \
1419 mono_add_patch_info (cfg, code - cfg->native_code, \
1420 MONO_PATCH_INFO_EXC, exc_name); \
1421 ppc_bcl (code, (b0), (b1), 0); \
1425 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1428 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1432 MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
1433 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1434 switch (ins->opcode) {
1436 /* remove unnecessary multiplication with 1 */
1437 if (ins->inst_imm == 1) {
1438 if (ins->dreg != ins->sreg1) {
1439 ins->opcode = OP_MOVE;
1445 int power2 = mono_is_power_of_two (ins->inst_imm);
1447 ins->opcode = OP_SHL_IMM;
1448 ins->inst_imm = power2;
1452 case OP_LOAD_MEMBASE:
1453 case OP_LOADI4_MEMBASE:
1455 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1456 * OP_LOAD_MEMBASE offset(basereg), reg
1458 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1459 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1460 ins->inst_basereg == last_ins->inst_destbasereg &&
1461 ins->inst_offset == last_ins->inst_offset) {
1462 if (ins->dreg == last_ins->sreg1) {
1466 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1467 ins->opcode = OP_MOVE;
1468 ins->sreg1 = last_ins->sreg1;
1472 * Note: reg1 must be different from the basereg in the second load
1473 * OP_LOAD_MEMBASE offset(basereg), reg1
1474 * OP_LOAD_MEMBASE offset(basereg), reg2
1476 * OP_LOAD_MEMBASE offset(basereg), reg1
1477 * OP_MOVE reg1, reg2
1479 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1480 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1481 ins->inst_basereg != last_ins->dreg &&
1482 ins->inst_basereg == last_ins->inst_basereg &&
1483 ins->inst_offset == last_ins->inst_offset) {
1485 if (ins->dreg == last_ins->dreg) {
1489 ins->opcode = OP_MOVE;
1490 ins->sreg1 = last_ins->dreg;
1493 //g_assert_not_reached ();
1497 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1498 * OP_LOAD_MEMBASE offset(basereg), reg
1500 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1501 * OP_ICONST reg, imm
1503 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1504 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1505 ins->inst_basereg == last_ins->inst_destbasereg &&
1506 ins->inst_offset == last_ins->inst_offset) {
1507 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1508 ins->opcode = OP_ICONST;
1509 ins->inst_c0 = last_ins->inst_imm;
1510 g_assert_not_reached (); // check this rule
1514 case OP_LOADU1_MEMBASE:
1515 case OP_LOADI1_MEMBASE:
1516 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1517 ins->inst_basereg == last_ins->inst_destbasereg &&
1518 ins->inst_offset == last_ins->inst_offset) {
1519 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1520 ins->sreg1 = last_ins->sreg1;
1523 case OP_LOADU2_MEMBASE:
1524 case OP_LOADI2_MEMBASE:
1525 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1526 ins->inst_basereg == last_ins->inst_destbasereg &&
1527 ins->inst_offset == last_ins->inst_offset) {
1528 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1529 ins->sreg1 = last_ins->sreg1;
1536 ins->opcode = OP_MOVE;
1540 if (ins->dreg == ins->sreg1) {
1545 * OP_MOVE sreg, dreg
1546 * OP_MOVE dreg, sreg
1548 if (last_ins && last_ins->opcode == OP_MOVE &&
1549 ins->sreg1 == last_ins->dreg &&
1550 ins->dreg == last_ins->sreg1) {
1560 * the branch_b0_table should maintain the order of these
1574 branch_b0_table [] = {
1589 branch_b1_table [] = {
1603 #define NEW_INS(cfg,ins,dest,op) do { \
1604 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1605 (dest)->opcode = (op); \
1606 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1610 map_to_reg_reg_op (int op)
1619 case OP_COMPARE_IMM:
1635 case OP_LOAD_MEMBASE:
1636 return OP_LOAD_MEMINDEX;
1637 case OP_LOADI4_MEMBASE:
1638 return OP_LOADI4_MEMINDEX;
1639 case OP_LOADU4_MEMBASE:
1640 return OP_LOADU4_MEMINDEX;
1641 case OP_LOADU1_MEMBASE:
1642 return OP_LOADU1_MEMINDEX;
1643 case OP_LOADI2_MEMBASE:
1644 return OP_LOADI2_MEMINDEX;
1645 case OP_LOADU2_MEMBASE:
1646 return OP_LOADU2_MEMINDEX;
1647 case OP_LOADI1_MEMBASE:
1648 return OP_LOADI1_MEMINDEX;
1649 case OP_LOADR4_MEMBASE:
1650 return OP_LOADR4_MEMINDEX;
1651 case OP_LOADR8_MEMBASE:
1652 return OP_LOADR8_MEMINDEX;
1653 case OP_STOREI1_MEMBASE_REG:
1654 return OP_STOREI1_MEMINDEX;
1655 case OP_STOREI2_MEMBASE_REG:
1656 return OP_STOREI2_MEMINDEX;
1657 case OP_STOREI4_MEMBASE_REG:
1658 return OP_STOREI4_MEMINDEX;
1659 case OP_STORE_MEMBASE_REG:
1660 return OP_STORE_MEMINDEX;
1661 case OP_STORER4_MEMBASE_REG:
1662 return OP_STORER4_MEMINDEX;
1663 case OP_STORER8_MEMBASE_REG:
1664 return OP_STORER8_MEMINDEX;
1665 case OP_STORE_MEMBASE_IMM:
1666 return OP_STORE_MEMBASE_REG;
1667 case OP_STOREI1_MEMBASE_IMM:
1668 return OP_STOREI1_MEMBASE_REG;
1669 case OP_STOREI2_MEMBASE_IMM:
1670 return OP_STOREI2_MEMBASE_REG;
1671 case OP_STOREI4_MEMBASE_IMM:
1672 return OP_STOREI4_MEMBASE_REG;
1674 g_assert_not_reached ();
1677 #define compare_opcode_is_unsigned(opcode) \
1678 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1679 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1680 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1682 * Remove from the instruction list the instructions that can't be
1683 * represented with very simple instructions with no register
1687 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1689 MonoInst *ins, *next, *temp;
1692 /* setup the virtual reg allocator */
1693 if (bb->max_vreg > cfg->rs->next_vreg)
1694 cfg->rs->next_vreg = bb->max_vreg;
1696 MONO_BB_FOR_EACH_INS (bb, ins) {
1698 switch (ins->opcode) {
1701 if (!ppc_is_imm16 (ins->inst_imm)) {
1702 NEW_INS (cfg, ins, temp, OP_ICONST);
1703 temp->inst_c0 = ins->inst_imm;
1704 temp->dreg = mono_regstate_next_int (cfg->rs);
1705 ins->sreg2 = temp->dreg;
1706 ins->opcode = map_to_reg_reg_op (ins->opcode);
1710 if (!ppc_is_imm16 (-ins->inst_imm)) {
1711 NEW_INS (cfg, ins, temp, OP_ICONST);
1712 temp->inst_c0 = ins->inst_imm;
1713 temp->dreg = mono_regstate_next_int (cfg->rs);
1714 ins->sreg2 = temp->dreg;
1715 ins->opcode = map_to_reg_reg_op (ins->opcode);
1721 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1722 NEW_INS (cfg, ins, temp, OP_ICONST);
1723 temp->inst_c0 = ins->inst_imm;
1724 temp->dreg = mono_regstate_next_int (cfg->rs);
1725 ins->sreg2 = temp->dreg;
1726 ins->opcode = map_to_reg_reg_op (ins->opcode);
1732 NEW_INS (cfg, ins, temp, OP_ICONST);
1733 temp->inst_c0 = ins->inst_imm;
1734 temp->dreg = mono_regstate_next_int (cfg->rs);
1735 ins->sreg2 = temp->dreg;
1736 ins->opcode = map_to_reg_reg_op (ins->opcode);
1738 case OP_COMPARE_IMM:
1739 next = mono_inst_list_next (&ins->node, &bb->ins_list);
1741 if (compare_opcode_is_unsigned (next->opcode)) {
1742 if (!ppc_is_uimm16 (ins->inst_imm)) {
1743 NEW_INS (cfg, ins, temp, OP_ICONST);
1744 temp->inst_c0 = ins->inst_imm;
1745 temp->dreg = mono_regstate_next_int (cfg->rs);
1746 ins->sreg2 = temp->dreg;
1747 ins->opcode = map_to_reg_reg_op (ins->opcode);
1750 if (!ppc_is_imm16 (ins->inst_imm)) {
1751 NEW_INS (cfg, ins, temp, OP_ICONST);
1752 temp->inst_c0 = ins->inst_imm;
1753 temp->dreg = mono_regstate_next_int (cfg->rs);
1754 ins->sreg2 = temp->dreg;
1755 ins->opcode = map_to_reg_reg_op (ins->opcode);
1760 if (ins->inst_imm == 1) {
1761 ins->opcode = OP_MOVE;
1764 if (ins->inst_imm == 0) {
1765 ins->opcode = OP_ICONST;
1769 imm = mono_is_power_of_two (ins->inst_imm);
1771 ins->opcode = OP_SHL_IMM;
1772 ins->inst_imm = imm;
1775 if (!ppc_is_imm16 (ins->inst_imm)) {
1776 NEW_INS (cfg, ins, temp, OP_ICONST);
1777 temp->inst_c0 = ins->inst_imm;
1778 temp->dreg = mono_regstate_next_int (cfg->rs);
1779 ins->sreg2 = temp->dreg;
1780 ins->opcode = map_to_reg_reg_op (ins->opcode);
1783 case OP_LOAD_MEMBASE:
1784 case OP_LOADI4_MEMBASE:
1785 case OP_LOADU4_MEMBASE:
1786 case OP_LOADI2_MEMBASE:
1787 case OP_LOADU2_MEMBASE:
1788 case OP_LOADI1_MEMBASE:
1789 case OP_LOADU1_MEMBASE:
1790 case OP_LOADR4_MEMBASE:
1791 case OP_LOADR8_MEMBASE:
1792 case OP_STORE_MEMBASE_REG:
1793 case OP_STOREI4_MEMBASE_REG:
1794 case OP_STOREI2_MEMBASE_REG:
1795 case OP_STOREI1_MEMBASE_REG:
1796 case OP_STORER4_MEMBASE_REG:
1797 case OP_STORER8_MEMBASE_REG:
1798 /* we can do two things: load the immed in a register
1799 * and use an indexed load, or see if the immed can be
1800 * represented as an ad_imm + a load with a smaller offset
1801 * that fits. We just do the first for now, optimize later.
1803 if (ppc_is_imm16 (ins->inst_offset))
1805 NEW_INS (cfg, ins, temp, OP_ICONST);
1806 temp->inst_c0 = ins->inst_offset;
1807 temp->dreg = mono_regstate_next_int (cfg->rs);
1808 ins->sreg2 = temp->dreg;
1809 ins->opcode = map_to_reg_reg_op (ins->opcode);
1811 case OP_STORE_MEMBASE_IMM:
1812 case OP_STOREI1_MEMBASE_IMM:
1813 case OP_STOREI2_MEMBASE_IMM:
1814 case OP_STOREI4_MEMBASE_IMM:
1815 NEW_INS (cfg, ins, temp, OP_ICONST);
1816 temp->inst_c0 = ins->inst_imm;
1817 temp->dreg = mono_regstate_next_int (cfg->rs);
1818 ins->sreg1 = temp->dreg;
1819 ins->opcode = map_to_reg_reg_op (ins->opcode);
1820 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1823 NEW_INS (cfg, ins, temp, OP_ICONST);
1824 temp->inst_c0 = ins->inst_p0;
1825 temp->dreg = mono_regstate_next_int (cfg->rs);
1826 ins->inst_basereg = temp->dreg;
1827 ins->inst_offset = 0;
1828 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
1829 /* make it handle the possibly big ins->inst_offset
1830 * later optimize to use lis + load_membase
1835 bb->max_vreg = cfg->rs->next_vreg;
1840 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1842 if (MONO_INST_LIST_EMPTY (&bb->ins_list))
1844 mono_arch_lowering_pass (cfg, bb);
1845 mono_local_regalloc (cfg, bb);
1849 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1851 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1852 ppc_fctiwz (code, ppc_f0, sreg);
1853 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1854 ppc_lwz (code, dreg, -4, ppc_sp);
1857 ppc_andid (code, dreg, dreg, 0xff);
1859 ppc_andid (code, dreg, dreg, 0xffff);
1862 ppc_extsb (code, dreg, dreg);
1864 ppc_extsh (code, dreg, dreg);
1869 static unsigned char*
1870 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1873 int sreg = tree->sreg1;
1874 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1875 if (tree->flags & MONO_INST_INIT) {
1877 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1878 x86_push_reg (code, X86_EAX);
1881 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1882 x86_push_reg (code, X86_ECX);
1885 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1886 x86_push_reg (code, X86_EDI);
1890 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1891 if (sreg != X86_ECX)
1892 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1893 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1895 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1897 x86_prefix (code, X86_REP_PREFIX);
1900 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1901 x86_pop_reg (code, X86_EDI);
1902 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1903 x86_pop_reg (code, X86_ECX);
1904 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1905 x86_pop_reg (code, X86_EAX);
1918 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1921 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1922 PatchData *pdata = (PatchData*)user_data;
1923 guchar *code = data;
1924 guint32 *thunks = data;
1925 guint32 *endthunks = (guint32*)(code + bsize);
1929 int difflow, diffhigh;
1931 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1932 difflow = (char*)pdata->code - (char*)thunks;
1933 diffhigh = (char*)pdata->code - (char*)endthunks;
1934 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1937 templ = (guchar*)load;
1938 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1939 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1941 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1942 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1943 while (thunks < endthunks) {
1944 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1945 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1946 ppc_patch (pdata->code, (guchar*)thunks);
1947 mono_arch_flush_icache (pdata->code, 4);
1950 static int num_thunks = 0;
1952 if ((num_thunks % 20) == 0)
1953 g_print ("num_thunks lookup: %d\n", num_thunks);
1956 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1957 /* found a free slot instead: emit thunk */
1958 code = (guchar*)thunks;
1959 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1960 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1961 ppc_mtctr (code, ppc_r0);
1962 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1963 mono_arch_flush_icache ((guchar*)thunks, 16);
1965 ppc_patch (pdata->code, (guchar*)thunks);
1966 mono_arch_flush_icache (pdata->code, 4);
1969 static int num_thunks = 0;
1971 if ((num_thunks % 20) == 0)
1972 g_print ("num_thunks: %d\n", num_thunks);
1976 /* skip 16 bytes, the size of the thunk */
1980 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1986 handle_thunk (int absolute, guchar *code, guchar *target) {
1987 MonoDomain *domain = mono_domain_get ();
1991 pdata.target = target;
1992 pdata.absolute = absolute;
1995 mono_domain_lock (domain);
1996 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1999 /* this uses the first available slot */
2001 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2003 mono_domain_unlock (domain);
2005 if (pdata.found != 1)
2006 g_print ("thunk failed for %p from %p\n", target, code);
2007 g_assert (pdata.found == 1);
2011 ppc_patch (guchar *code, guchar *target)
2013 guint32 ins = *(guint32*)code;
2014 guint32 prim = ins >> 26;
2017 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2019 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2020 gint diff = target - code;
2022 if (diff <= 33554431){
2023 ins = (18 << 26) | (diff) | (ins & 1);
2024 *(guint32*)code = ins;
2028 /* diff between 0 and -33554432 */
2029 if (diff >= -33554432){
2030 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2031 *(guint32*)code = ins;
2036 if ((glong)target >= 0){
2037 if ((glong)target <= 33554431){
2038 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2039 *(guint32*)code = ins;
2043 if ((glong)target >= -33554432){
2044 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2045 *(guint32*)code = ins;
2050 handle_thunk (TRUE, code, target);
2053 g_assert_not_reached ();
2060 guint32 li = (guint32)target;
2061 ins = (ins & 0xffff0000) | (ins & 3);
2062 ovf = li & 0xffff0000;
2063 if (ovf != 0 && ovf != 0xffff0000)
2064 g_assert_not_reached ();
2067 // FIXME: assert the top bits of li are 0
2069 gint diff = target - code;
2070 ins = (ins & 0xffff0000) | (ins & 3);
2071 ovf = diff & 0xffff0000;
2072 if (ovf != 0 && ovf != 0xffff0000)
2073 g_assert_not_reached ();
2077 *(guint32*)code = ins;
2081 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2083 /* the trampoline code will try to patch the blrl, blr, bcctr */
2084 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2087 /* this is the lis/ori/mtlr/blrl sequence */
2088 seq = (guint32*)code;
2089 g_assert ((seq [0] >> 26) == 15);
2090 g_assert ((seq [1] >> 26) == 24);
2091 g_assert ((seq [2] >> 26) == 31);
2092 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2093 /* FIXME: make this thread safe */
2094 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2095 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2096 mono_arch_flush_icache (code - 8, 8);
2098 g_assert_not_reached ();
2100 // g_print ("patched with 0x%08x\n", ins);
2104 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2106 MonoInst *ins, *next;
2109 guint8 *code = cfg->native_code + cfg->code_len;
2110 guint last_offset = 0;
2113 if (cfg->opt & MONO_OPT_PEEPHOLE)
2114 peephole_pass (cfg, bb);
2116 /* we don't align basic blocks of loops on ppc */
2118 if (cfg->verbose_level > 2)
2119 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2121 cpos = bb->max_offset;
2123 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2124 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2125 //g_assert (!mono_compile_aot);
2128 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2129 /* this is not thread save, but good enough */
2130 /* fixme: howto handle overflows? */
2131 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2134 MONO_BB_FOR_EACH_INS (bb, ins) {
2135 offset = code - cfg->native_code;
2137 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2139 if (offset > (cfg->code_size - max_len - 16)) {
2140 cfg->code_size *= 2;
2141 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2142 code = cfg->native_code + offset;
2144 // if (ins->cil_code)
2145 // g_print ("cil code\n");
2146 mono_debug_record_line_number (cfg, ins, offset);
2148 switch (ins->opcode) {
2150 emit_tls_access (code, ins->dreg, ins->inst_offset);
2153 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2154 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2155 ppc_mr (code, ppc_r4, ppc_r0);
2158 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2159 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2160 ppc_mr (code, ppc_r4, ppc_r0);
2162 case OP_MEMORY_BARRIER:
2165 case OP_STOREI1_MEMBASE_REG:
2166 if (ppc_is_imm16 (ins->inst_offset)) {
2167 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2169 g_assert_not_reached ();
2172 case OP_STOREI2_MEMBASE_REG:
2173 if (ppc_is_imm16 (ins->inst_offset)) {
2174 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2176 g_assert_not_reached ();
2179 case OP_STORE_MEMBASE_REG:
2180 case OP_STOREI4_MEMBASE_REG:
2181 if (ppc_is_imm16 (ins->inst_offset)) {
2182 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2184 g_assert_not_reached ();
2187 case OP_STOREI1_MEMINDEX:
2188 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2190 case OP_STOREI2_MEMINDEX:
2191 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2193 case OP_STORE_MEMINDEX:
2194 case OP_STOREI4_MEMINDEX:
2195 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2200 g_assert_not_reached ();
2201 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2204 g_assert_not_reached ();
2206 case OP_LOAD_MEMBASE:
2207 case OP_LOADI4_MEMBASE:
2208 case OP_LOADU4_MEMBASE:
2209 if (ppc_is_imm16 (ins->inst_offset)) {
2210 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2212 g_assert_not_reached ();
2215 case OP_LOADI1_MEMBASE:
2216 case OP_LOADU1_MEMBASE:
2217 if (ppc_is_imm16 (ins->inst_offset)) {
2218 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2220 g_assert_not_reached ();
2222 if (ins->opcode == OP_LOADI1_MEMBASE)
2223 ppc_extsb (code, ins->dreg, ins->dreg);
2225 case OP_LOADU2_MEMBASE:
2226 if (ppc_is_imm16 (ins->inst_offset)) {
2227 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2229 g_assert_not_reached ();
2232 case OP_LOADI2_MEMBASE:
2233 if (ppc_is_imm16 (ins->inst_offset)) {
2234 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2236 g_assert_not_reached ();
2239 case OP_LOAD_MEMINDEX:
2240 case OP_LOADI4_MEMINDEX:
2241 case OP_LOADU4_MEMINDEX:
2242 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2244 case OP_LOADU2_MEMINDEX:
2245 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2247 case OP_LOADI2_MEMINDEX:
2248 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2250 case OP_LOADU1_MEMINDEX:
2251 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2253 case OP_LOADI1_MEMINDEX:
2254 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2255 ppc_extsb (code, ins->dreg, ins->dreg);
2258 ppc_extsb (code, ins->dreg, ins->sreg1);
2261 ppc_extsh (code, ins->dreg, ins->sreg1);
2264 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2267 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2270 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2271 if (next && compare_opcode_is_unsigned (next->opcode))
2272 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2274 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2276 case OP_COMPARE_IMM:
2277 next = mono_inst_list_next (&ins->node, &bb->ins_list);
2278 if (next && compare_opcode_is_unsigned (next->opcode)) {
2279 if (ppc_is_uimm16 (ins->inst_imm)) {
2280 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2282 g_assert_not_reached ();
2285 if (ppc_is_imm16 (ins->inst_imm)) {
2286 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2288 g_assert_not_reached ();
2296 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2299 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2302 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2305 if (ppc_is_imm16 (ins->inst_imm)) {
2306 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2308 g_assert_not_reached ();
2312 if (ppc_is_imm16 (ins->inst_imm)) {
2313 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2315 g_assert_not_reached ();
2319 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2321 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2322 ppc_mfspr (code, ppc_r0, ppc_xer);
2323 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2324 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2326 case CEE_ADD_OVF_UN:
2327 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2329 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2330 ppc_mfspr (code, ppc_r0, ppc_xer);
2331 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2332 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2335 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2337 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2338 ppc_mfspr (code, ppc_r0, ppc_xer);
2339 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2340 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2342 case CEE_SUB_OVF_UN:
2343 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2345 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2346 ppc_mfspr (code, ppc_r0, ppc_xer);
2347 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2348 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2350 case OP_ADD_OVF_CARRY:
2351 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2353 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2354 ppc_mfspr (code, ppc_r0, ppc_xer);
2355 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2356 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2358 case OP_ADD_OVF_UN_CARRY:
2359 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2361 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2362 ppc_mfspr (code, ppc_r0, ppc_xer);
2363 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2364 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2366 case OP_SUB_OVF_CARRY:
2367 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2369 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2370 ppc_mfspr (code, ppc_r0, ppc_xer);
2371 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2372 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2374 case OP_SUB_OVF_UN_CARRY:
2375 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2377 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2378 ppc_mfspr (code, ppc_r0, ppc_xer);
2379 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2380 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2383 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2386 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2389 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2392 // we add the negated value
2393 if (ppc_is_imm16 (-ins->inst_imm))
2394 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2396 g_assert_not_reached ();
2400 g_assert (ppc_is_imm16 (ins->inst_imm));
2401 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2404 ppc_subfze (code, ins->dreg, ins->sreg1);
2407 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2408 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2411 if (!(ins->inst_imm & 0xffff0000)) {
2412 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2413 } else if (!(ins->inst_imm & 0xffff)) {
2414 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2416 g_assert_not_reached ();
2420 guint32 *divisor_is_m1;
2421 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2423 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2424 divisor_is_m1 = code;
2425 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2426 ppc_lis (code, ppc_r0, 0x8000);
2427 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2428 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2429 ppc_patch (divisor_is_m1, code);
2430 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2432 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2433 ppc_mfspr (code, ppc_r0, ppc_xer);
2434 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2435 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2439 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2440 ppc_mfspr (code, ppc_r0, ppc_xer);
2441 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2442 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2448 g_assert_not_reached ();
2450 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2453 if (!(ins->inst_imm & 0xffff0000)) {
2454 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2455 } else if (!(ins->inst_imm & 0xffff)) {
2456 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2458 g_assert_not_reached ();
2462 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2465 if (!(ins->inst_imm & 0xffff0000)) {
2466 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2467 } else if (!(ins->inst_imm & 0xffff)) {
2468 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2470 g_assert_not_reached ();
2474 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2477 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2480 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2483 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2487 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2489 ppc_mr (code, ins->dreg, ins->sreg1);
2492 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2495 ppc_not (code, ins->dreg, ins->sreg1);
2498 ppc_neg (code, ins->dreg, ins->sreg1);
2501 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2504 if (ppc_is_imm16 (ins->inst_imm)) {
2505 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2507 g_assert_not_reached ();
2511 /* we annot use mcrxr, since it's not implemented on some processors
2512 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2514 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2515 ppc_mfspr (code, ppc_r0, ppc_xer);
2516 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2517 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2519 case CEE_MUL_OVF_UN:
2520 /* we first multiply to get the high word and compare to 0
2521 * to set the flags, then the result is discarded and then
2522 * we multiply to get the lower * bits result
2524 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2525 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2526 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2527 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2531 ppc_load (code, ins->dreg, ins->inst_c0);
2534 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2535 ppc_lis (code, ins->dreg, 0);
2536 ppc_ori (code, ins->dreg, ins->dreg, 0);
2542 ppc_mr (code, ins->dreg, ins->sreg1);
2545 int saved = ins->sreg1;
2546 if (ins->sreg1 == ppc_r3) {
2547 ppc_mr (code, ppc_r0, ins->sreg1);
2550 if (ins->sreg2 != ppc_r3)
2551 ppc_mr (code, ppc_r3, ins->sreg2);
2552 if (saved != ppc_r4)
2553 ppc_mr (code, ppc_r4, saved);
2558 ppc_fmr (code, ins->dreg, ins->sreg1);
2560 case OP_FCONV_TO_R4:
2561 ppc_frsp (code, ins->dreg, ins->sreg1);
2567 * Keep in sync with mono_arch_emit_epilog
2569 g_assert (!cfg->method->save_lmf);
2571 * Note: we can use ppc_r11 here because it is dead anyway:
2572 * we're leaving the method.
2574 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2575 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2576 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2578 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2579 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2581 ppc_mtlr (code, ppc_r0);
2583 if (ppc_is_imm16 (cfg->stack_usage)) {
2584 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2586 ppc_load (code, ppc_r11, cfg->stack_usage);
2587 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2589 if (!cfg->method->save_lmf) {
2590 /*for (i = 31; i >= 14; --i) {
2591 if (cfg->used_float_regs & (1 << i)) {
2592 pos += sizeof (double);
2593 ppc_lfd (code, i, -pos, cfg->frame_reg);
2596 for (i = 31; i >= 13; --i) {
2597 if (cfg->used_int_regs & (1 << i)) {
2598 pos += sizeof (gulong);
2599 ppc_lwz (code, i, -pos, cfg->frame_reg);
2603 /* FIXME restore from MonoLMF: though this can't happen yet */
2605 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2610 /* ensure ins->sreg1 is not NULL */
2611 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2614 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2615 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2617 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
2618 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
2620 ppc_stw (code, ppc_r0, 0, ins->sreg1);
2628 call = (MonoCallInst*)ins;
2629 if (ins->flags & MONO_INST_HAS_METHOD)
2630 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2632 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2633 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2634 ppc_lis (code, ppc_r0, 0);
2635 ppc_ori (code, ppc_r0, ppc_r0, 0);
2636 ppc_mtlr (code, ppc_r0);
2645 case OP_VOIDCALL_REG:
2647 ppc_mtlr (code, ins->sreg1);
2650 case OP_FCALL_MEMBASE:
2651 case OP_LCALL_MEMBASE:
2652 case OP_VCALL_MEMBASE:
2653 case OP_VOIDCALL_MEMBASE:
2654 case OP_CALL_MEMBASE:
2655 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2656 ppc_mtlr (code, ppc_r0);
2660 g_assert_not_reached ();
2663 guint32 * zero_loop_jump, * zero_loop_start;
2664 /* keep alignment */
2665 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2666 int area_offset = alloca_waste;
2668 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2669 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2670 /* use ctr to store the number of words to 0 if needed */
2671 if (ins->flags & MONO_INST_INIT) {
2672 /* we zero 4 bytes at a time:
2673 * we add 7 instead of 3 so that we set the counter to
2674 * at least 1, otherwise the bdnz instruction will make
2675 * it negative and iterate billions of times.
2677 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2678 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2679 ppc_mtctr (code, ppc_r0);
2681 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2682 ppc_neg (code, ppc_r11, ppc_r11);
2683 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2685 if (ins->flags & MONO_INST_INIT) {
2686 /* adjust the dest reg by -4 so we can use stwu */
2687 /* we actually adjust -8 because we let the loop
2690 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2691 ppc_li (code, ppc_r11, 0);
2692 zero_loop_start = code;
2693 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2694 zero_loop_jump = code;
2695 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2696 ppc_patch (zero_loop_jump, zero_loop_start);
2698 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2706 ppc_mr (code, ppc_r3, ins->sreg1);
2707 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2708 (gpointer)"mono_arch_throw_exception");
2709 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2710 ppc_lis (code, ppc_r0, 0);
2711 ppc_ori (code, ppc_r0, ppc_r0, 0);
2712 ppc_mtlr (code, ppc_r0);
2721 ppc_mr (code, ppc_r3, ins->sreg1);
2722 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2723 (gpointer)"mono_arch_rethrow_exception");
2724 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2725 ppc_lis (code, ppc_r0, 0);
2726 ppc_ori (code, ppc_r0, ppc_r0, 0);
2727 ppc_mtlr (code, ppc_r0);
2734 case OP_START_HANDLER:
2735 ppc_mflr (code, ppc_r0);
2736 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2737 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2739 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2740 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2744 if (ins->sreg1 != ppc_r3)
2745 ppc_mr (code, ppc_r3, ins->sreg1);
2746 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2747 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2749 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2750 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2752 ppc_mtlr (code, ppc_r0);
2756 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2757 ppc_mtlr (code, ppc_r0);
2760 case OP_CALL_HANDLER:
2761 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2765 ins->inst_c0 = code - cfg->native_code;
2768 if (ins->flags & MONO_INST_BRLABEL) {
2769 /*if (ins->inst_i0->inst_c0) {
2771 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2773 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2777 /*if (ins->inst_target_bb->native_offset) {
2779 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2781 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2787 ppc_mtctr (code, ins->sreg1);
2788 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2791 ppc_li (code, ins->dreg, 0);
2792 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2793 ppc_li (code, ins->dreg, 1);
2797 ppc_li (code, ins->dreg, 1);
2798 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2799 ppc_li (code, ins->dreg, 0);
2803 ppc_li (code, ins->dreg, 1);
2804 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2805 ppc_li (code, ins->dreg, 0);
2807 case OP_COND_EXC_EQ:
2808 case OP_COND_EXC_NE_UN:
2809 case OP_COND_EXC_LT:
2810 case OP_COND_EXC_LT_UN:
2811 case OP_COND_EXC_GT:
2812 case OP_COND_EXC_GT_UN:
2813 case OP_COND_EXC_GE:
2814 case OP_COND_EXC_GE_UN:
2815 case OP_COND_EXC_LE:
2816 case OP_COND_EXC_LE_UN:
2817 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2820 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2822 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2823 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2824 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2826 case OP_COND_EXC_OV:
2827 /*ppc_mcrxr (code, 0);
2828 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2830 case OP_COND_EXC_NC:
2831 case OP_COND_EXC_NO:
2832 g_assert_not_reached ();
2844 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2847 /* floating point opcodes */
2850 g_assert_not_reached ();
2851 case OP_STORER8_MEMBASE_REG:
2852 if (ppc_is_imm16 (ins->inst_offset)) {
2853 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2855 g_assert_not_reached ();
2858 case OP_LOADR8_MEMBASE:
2859 if (ppc_is_imm16 (ins->inst_offset)) {
2860 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2862 g_assert_not_reached ();
2865 case OP_STORER4_MEMBASE_REG:
2866 ppc_frsp (code, ins->sreg1, ins->sreg1);
2867 if (ppc_is_imm16 (ins->inst_offset)) {
2868 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2870 g_assert_not_reached ();
2873 case OP_LOADR4_MEMBASE:
2874 if (ppc_is_imm16 (ins->inst_offset)) {
2875 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2877 g_assert_not_reached ();
2880 case OP_LOADR4_MEMINDEX:
2881 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2883 case OP_LOADR8_MEMINDEX:
2884 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2886 case OP_STORER4_MEMINDEX:
2887 ppc_frsp (code, ins->sreg1, ins->sreg1);
2888 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2890 case OP_STORER8_MEMINDEX:
2891 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2894 case CEE_CONV_R4: /* FIXME: change precision */
2896 g_assert_not_reached ();
2897 case OP_FCONV_TO_I1:
2898 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2900 case OP_FCONV_TO_U1:
2901 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2903 case OP_FCONV_TO_I2:
2904 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2906 case OP_FCONV_TO_U2:
2907 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2909 case OP_FCONV_TO_I4:
2911 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2913 case OP_FCONV_TO_U4:
2915 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2917 case OP_FCONV_TO_I8:
2918 case OP_FCONV_TO_U8:
2919 g_assert_not_reached ();
2920 /* Implemented as helper calls */
2922 case OP_LCONV_TO_R_UN:
2923 g_assert_not_reached ();
2924 /* Implemented as helper calls */
2926 case OP_LCONV_TO_OVF_I: {
2927 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2928 // Check if its negative
2929 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2930 negative_branch = code;
2931 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2932 // Its positive msword == 0
2933 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2934 msword_positive_branch = code;
2935 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2937 ovf_ex_target = code;
2938 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2940 ppc_patch (negative_branch, code);
2941 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2942 msword_negative_branch = code;
2943 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2944 ppc_patch (msword_negative_branch, ovf_ex_target);
2946 ppc_patch (msword_positive_branch, code);
2947 if (ins->dreg != ins->sreg1)
2948 ppc_mr (code, ins->dreg, ins->sreg1);
2952 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2955 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2958 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2961 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2964 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2967 ppc_fneg (code, ins->dreg, ins->sreg1);
2971 g_assert_not_reached ();
2974 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2977 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2978 ppc_li (code, ins->dreg, 0);
2979 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2980 ppc_li (code, ins->dreg, 1);
2983 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2984 ppc_li (code, ins->dreg, 1);
2985 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2986 ppc_li (code, ins->dreg, 0);
2989 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2990 ppc_li (code, ins->dreg, 1);
2991 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2992 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2993 ppc_li (code, ins->dreg, 0);
2996 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2997 ppc_li (code, ins->dreg, 1);
2998 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2999 ppc_li (code, ins->dreg, 0);
3002 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3003 ppc_li (code, ins->dreg, 1);
3004 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3005 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3006 ppc_li (code, ins->dreg, 0);
3009 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3012 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3015 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3016 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3019 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3020 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3023 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3024 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3027 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3028 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3031 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3032 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3035 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3038 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3039 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3042 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3045 g_assert_not_reached ();
3046 case OP_CHECK_FINITE: {
3047 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3048 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3049 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3050 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3054 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3055 g_assert_not_reached ();
3058 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3059 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3060 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3061 g_assert_not_reached ();
3066 last_offset = offset;
3069 cfg->code_len = code - cfg->native_code;
3073 mono_arch_register_lowlevel_calls (void)
3077 #define patch_lis_ori(ip,val) do {\
3078 guint16 *__lis_ori = (guint16*)(ip); \
3079 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3080 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3084 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3086 MonoJumpInfo *patch_info;
3088 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3089 unsigned char *ip = patch_info->ip.i + code;
3090 const unsigned char *target;
3092 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3094 switch (patch_info->type) {
3095 case MONO_PATCH_INFO_IP:
3096 patch_lis_ori (ip, ip);
3098 case MONO_PATCH_INFO_METHOD_REL:
3099 g_assert_not_reached ();
3100 *((gpointer *)(ip)) = code + patch_info->data.offset;
3102 case MONO_PATCH_INFO_SWITCH: {
3103 gpointer *table = (gpointer *)patch_info->data.table->table;
3106 patch_lis_ori (ip, table);
3108 for (i = 0; i < patch_info->data.table->table_size; i++) {
3109 table [i] = (int)patch_info->data.table->table [i] + code;
3111 /* we put into the table the absolute address, no need for ppc_patch in this case */
3114 case MONO_PATCH_INFO_METHODCONST:
3115 case MONO_PATCH_INFO_CLASS:
3116 case MONO_PATCH_INFO_IMAGE:
3117 case MONO_PATCH_INFO_FIELD:
3118 case MONO_PATCH_INFO_VTABLE:
3119 case MONO_PATCH_INFO_IID:
3120 case MONO_PATCH_INFO_SFLDA:
3121 case MONO_PATCH_INFO_LDSTR:
3122 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3123 case MONO_PATCH_INFO_LDTOKEN:
3124 /* from OP_AOTCONST : lis + ori */
3125 patch_lis_ori (ip, target);
3127 case MONO_PATCH_INFO_R4:
3128 case MONO_PATCH_INFO_R8:
3129 g_assert_not_reached ();
3130 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3132 case MONO_PATCH_INFO_EXC_NAME:
3133 g_assert_not_reached ();
3134 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3136 case MONO_PATCH_INFO_NONE:
3137 case MONO_PATCH_INFO_BB_OVF:
3138 case MONO_PATCH_INFO_EXC_OVF:
3139 /* everything is dealt with at epilog output time */
3144 ppc_patch (ip, target);
3149 * Stack frame layout:
3151 * ------------------- sp
3152 * MonoLMF structure or saved registers
3153 * -------------------
3155 * -------------------
3157 * -------------------
3158 * optional 8 bytes for tracing
3159 * -------------------
3160 * param area size is cfg->param_area
3161 * -------------------
3162 * linkage area size is PPC_STACK_PARAM_OFFSET
3163 * ------------------- sp
3167 mono_arch_emit_prolog (MonoCompile *cfg)
3169 MonoMethod *method = cfg->method;
3171 MonoMethodSignature *sig;
3173 int alloc_size, pos, max_offset, i;
3179 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3182 sig = mono_method_signature (method);
3183 cfg->code_size = 256 + sig->param_count * 20;
3184 code = cfg->native_code = g_malloc (cfg->code_size);
3186 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3187 ppc_mflr (code, ppc_r0);
3188 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3191 alloc_size = cfg->stack_offset;
3194 if (!method->save_lmf) {
3195 /*for (i = 31; i >= 14; --i) {
3196 if (cfg->used_float_regs & (1 << i)) {
3197 pos += sizeof (gdouble);
3198 ppc_stfd (code, i, -pos, ppc_sp);
3201 for (i = 31; i >= 13; --i) {
3202 if (cfg->used_int_regs & (1 << i)) {
3203 pos += sizeof (gulong);
3204 ppc_stw (code, i, -pos, ppc_sp);
3209 pos += sizeof (MonoLMF);
3211 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3212 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3213 for (i = 14; i < 32; i++) {
3214 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3218 // align to PPC_STACK_ALIGNMENT bytes
3219 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3220 alloc_size += PPC_STACK_ALIGNMENT - 1;
3221 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3224 cfg->stack_usage = alloc_size;
3225 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3227 if (ppc_is_imm16 (-alloc_size)) {
3228 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3230 ppc_load (code, ppc_r11, -alloc_size);
3231 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3234 if (cfg->frame_reg != ppc_sp)
3235 ppc_mr (code, cfg->frame_reg, ppc_sp);
3237 /* compute max_offset in order to use short forward jumps
3238 * we always do it on ppc because the immediate displacement
3239 * for jumps is too small
3242 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3244 bb->max_offset = max_offset;
3246 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3249 MONO_BB_FOR_EACH_INS (bb, ins) {
3250 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3253 /* load arguments allocated to register from the stack */
3256 cinfo = calculate_sizes (sig, sig->pinvoke);
3258 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3259 ArgInfo *ainfo = &cinfo->ret;
3261 if (ppc_is_imm16 (inst->inst_offset)) {
3262 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3264 ppc_load (code, ppc_r11, inst->inst_offset);
3265 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3268 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3269 ArgInfo *ainfo = cinfo->args + i;
3270 inst = cfg->args [pos];
3272 if (cfg->verbose_level > 2)
3273 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3274 if (inst->opcode == OP_REGVAR) {
3275 if (ainfo->regtype == RegTypeGeneral)
3276 ppc_mr (code, inst->dreg, ainfo->reg);
3277 else if (ainfo->regtype == RegTypeFP)
3278 ppc_fmr (code, inst->dreg, ainfo->reg);
3279 else if (ainfo->regtype == RegTypeBase) {
3280 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3281 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3283 g_assert_not_reached ();
3285 if (cfg->verbose_level > 2)
3286 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3288 /* the argument should be put on the stack: FIXME handle size != word */
3289 if (ainfo->regtype == RegTypeGeneral) {
3290 switch (ainfo->size) {
3292 if (ppc_is_imm16 (inst->inst_offset)) {
3293 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3295 ppc_load (code, ppc_r11, inst->inst_offset);
3296 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3300 if (ppc_is_imm16 (inst->inst_offset)) {
3301 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3303 ppc_load (code, ppc_r11, inst->inst_offset);
3304 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3308 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3309 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3310 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3312 ppc_load (code, ppc_r11, inst->inst_offset);
3313 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3314 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3315 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3319 if (ppc_is_imm16 (inst->inst_offset)) {
3320 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3322 ppc_load (code, ppc_r11, inst->inst_offset);
3323 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3327 } else if (ainfo->regtype == RegTypeBase) {
3328 /* load the previous stack pointer in r11 */
3329 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3330 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3331 switch (ainfo->size) {
3333 if (ppc_is_imm16 (inst->inst_offset)) {
3334 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3336 ppc_load (code, ppc_r11, inst->inst_offset);
3337 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3341 if (ppc_is_imm16 (inst->inst_offset)) {
3342 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3344 ppc_load (code, ppc_r11, inst->inst_offset);
3345 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3349 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3350 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3351 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3352 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3355 g_assert_not_reached ();
3359 if (ppc_is_imm16 (inst->inst_offset)) {
3360 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3362 ppc_load (code, ppc_r11, inst->inst_offset);
3363 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3367 } else if (ainfo->regtype == RegTypeFP) {
3368 g_assert (ppc_is_imm16 (inst->inst_offset));
3369 if (ainfo->size == 8)
3370 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3371 else if (ainfo->size == 4)
3372 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3374 g_assert_not_reached ();
3375 } else if (ainfo->regtype == RegTypeStructByVal) {
3376 int doffset = inst->inst_offset;
3380 g_assert (ppc_is_imm16 (inst->inst_offset));
3381 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3382 if (mono_class_from_mono_type (inst->inst_vtype))
3383 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3384 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3386 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3387 register. Should this case include linux/ppc?
3391 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3393 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3396 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3397 soffset += sizeof (gpointer);
3398 doffset += sizeof (gpointer);
3400 if (ainfo->vtsize) {
3401 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3402 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3403 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3404 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3406 } else if (ainfo->regtype == RegTypeStructByAddr) {
3407 /* if it was originally a RegTypeBase */
3408 if (ainfo->offset) {
3409 /* load the previous stack pointer in r11 */
3410 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3411 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3413 ppc_mr (code, ppc_r11, ainfo->reg);
3415 g_assert (ppc_is_imm16 (inst->inst_offset));
3416 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3417 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3419 g_assert_not_reached ();
3424 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3425 ppc_load (code, ppc_r3, cfg->domain);
3426 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3427 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3428 ppc_lis (code, ppc_r0, 0);
3429 ppc_ori (code, ppc_r0, ppc_r0, 0);
3430 ppc_mtlr (code, ppc_r0);
3437 if (method->save_lmf) {
3438 if (lmf_pthread_key != -1) {
3439 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3440 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3441 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3443 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3444 (gpointer)"mono_get_lmf_addr");
3445 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3446 ppc_lis (code, ppc_r0, 0);
3447 ppc_ori (code, ppc_r0, ppc_r0, 0);
3448 ppc_mtlr (code, ppc_r0);
3454 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3455 /* lmf_offset is the offset from the previous stack pointer,
3456 * alloc_size is the total stack space allocated, so the offset
3457 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3458 * The pointer to the struct is put in ppc_r11 (new_lmf).
3459 * The callee-saved registers are already in the MonoLMF structure
3461 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3462 /* ppc_r3 is the result from mono_get_lmf_addr () */
3463 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3464 /* new_lmf->previous_lmf = *lmf_addr */
3465 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3466 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3467 /* *(lmf_addr) = r11 */
3468 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3469 /* save method info */
3470 ppc_load (code, ppc_r0, method);
3471 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3472 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3473 /* save the current IP */
3474 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3475 ppc_load (code, ppc_r0, 0x01010101);
3476 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3480 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3482 cfg->code_len = code - cfg->native_code;
3483 g_assert (cfg->code_len < cfg->code_size);
3490 mono_arch_emit_epilog (MonoCompile *cfg)
3492 MonoJumpInfo *patch_info;
3493 MonoMethod *method = cfg->method;
3495 int max_epilog_size = 16 + 20*4;
3498 if (cfg->method->save_lmf)
3499 max_epilog_size += 128;
3501 if (mono_jit_trace_calls != NULL)
3502 max_epilog_size += 50;
3504 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3505 max_epilog_size += 50;
3507 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3508 cfg->code_size *= 2;
3509 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3510 mono_jit_stats.code_reallocs++;
3514 * Keep in sync with OP_JMP
3516 code = cfg->native_code + cfg->code_len;
3518 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3519 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3523 if (method->save_lmf) {
3525 pos += sizeof (MonoLMF);
3527 /* save the frame reg in r8 */
3528 ppc_mr (code, ppc_r8, cfg->frame_reg);
3529 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3530 /* r5 = previous_lmf */
3531 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3533 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3534 /* *(lmf_addr) = previous_lmf */
3535 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3536 /* FIXME: speedup: there is no actual need to restore the registers if
3537 * we didn't actually change them (idea from Zoltan).
3540 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3542 /*for (i = 14; i < 32; i++) {
3543 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3545 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3546 /* use the saved copy of the frame reg in r8 */
3547 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3548 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3549 ppc_mtlr (code, ppc_r0);
3551 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3553 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3554 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3555 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3557 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3558 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3560 ppc_mtlr (code, ppc_r0);
3562 if (ppc_is_imm16 (cfg->stack_usage)) {
3563 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3565 ppc_load (code, ppc_r11, cfg->stack_usage);
3566 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3569 /*for (i = 31; i >= 14; --i) {
3570 if (cfg->used_float_regs & (1 << i)) {
3571 pos += sizeof (double);
3572 ppc_lfd (code, i, -pos, ppc_sp);
3575 for (i = 31; i >= 13; --i) {
3576 if (cfg->used_int_regs & (1 << i)) {
3577 pos += sizeof (gulong);
3578 ppc_lwz (code, i, -pos, ppc_sp);
3584 cfg->code_len = code - cfg->native_code;
3586 g_assert (cfg->code_len < cfg->code_size);
3590 /* remove once throw_exception_by_name is eliminated */
3592 exception_id_by_name (const char *name)
3594 if (strcmp (name, "IndexOutOfRangeException") == 0)
3595 return MONO_EXC_INDEX_OUT_OF_RANGE;
3596 if (strcmp (name, "OverflowException") == 0)
3597 return MONO_EXC_OVERFLOW;
3598 if (strcmp (name, "ArithmeticException") == 0)
3599 return MONO_EXC_ARITHMETIC;
3600 if (strcmp (name, "DivideByZeroException") == 0)
3601 return MONO_EXC_DIVIDE_BY_ZERO;
3602 if (strcmp (name, "InvalidCastException") == 0)
3603 return MONO_EXC_INVALID_CAST;
3604 if (strcmp (name, "NullReferenceException") == 0)
3605 return MONO_EXC_NULL_REF;
3606 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3607 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3608 g_error ("Unknown intrinsic exception %s\n", name);
3613 mono_arch_emit_exceptions (MonoCompile *cfg)
3615 MonoJumpInfo *patch_info;
3618 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3619 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3622 int max_epilog_size = 50;
3624 /* count the number of exception infos */
3627 * make sure we have enough space for exceptions
3628 * 24 is the simulated call to throw_exception_by_name
3630 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3631 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3632 i = exception_id_by_name (patch_info->data.target);
3633 if (!exc_throw_found [i]) {
3634 max_epilog_size += 24;
3635 exc_throw_found [i] = TRUE;
3637 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3638 max_epilog_size += 12;
3639 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3640 MonoOvfJump *ovfj = patch_info->data.target;
3641 i = exception_id_by_name (ovfj->data.exception);
3642 if (!exc_throw_found [i]) {
3643 max_epilog_size += 24;
3644 exc_throw_found [i] = TRUE;
3646 max_epilog_size += 8;
3650 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3651 cfg->code_size *= 2;
3652 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3653 mono_jit_stats.code_reallocs++;
3656 code = cfg->native_code + cfg->code_len;
3658 /* add code to raise exceptions */
3659 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3660 switch (patch_info->type) {
3661 case MONO_PATCH_INFO_BB_OVF: {
3662 MonoOvfJump *ovfj = patch_info->data.target;
3663 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3664 /* patch the initial jump */
3665 ppc_patch (ip, code);
3666 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3668 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3669 /* jump back to the true target */
3671 ip = ovfj->data.bb->native_offset + cfg->native_code;
3672 ppc_patch (code - 4, ip);
3675 case MONO_PATCH_INFO_EXC_OVF: {
3676 MonoOvfJump *ovfj = patch_info->data.target;
3677 MonoJumpInfo *newji;
3678 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3679 unsigned char *bcl = code;
3680 /* patch the initial jump: we arrived here with a call */
3681 ppc_patch (ip, code);
3682 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3684 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3685 /* patch the conditional jump to the right handler */
3686 /* make it processed next */
3687 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3688 newji->type = MONO_PATCH_INFO_EXC;
3689 newji->ip.i = bcl - cfg->native_code;
3690 newji->data.target = ovfj->data.exception;
3691 newji->next = patch_info->next;
3692 patch_info->next = newji;
3695 case MONO_PATCH_INFO_EXC: {
3696 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3697 i = exception_id_by_name (patch_info->data.target);
3698 if (exc_throw_pos [i]) {
3699 ppc_patch (ip, exc_throw_pos [i]);
3700 patch_info->type = MONO_PATCH_INFO_NONE;
3703 exc_throw_pos [i] = code;
3705 ppc_patch (ip, code);
3706 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3707 ppc_load (code, ppc_r3, patch_info->data.target);
3708 /* we got here from a conditional call, so the calling ip is set in lr already */
3709 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3710 patch_info->data.name = "mono_arch_throw_exception_by_name";
3711 patch_info->ip.i = code - cfg->native_code;
3712 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3713 ppc_lis (code, ppc_r0, 0);
3714 ppc_ori (code, ppc_r0, ppc_r0, 0);
3715 ppc_mtctr (code, ppc_r0);
3716 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3728 cfg->code_len = code - cfg->native_code;
3730 g_assert (cfg->code_len < cfg->code_size);
3735 try_offset_access (void *value, guint32 idx)
3737 register void* me __asm__ ("r2");
3738 void ***p = (void***)((char*)me + 284);
3739 int idx1 = idx / 32;
3740 int idx2 = idx % 32;
3743 if (value != p[idx1][idx2])
3749 setup_tls_access (void)
3752 guint32 *ins, *code;
3753 guint32 cmplwi_1023, li_0x48, blr_ins;
3754 if (tls_mode == TLS_MODE_FAILED)
3757 if (g_getenv ("MONO_NO_TLS")) {
3758 tls_mode = TLS_MODE_FAILED;
3762 if (tls_mode == TLS_MODE_DETECT) {
3763 ins = (guint32*)pthread_getspecific;
3764 /* uncond branch to the real method */
3765 if ((*ins >> 26) == 18) {
3767 val = (*ins & ~3) << 6;
3771 ins = (guint32*)val;
3773 ins = (guint32*) ((char*)ins + val);
3776 code = &cmplwi_1023;
3777 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3779 ppc_li (code, ppc_r4, 0x48);
3782 if (*ins == cmplwi_1023) {
3783 int found_lwz_284 = 0;
3784 for (ptk = 0; ptk < 20; ++ptk) {
3786 if (!*ins || *ins == blr_ins)
3788 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3793 if (!found_lwz_284) {
3794 tls_mode = TLS_MODE_FAILED;
3797 tls_mode = TLS_MODE_LTHREADS;
3798 } else if (*ins == li_0x48) {
3800 /* uncond branch to the real method */
3801 if ((*ins >> 26) == 18) {
3803 val = (*ins & ~3) << 6;
3807 ins = (guint32*)val;
3809 ins = (guint32*) ((char*)ins + val);
3812 ppc_li (code, ppc_r0, 0x7FF2);
3813 if (ins [1] == val) {
3814 /* Darwin on G4, implement */
3815 tls_mode = TLS_MODE_FAILED;
3819 ppc_mfspr (code, ppc_r3, 104);
3820 if (ins [1] != val) {
3821 tls_mode = TLS_MODE_FAILED;
3824 tls_mode = TLS_MODE_DARWIN_G5;
3827 tls_mode = TLS_MODE_FAILED;
3831 tls_mode = TLS_MODE_FAILED;
3835 if (monodomain_key == -1) {
3836 ptk = mono_domain_get_tls_key ();
3838 ptk = mono_pthread_key_for_tls (ptk);
3840 monodomain_key = ptk;
3844 if (lmf_pthread_key == -1) {
3845 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3847 /*g_print ("MonoLMF at: %d\n", ptk);*/
3848 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3849 init_tls_failed = 1;
3852 lmf_pthread_key = ptk;
3855 if (monothread_key == -1) {
3856 ptk = mono_thread_get_tls_key ();
3858 ptk = mono_pthread_key_for_tls (ptk);
3860 monothread_key = ptk;
3861 /*g_print ("thread inited: %d\n", ptk);*/
3864 /*g_print ("thread not inited yet %d\n", ptk);*/
3870 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3872 setup_tls_access ();
3876 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3881 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3883 int this_dreg = ppc_r3;
3888 /* add the this argument */
3889 if (this_reg != -1) {
3891 MONO_INST_NEW (cfg, this, OP_SETREG);
3892 this->type = this_type;
3893 this->sreg1 = this_reg;
3894 this->dreg = mono_regstate_next_int (cfg->rs);
3895 mono_bblock_add_inst (cfg->cbb, this);
3896 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3901 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3902 vtarg->type = STACK_MP;
3903 vtarg->sreg1 = vt_reg;
3904 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3905 mono_bblock_add_inst (cfg->cbb, vtarg);
3906 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3910 #ifdef MONO_ARCH_HAVE_IMT
3914 #define JUMP_IMM_SIZE 12
3915 #define ENABLE_WRONG_METHOD_CHECK 0
3918 * LOCKING: called with the domain lock held
3921 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3925 guint8 *code, *start;
3927 for (i = 0; i < count; ++i) {
3928 MonoIMTCheckItem *item = imt_entries [i];
3929 if (item->is_equals) {
3930 if (item->check_target_idx) {
3931 if (!item->compare_done)
3932 item->chunk_size += CMP_SIZE;
3933 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
3935 item->chunk_size += JUMP_IMM_SIZE;
3936 #if ENABLE_WRONG_METHOD_CHECK
3937 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
3941 item->chunk_size += CMP_SIZE + BR_SIZE;
3942 imt_entries [item->check_target_idx]->compare_done = TRUE;
3944 size += item->chunk_size;
3946 /* the initial load of the vtable address */
3948 code = mono_code_manager_reserve (domain->code_mp, size);
3950 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
3951 for (i = 0; i < count; ++i) {
3952 MonoIMTCheckItem *item = imt_entries [i];
3953 item->code_target = code;
3954 if (item->is_equals) {
3955 if (item->check_target_idx) {
3956 if (!item->compare_done) {
3957 ppc_load (code, ppc_r0, (guint32)item->method);
3958 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3960 item->jmp_code = code;
3961 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3962 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3963 ppc_mtctr (code, ppc_r0);
3964 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3966 /* enable the commented code to assert on wrong method */
3967 #if ENABLE_WRONG_METHOD_CHECK
3968 ppc_load (code, ppc_r0, (guint32)item->method);
3969 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3970 item->jmp_code = code;
3971 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3973 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3974 ppc_mtctr (code, ppc_r0);
3975 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3976 #if ENABLE_WRONG_METHOD_CHECK
3977 ppc_patch (item->jmp_code, code);
3979 item->jmp_code = NULL;
3983 ppc_load (code, ppc_r0, (guint32)item->method);
3984 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3985 item->jmp_code = code;
3986 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
3989 /* patch the branches to get to the target items */
3990 for (i = 0; i < count; ++i) {
3991 MonoIMTCheckItem *item = imt_entries [i];
3992 if (item->jmp_code) {
3993 if (item->check_target_idx) {
3994 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
3999 mono_stats.imt_thunks_size += code - start;
4000 g_assert (code - start <= size);
4001 mono_arch_flush_icache (start, size);
4006 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4008 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4012 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4014 return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
4019 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4021 MonoInst *ins = NULL;
4023 if (cmethod->klass == mono_defaults.thread_class &&
4024 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4025 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4027 /*if (cmethod->klass == mono_defaults.math_class) {
4028 if (strcmp (cmethod->name, "Sqrt") == 0) {
4029 MONO_INST_NEW (cfg, ins, OP_SQRT);
4030 ins->inst_i0 = args [0];
4037 mono_arch_print_tree (MonoInst *tree, int arity)
4042 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4046 setup_tls_access ();
4047 if (monodomain_key == -1)
4050 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4051 ins->inst_offset = monodomain_key;
4056 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4060 setup_tls_access ();
4061 if (monothread_key == -1)
4064 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4065 ins->inst_offset = monothread_key;