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 = mono_type_stack_size (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_addr (guint8 *code_ptr, gpointer *regs)
231 guint32* code = (guint32*)code_ptr;
233 /* This is the 'blrl' instruction */
236 /* Sanity check: instruction must be 'blrl' */
237 if (*code != 0x4e800021)
240 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
241 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
245 /* OK, we're now at the 'blrl' instruction. Now walk backwards
246 till we get to a 'mtlr rA' */
248 if((*code & 0x7c0803a6) == 0x7c0803a6) {
250 /* Here we are: we reached the 'mtlr rA'.
251 Extract the register from the instruction */
252 reg = (*code & 0x03e00000) >> 21;
254 /* ok, this is a lwz reg, offset (vtreg)
255 * it is emitted with:
256 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
258 soff = (*code & 0xffff);
260 reg = (*code >> 16) & 0x1f;
261 g_assert (reg != ppc_r1);
262 /*g_print ("patching reg is %d\n", reg);*/
264 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
265 /* saved in the MonoLMF structure */
266 o = (gpointer)lmf->iregs [reg - 13];
277 #define MAX_ARCH_DELEGATE_PARAMS 7
280 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
282 guint8 *code, *start;
284 /* FIXME: Support more cases */
285 if (MONO_TYPE_ISSTRUCT (sig->ret))
289 static guint8* cached = NULL;
290 mono_mini_arch_lock ();
292 mono_mini_arch_unlock ();
296 start = code = mono_global_codeman_reserve (16);
298 /* Replace the this argument with the target */
299 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
300 ppc_mtctr (code, ppc_r0);
301 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
302 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
304 g_assert ((code - start) <= 16);
306 mono_arch_flush_icache (code, 16);
308 mono_mini_arch_unlock ();
311 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
314 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
316 for (i = 0; i < sig->param_count; ++i)
317 if (!mono_is_regsize_var (sig->params [i]))
320 mono_mini_arch_lock ();
321 code = cache [sig->param_count];
323 mono_mini_arch_unlock ();
327 size = 12 + sig->param_count * 4;
328 start = code = mono_global_codeman_reserve (size);
330 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
331 ppc_mtctr (code, ppc_r0);
332 /* slide down the arguments */
333 for (i = 0; i < sig->param_count; ++i) {
334 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
336 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
338 g_assert ((code - start) <= size);
340 mono_arch_flush_icache (code, size);
341 cache [sig->param_count] = start;
342 mono_mini_arch_unlock ();
349 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
351 /* FIXME: handle returning a struct */
352 if (MONO_TYPE_ISSTRUCT (sig->ret))
353 return (gpointer)regs [ppc_r4];
354 return (gpointer)regs [ppc_r3];
358 * Initialize the cpu to execute managed code.
361 mono_arch_cpu_init (void)
366 * Initialize architecture specific code.
369 mono_arch_init (void)
371 InitializeCriticalSection (&mini_arch_mutex);
375 * Cleanup architecture specific code.
378 mono_arch_cleanup (void)
380 DeleteCriticalSection (&mini_arch_mutex);
384 * This function returns the optimizations supported on this cpu.
387 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
391 /* no ppc-specific optimizations yet */
397 is_regsize_var (MonoType *t) {
400 t = mono_type_get_underlying_type (t);
407 case MONO_TYPE_FNPTR:
409 case MONO_TYPE_OBJECT:
410 case MONO_TYPE_STRING:
411 case MONO_TYPE_CLASS:
412 case MONO_TYPE_SZARRAY:
413 case MONO_TYPE_ARRAY:
415 case MONO_TYPE_GENERICINST:
416 if (!mono_type_generic_inst_is_valuetype (t))
419 case MONO_TYPE_VALUETYPE:
426 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
431 for (i = 0; i < cfg->num_varinfo; i++) {
432 MonoInst *ins = cfg->varinfo [i];
433 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
436 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
439 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
442 /* we can only allocate 32 bit values */
443 if (is_regsize_var (ins->inst_vtype)) {
444 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
445 g_assert (i == vmv->idx);
446 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
454 mono_arch_get_global_int_regs (MonoCompile *cfg)
458 if (cfg->frame_reg != ppc_sp)
460 /* ppc_r13 is used by the system on PPC EABI */
461 for (i = 14; i < top; ++i)
462 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
468 * mono_arch_regalloc_cost:
470 * Return the cost, in number of memory references, of the action of
471 * allocating the variable VMV into a register during global register
475 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
487 mono_arch_flush_icache (guint8 *code, gint size)
489 guint8 *p, *endp, *start;
490 static int cachelinesize = 0;
491 static int cachelineinc = 16;
493 if (!cachelinesize) {
497 mib [1] = HW_CACHELINE;
498 len = sizeof (cachelinesize);
499 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
503 cachelineinc = cachelinesize;
504 /*g_print ("setting cl size to %d\n", cachelinesize);*/
506 #elif defined(__linux__)
507 /* sadly this will work only with 2.6 kernels... */
508 FILE* f = fopen ("/proc/self/auxv", "rb");
511 while (fread (&vec, sizeof (vec), 1, f) == 1) {
512 if (vec.type == 19) {
513 cachelinesize = vec.value;
522 #warning Need a way to get cache line size
528 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
529 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
531 for (p = start; p < endp; p += cachelineinc) {
532 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
535 for (p = start; p < endp; p += cachelineinc) {
536 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
541 for (p = start; p < endp; p += cachelineinc) {
542 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
548 #define NOT_IMPLEMENTED(x) \
549 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
552 #define ALWAYS_ON_STACK(s) s
553 #define FP_ALSO_IN_REG(s) s
555 #define ALWAYS_ON_STACK(s)
556 #define FP_ALSO_IN_REG(s)
557 #define ALIGN_DOUBLES
570 guint32 vtsize; /* in param area */
572 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
573 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
588 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
591 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
592 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
593 ainfo->reg = ppc_sp; /* in the caller */
594 ainfo->regtype = RegTypeBase;
597 ALWAYS_ON_STACK (*stack_size += 4);
601 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
603 //*stack_size += (*stack_size % 8);
605 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
606 ainfo->reg = ppc_sp; /* in the caller */
607 ainfo->regtype = RegTypeBase;
614 ALWAYS_ON_STACK (*stack_size += 8);
623 /* size == 4 is checked already */
625 has_only_a_r4_field (MonoClass *klass)
630 while ((f = mono_class_get_fields (klass, &iter))) {
631 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
632 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
642 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
645 int n = sig->hasthis + sig->param_count;
647 guint32 stack_size = 0;
648 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
650 fr = PPC_FIRST_FPARG_REG;
651 gr = PPC_FIRST_ARG_REG;
653 /* FIXME: handle returning a struct */
654 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
655 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
656 cinfo->struct_ret = PPC_FIRST_ARG_REG;
661 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
664 DEBUG(printf("params: %d\n", sig->param_count));
665 for (i = 0; i < sig->param_count; ++i) {
666 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
667 /* Prevent implicit arguments and sig_cookie from
668 being passed in registers */
669 gr = PPC_LAST_ARG_REG + 1;
670 /* Emit the signature cookie just before the implicit arguments */
671 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
673 DEBUG(printf("param %d: ", i));
674 if (sig->params [i]->byref) {
675 DEBUG(printf("byref\n"));
676 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
680 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
681 switch (simpletype) {
682 case MONO_TYPE_BOOLEAN:
685 cinfo->args [n].size = 1;
686 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
692 cinfo->args [n].size = 2;
693 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
698 cinfo->args [n].size = 4;
699 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
705 case MONO_TYPE_FNPTR:
706 case MONO_TYPE_CLASS:
707 case MONO_TYPE_OBJECT:
708 case MONO_TYPE_STRING:
709 case MONO_TYPE_SZARRAY:
710 case MONO_TYPE_ARRAY:
711 cinfo->args [n].size = sizeof (gpointer);
712 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
715 case MONO_TYPE_GENERICINST:
716 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
717 cinfo->args [n].size = sizeof (gpointer);
718 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
723 case MONO_TYPE_VALUETYPE: {
726 klass = mono_class_from_mono_type (sig->params [i]);
728 size = mono_class_native_size (klass, NULL);
730 size = mono_class_value_size (klass, NULL);
732 if (size == 4 && has_only_a_r4_field (klass)) {
733 cinfo->args [n].size = 4;
735 /* It was 7, now it is 8 in LinuxPPC */
736 if (fr <= PPC_LAST_FPARG_REG) {
737 cinfo->args [n].regtype = RegTypeFP;
738 cinfo->args [n].reg = fr;
740 FP_ALSO_IN_REG (gr ++);
741 ALWAYS_ON_STACK (stack_size += 4);
743 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
744 cinfo->args [n].regtype = RegTypeBase;
745 cinfo->args [n].reg = ppc_sp; /* in the caller*/
752 DEBUG(printf ("load %d bytes struct\n",
753 mono_class_native_size (sig->params [i]->data.klass, NULL)));
754 #if PPC_PASS_STRUCTS_BY_VALUE
756 int align_size = size;
758 align_size += (sizeof (gpointer) - 1);
759 align_size &= ~(sizeof (gpointer) - 1);
760 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
761 cinfo->args [n].regtype = RegTypeStructByVal;
762 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
763 cinfo->args [n].size = 0;
764 cinfo->args [n].vtsize = nwords;
766 int rest = PPC_LAST_ARG_REG - gr + 1;
767 int n_in_regs = rest >= nwords? nwords: rest;
768 cinfo->args [n].size = n_in_regs;
769 cinfo->args [n].vtsize = nwords - n_in_regs;
770 cinfo->args [n].reg = gr;
773 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
774 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
775 stack_size += nwords * sizeof (gpointer);
778 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
779 cinfo->args [n].regtype = RegTypeStructByAddr;
780 cinfo->args [n].vtsize = size;
785 case MONO_TYPE_TYPEDBYREF: {
786 int size = sizeof (MonoTypedRef);
787 /* keep in sync or merge with the valuetype case */
788 #if PPC_PASS_STRUCTS_BY_VALUE
790 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
791 cinfo->args [n].regtype = RegTypeStructByVal;
792 if (gr <= PPC_LAST_ARG_REG) {
793 int rest = PPC_LAST_ARG_REG - gr + 1;
794 int n_in_regs = rest >= nwords? nwords: rest;
795 cinfo->args [n].size = n_in_regs;
796 cinfo->args [n].vtsize = nwords - n_in_regs;
797 cinfo->args [n].reg = gr;
800 cinfo->args [n].size = 0;
801 cinfo->args [n].vtsize = nwords;
803 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
804 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
805 stack_size += nwords * sizeof (gpointer);
808 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
809 cinfo->args [n].regtype = RegTypeStructByAddr;
810 cinfo->args [n].vtsize = size;
817 cinfo->args [n].size = 8;
818 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
822 cinfo->args [n].size = 4;
824 /* It was 7, now it is 8 in LinuxPPC */
825 if (fr <= PPC_LAST_FPARG_REG) {
826 cinfo->args [n].regtype = RegTypeFP;
827 cinfo->args [n].reg = fr;
829 FP_ALSO_IN_REG (gr ++);
830 ALWAYS_ON_STACK (stack_size += 4);
832 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
833 cinfo->args [n].regtype = RegTypeBase;
834 cinfo->args [n].reg = ppc_sp; /* in the caller*/
840 cinfo->args [n].size = 8;
841 /* It was 7, now it is 8 in LinuxPPC */
842 if (fr <= PPC_LAST_FPARG_REG) {
843 cinfo->args [n].regtype = RegTypeFP;
844 cinfo->args [n].reg = fr;
846 FP_ALSO_IN_REG (gr += 2);
847 ALWAYS_ON_STACK (stack_size += 8);
849 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
850 cinfo->args [n].regtype = RegTypeBase;
851 cinfo->args [n].reg = ppc_sp; /* in the caller*/
857 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
862 simpletype = mono_type_get_underlying_type (sig->ret)->type;
863 switch (simpletype) {
864 case MONO_TYPE_BOOLEAN:
875 case MONO_TYPE_FNPTR:
876 case MONO_TYPE_CLASS:
877 case MONO_TYPE_OBJECT:
878 case MONO_TYPE_SZARRAY:
879 case MONO_TYPE_ARRAY:
880 case MONO_TYPE_STRING:
881 cinfo->ret.reg = ppc_r3;
885 cinfo->ret.reg = ppc_r3;
889 cinfo->ret.reg = ppc_f1;
890 cinfo->ret.regtype = RegTypeFP;
892 case MONO_TYPE_GENERICINST:
893 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
894 cinfo->ret.reg = ppc_r3;
898 case MONO_TYPE_VALUETYPE:
900 case MONO_TYPE_TYPEDBYREF:
904 g_error ("Can't handle as return value 0x%x", sig->ret->type);
908 /* align stack size to 16 */
909 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
910 stack_size = (stack_size + 15) & ~15;
912 cinfo->stack_usage = stack_size;
918 * Set var information according to the calling convention. ppc version.
919 * The locals var stuff should most likely be split in another method.
922 mono_arch_allocate_vars (MonoCompile *m)
924 MonoMethodSignature *sig;
925 MonoMethodHeader *header;
927 int i, offset, size, align, curinst;
928 int frame_reg = ppc_sp;
930 m->flags |= MONO_CFG_HAS_SPILLUP;
932 /* allow room for the vararg method args: void* and long/double */
933 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
934 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
935 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
936 * call convs needs to be handled this way.
938 if (m->flags & MONO_CFG_HAS_VARARGS)
939 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
940 /* gtk-sharp and other broken code will dllimport vararg functions even with
941 * non-varargs signatures. Since there is little hope people will get this right
942 * we assume they won't.
944 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
945 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
947 header = mono_method_get_header (m->method);
950 * We use the frame register also for any method that has
951 * exception clauses. This way, when the handlers are called,
952 * the code will reference local variables using the frame reg instead of
953 * the stack pointer: if we had to restore the stack pointer, we'd
954 * corrupt the method frames that are already on the stack (since
955 * filters get called before stack unwinding happens) when the filter
956 * code would call any method (this also applies to finally etc.).
958 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
960 m->frame_reg = frame_reg;
961 if (frame_reg != ppc_sp) {
962 m->used_int_regs |= 1 << frame_reg;
965 sig = mono_method_signature (m->method);
969 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
970 m->ret->opcode = OP_REGVAR;
971 m->ret->inst_c0 = ppc_r3;
973 /* FIXME: handle long and FP values */
974 switch (mono_type_get_underlying_type (sig->ret)->type) {
978 m->ret->opcode = OP_REGVAR;
979 m->ret->inst_c0 = ppc_r3;
983 /* local vars are at a positive offset from the stack pointer */
985 * also note that if the function uses alloca, we use ppc_r31
986 * to point at the local variables.
988 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
989 /* align the offset to 16 bytes: not sure this is needed here */
991 //offset &= ~(16 - 1);
993 /* add parameter area size for called functions */
994 offset += m->param_area;
998 /* allow room to save the return value */
999 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1002 /* the MonoLMF structure is stored just below the stack pointer */
1005 /* this stuff should not be needed on ppc and the new jit,
1006 * because a call on ppc to the handlers doesn't change the
1007 * stack pointer and the jist doesn't manipulate the stack pointer
1008 * for operations involving valuetypes.
1010 /* reserve space to store the esp */
1011 offset += sizeof (gpointer);
1013 /* this is a global constant */
1014 mono_exc_esp_offset = offset;
1016 if (sig->call_convention == MONO_CALL_VARARG) {
1017 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1020 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1022 offset += sizeof(gpointer) - 1;
1023 offset &= ~(sizeof(gpointer) - 1);
1024 inst->inst_offset = offset;
1025 inst->opcode = OP_REGOFFSET;
1026 inst->inst_basereg = frame_reg;
1027 offset += sizeof(gpointer);
1028 if (sig->call_convention == MONO_CALL_VARARG)
1029 m->sig_cookie += sizeof (gpointer);
1032 curinst = m->locals_start;
1033 for (i = curinst; i < m->num_varinfo; ++i) {
1034 inst = m->varinfo [i];
1035 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1038 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1039 * pinvoke wrappers when they call functions returning structure */
1040 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1041 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1043 size = mono_type_size (inst->inst_vtype, &align);
1045 offset += align - 1;
1046 offset &= ~(align - 1);
1047 inst->inst_offset = offset;
1048 inst->opcode = OP_REGOFFSET;
1049 inst->inst_basereg = frame_reg;
1051 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1056 inst = m->args [curinst];
1057 if (inst->opcode != OP_REGVAR) {
1058 inst->opcode = OP_REGOFFSET;
1059 inst->inst_basereg = frame_reg;
1060 offset += sizeof (gpointer) - 1;
1061 offset &= ~(sizeof (gpointer) - 1);
1062 inst->inst_offset = offset;
1063 offset += sizeof (gpointer);
1064 if (sig->call_convention == MONO_CALL_VARARG)
1065 m->sig_cookie += sizeof (gpointer);
1070 for (i = 0; i < sig->param_count; ++i) {
1071 inst = m->args [curinst];
1072 if (inst->opcode != OP_REGVAR) {
1073 inst->opcode = OP_REGOFFSET;
1074 inst->inst_basereg = frame_reg;
1075 size = mono_type_size (sig->params [i], &align);
1076 offset += align - 1;
1077 offset &= ~(align - 1);
1078 inst->inst_offset = offset;
1080 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1081 m->sig_cookie += size;
1086 /* align the offset to 16 bytes */
1088 offset &= ~(16 - 1);
1091 m->stack_offset = offset;
1095 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1096 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1100 * take the arguments and generate the arch-specific
1101 * instructions to properly call the function in call.
1102 * This includes pushing, moving arguments to the right register
1104 * Issue: who does the spilling if needed, and when?
1107 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1109 MonoMethodSignature *sig;
1114 sig = call->signature;
1115 n = sig->param_count + sig->hasthis;
1117 cinfo = calculate_sizes (sig, sig->pinvoke);
1118 if (cinfo->struct_ret)
1119 call->used_iregs |= 1 << cinfo->struct_ret;
1121 for (i = 0; i < n; ++i) {
1122 ainfo = cinfo->args + i;
1123 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1125 cfg->disable_aot = TRUE;
1127 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1128 sig_arg->inst_p0 = call->signature;
1130 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1131 arg->inst_imm = cinfo->sig_cookie.offset;
1132 arg->inst_left = sig_arg;
1134 /* prepend, so they get reversed */
1135 arg->next = call->out_args;
1136 call->out_args = arg;
1138 if (is_virtual && i == 0) {
1139 /* the argument will be attached to the call instrucion */
1140 in = call->args [i];
1141 call->used_iregs |= 1 << ainfo->reg;
1143 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1144 in = call->args [i];
1145 arg->cil_code = in->cil_code;
1146 arg->inst_left = in;
1147 arg->inst_call = call;
1148 arg->type = in->type;
1149 /* prepend, we'll need to reverse them later */
1150 arg->next = call->out_args;
1151 call->out_args = arg;
1152 if (ainfo->regtype == RegTypeGeneral) {
1153 arg->backend.reg3 = ainfo->reg;
1154 call->used_iregs |= 1 << ainfo->reg;
1155 if (arg->type == STACK_I8)
1156 call->used_iregs |= 1 << (ainfo->reg + 1);
1157 } else if (ainfo->regtype == RegTypeStructByAddr) {
1158 if (ainfo->offset) {
1159 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1160 arg->opcode = OP_OUTARG_MEMBASE;
1161 ai->reg = ainfo->reg;
1162 ai->size = sizeof (gpointer);
1163 ai->offset = ainfo->offset;
1164 arg->backend.data = ai;
1166 arg->backend.reg3 = ainfo->reg;
1167 call->used_iregs |= 1 << ainfo->reg;
1169 } else if (ainfo->regtype == RegTypeStructByVal) {
1171 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1172 /* mark the used regs */
1173 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1174 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1176 arg->opcode = OP_OUTARG_VT;
1177 ai->reg = ainfo->reg;
1178 ai->size = ainfo->size;
1179 ai->vtsize = ainfo->vtsize;
1180 ai->offset = ainfo->offset;
1181 arg->backend.data = ai;
1182 } else if (ainfo->regtype == RegTypeBase) {
1183 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1184 arg->opcode = OP_OUTARG_MEMBASE;
1185 ai->reg = ainfo->reg;
1186 ai->size = ainfo->size;
1187 ai->offset = ainfo->offset;
1188 arg->backend.data = ai;
1189 } else if (ainfo->regtype == RegTypeFP) {
1190 arg->opcode = OP_OUTARG_R8;
1191 arg->backend.reg3 = ainfo->reg;
1192 call->used_fregs |= 1 << ainfo->reg;
1193 if (ainfo->size == 4) {
1194 arg->opcode = OP_OUTARG_R8;
1195 /* we reduce the precision */
1197 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1198 conv->inst_left = arg->inst_left;
1199 arg->inst_left = conv;*/
1202 g_assert_not_reached ();
1207 * Reverse the call->out_args list.
1210 MonoInst *prev = NULL, *list = call->out_args, *next;
1217 call->out_args = prev;
1219 call->stack_usage = cinfo->stack_usage;
1220 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1221 cfg->flags |= MONO_CFG_HAS_CALLS;
1223 * should set more info in call, such as the stack space
1224 * used by the args that needs to be added back to esp
1232 * Allow tracing to work with this interface (with an optional argument)
1236 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1240 ppc_load (code, ppc_r3, cfg->method);
1241 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1242 ppc_load (code, ppc_r0, func);
1243 ppc_mtlr (code, ppc_r0);
1257 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1260 int save_mode = SAVE_NONE;
1262 MonoMethod *method = cfg->method;
1263 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1264 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1268 offset = code - cfg->native_code;
1269 /* we need about 16 instructions */
1270 if (offset > (cfg->code_size - 16 * 4)) {
1271 cfg->code_size *= 2;
1272 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1273 code = cfg->native_code + offset;
1277 case MONO_TYPE_VOID:
1278 /* special case string .ctor icall */
1279 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1280 save_mode = SAVE_ONE;
1282 save_mode = SAVE_NONE;
1286 save_mode = SAVE_TWO;
1290 save_mode = SAVE_FP;
1292 case MONO_TYPE_VALUETYPE:
1293 save_mode = SAVE_STRUCT;
1296 save_mode = SAVE_ONE;
1300 switch (save_mode) {
1302 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1303 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1304 if (enable_arguments) {
1305 ppc_mr (code, ppc_r5, ppc_r4);
1306 ppc_mr (code, ppc_r4, ppc_r3);
1310 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1311 if (enable_arguments) {
1312 ppc_mr (code, ppc_r4, ppc_r3);
1316 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1317 if (enable_arguments) {
1318 /* FIXME: what reg? */
1319 ppc_fmr (code, ppc_f3, ppc_f1);
1320 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1321 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1325 if (enable_arguments) {
1326 /* FIXME: get the actual address */
1327 ppc_mr (code, ppc_r4, ppc_r3);
1335 ppc_load (code, ppc_r3, cfg->method);
1336 ppc_load (code, ppc_r0, func);
1337 ppc_mtlr (code, ppc_r0);
1340 switch (save_mode) {
1342 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1343 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1346 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1349 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1359 * Conditional branches have a small offset, so if it is likely overflowed,
1360 * we do a branch to the end of the method (uncond branches have much larger
1361 * offsets) where we perform the conditional and jump back unconditionally.
1362 * It's slightly slower, since we add two uncond branches, but it's very simple
1363 * with the current patch implementation and such large methods are likely not
1364 * going to be perf critical anyway.
1369 const char *exception;
1376 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1377 if (ins->flags & MONO_INST_BRLABEL) { \
1378 if (0 && ins->inst_i0->inst_c0) { \
1379 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1381 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1382 ppc_bc (code, (b0), (b1), 0); \
1385 if (0 && ins->inst_true_bb->native_offset) { \
1386 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1388 int br_disp = ins->inst_true_bb->max_offset - offset; \
1389 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1390 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1391 ovfj->data.bb = ins->inst_true_bb; \
1392 ovfj->ip_offset = 0; \
1393 ovfj->b0_cond = (b0); \
1394 ovfj->b1_cond = (b1); \
1395 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1398 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1399 ppc_bc (code, (b0), (b1), 0); \
1404 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1406 /* emit an exception if condition is fail
1408 * We assign the extra code used to throw the implicit exceptions
1409 * to cfg->bb_exit as far as the big branch handling is concerned
1411 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1413 int br_disp = cfg->bb_exit->max_offset - offset; \
1414 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1415 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1416 ovfj->data.exception = (exc_name); \
1417 ovfj->ip_offset = code - cfg->native_code; \
1418 ovfj->b0_cond = (b0); \
1419 ovfj->b1_cond = (b1); \
1420 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1422 cfg->bb_exit->max_offset += 24; \
1424 mono_add_patch_info (cfg, code - cfg->native_code, \
1425 MONO_PATCH_INFO_EXC, exc_name); \
1426 ppc_bcl (code, (b0), (b1), 0); \
1430 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1433 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1435 MonoInst *ins, *last_ins = NULL;
1440 switch (ins->opcode) {
1442 /* remove unnecessary multiplication with 1 */
1443 if (ins->inst_imm == 1) {
1444 if (ins->dreg != ins->sreg1) {
1445 ins->opcode = OP_MOVE;
1447 last_ins->next = ins->next;
1452 int power2 = mono_is_power_of_two (ins->inst_imm);
1454 ins->opcode = OP_SHL_IMM;
1455 ins->inst_imm = power2;
1459 case OP_LOAD_MEMBASE:
1460 case OP_LOADI4_MEMBASE:
1462 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1463 * OP_LOAD_MEMBASE offset(basereg), reg
1465 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1466 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1467 ins->inst_basereg == last_ins->inst_destbasereg &&
1468 ins->inst_offset == last_ins->inst_offset) {
1469 if (ins->dreg == last_ins->sreg1) {
1470 last_ins->next = ins->next;
1474 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1475 ins->opcode = OP_MOVE;
1476 ins->sreg1 = last_ins->sreg1;
1480 * Note: reg1 must be different from the basereg in the second load
1481 * OP_LOAD_MEMBASE offset(basereg), reg1
1482 * OP_LOAD_MEMBASE offset(basereg), reg2
1484 * OP_LOAD_MEMBASE offset(basereg), reg1
1485 * OP_MOVE reg1, reg2
1487 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1488 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1489 ins->inst_basereg != last_ins->dreg &&
1490 ins->inst_basereg == last_ins->inst_basereg &&
1491 ins->inst_offset == last_ins->inst_offset) {
1493 if (ins->dreg == last_ins->dreg) {
1494 last_ins->next = ins->next;
1498 ins->opcode = OP_MOVE;
1499 ins->sreg1 = last_ins->dreg;
1502 //g_assert_not_reached ();
1506 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1507 * OP_LOAD_MEMBASE offset(basereg), reg
1509 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1510 * OP_ICONST reg, imm
1512 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1513 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1514 ins->inst_basereg == last_ins->inst_destbasereg &&
1515 ins->inst_offset == last_ins->inst_offset) {
1516 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1517 ins->opcode = OP_ICONST;
1518 ins->inst_c0 = last_ins->inst_imm;
1519 g_assert_not_reached (); // check this rule
1523 case OP_LOADU1_MEMBASE:
1524 case OP_LOADI1_MEMBASE:
1525 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1526 ins->inst_basereg == last_ins->inst_destbasereg &&
1527 ins->inst_offset == last_ins->inst_offset) {
1528 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1529 ins->sreg1 = last_ins->sreg1;
1532 case OP_LOADU2_MEMBASE:
1533 case OP_LOADI2_MEMBASE:
1534 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1535 ins->inst_basereg == last_ins->inst_destbasereg &&
1536 ins->inst_offset == last_ins->inst_offset) {
1537 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1538 ins->sreg1 = last_ins->sreg1;
1545 ins->opcode = OP_MOVE;
1549 if (ins->dreg == ins->sreg1) {
1551 last_ins->next = ins->next;
1556 * OP_MOVE sreg, dreg
1557 * OP_MOVE dreg, sreg
1559 if (last_ins && last_ins->opcode == OP_MOVE &&
1560 ins->sreg1 == last_ins->dreg &&
1561 ins->dreg == last_ins->sreg1) {
1562 last_ins->next = ins->next;
1571 bb->last_ins = last_ins;
1575 * the branch_b0_table should maintain the order of these
1589 branch_b0_table [] = {
1604 branch_b1_table [] = {
1619 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1623 bb->code = to_insert;
1624 to_insert->next = ins;
1626 to_insert->next = ins->next;
1627 ins->next = to_insert;
1631 #define NEW_INS(cfg,dest,op) do { \
1632 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1633 (dest)->opcode = (op); \
1634 insert_after_ins (bb, last_ins, (dest)); \
1638 map_to_reg_reg_op (int op)
1647 case OP_COMPARE_IMM:
1663 case OP_LOAD_MEMBASE:
1664 return OP_LOAD_MEMINDEX;
1665 case OP_LOADI4_MEMBASE:
1666 return OP_LOADI4_MEMINDEX;
1667 case OP_LOADU4_MEMBASE:
1668 return OP_LOADU4_MEMINDEX;
1669 case OP_LOADU1_MEMBASE:
1670 return OP_LOADU1_MEMINDEX;
1671 case OP_LOADI2_MEMBASE:
1672 return OP_LOADI2_MEMINDEX;
1673 case OP_LOADU2_MEMBASE:
1674 return OP_LOADU2_MEMINDEX;
1675 case OP_LOADI1_MEMBASE:
1676 return OP_LOADI1_MEMINDEX;
1677 case OP_LOADR4_MEMBASE:
1678 return OP_LOADR4_MEMINDEX;
1679 case OP_LOADR8_MEMBASE:
1680 return OP_LOADR8_MEMINDEX;
1681 case OP_STOREI1_MEMBASE_REG:
1682 return OP_STOREI1_MEMINDEX;
1683 case OP_STOREI2_MEMBASE_REG:
1684 return OP_STOREI2_MEMINDEX;
1685 case OP_STOREI4_MEMBASE_REG:
1686 return OP_STOREI4_MEMINDEX;
1687 case OP_STORE_MEMBASE_REG:
1688 return OP_STORE_MEMINDEX;
1689 case OP_STORER4_MEMBASE_REG:
1690 return OP_STORER4_MEMINDEX;
1691 case OP_STORER8_MEMBASE_REG:
1692 return OP_STORER8_MEMINDEX;
1693 case OP_STORE_MEMBASE_IMM:
1694 return OP_STORE_MEMBASE_REG;
1695 case OP_STOREI1_MEMBASE_IMM:
1696 return OP_STOREI1_MEMBASE_REG;
1697 case OP_STOREI2_MEMBASE_IMM:
1698 return OP_STOREI2_MEMBASE_REG;
1699 case OP_STOREI4_MEMBASE_IMM:
1700 return OP_STOREI4_MEMBASE_REG;
1702 g_assert_not_reached ();
1705 #define compare_opcode_is_unsigned(opcode) \
1706 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1707 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1708 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1710 * Remove from the instruction list the instructions that can't be
1711 * represented with very simple instructions with no register
1715 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1717 MonoInst *ins, *next, *temp, *last_ins = NULL;
1720 /* setup the virtual reg allocator */
1721 if (bb->max_vreg > cfg->rs->next_vreg)
1722 cfg->rs->next_vreg = bb->max_vreg;
1727 switch (ins->opcode) {
1730 if (!ppc_is_imm16 (ins->inst_imm)) {
1731 NEW_INS (cfg, temp, OP_ICONST);
1732 temp->inst_c0 = ins->inst_imm;
1733 temp->dreg = mono_regstate_next_int (cfg->rs);
1734 ins->sreg2 = temp->dreg;
1735 ins->opcode = map_to_reg_reg_op (ins->opcode);
1739 if (!ppc_is_imm16 (-ins->inst_imm)) {
1740 NEW_INS (cfg, temp, OP_ICONST);
1741 temp->inst_c0 = ins->inst_imm;
1742 temp->dreg = mono_regstate_next_int (cfg->rs);
1743 ins->sreg2 = temp->dreg;
1744 ins->opcode = map_to_reg_reg_op (ins->opcode);
1750 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1751 NEW_INS (cfg, 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);
1761 NEW_INS (cfg, temp, OP_ICONST);
1762 temp->inst_c0 = ins->inst_imm;
1763 temp->dreg = mono_regstate_next_int (cfg->rs);
1764 ins->sreg2 = temp->dreg;
1765 ins->opcode = map_to_reg_reg_op (ins->opcode);
1767 case OP_COMPARE_IMM:
1768 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1769 if (!ppc_is_uimm16 (ins->inst_imm)) {
1770 NEW_INS (cfg, temp, OP_ICONST);
1771 temp->inst_c0 = ins->inst_imm;
1772 temp->dreg = mono_regstate_next_int (cfg->rs);
1773 ins->sreg2 = temp->dreg;
1774 ins->opcode = map_to_reg_reg_op (ins->opcode);
1777 if (!ppc_is_imm16 (ins->inst_imm)) {
1778 NEW_INS (cfg, temp, OP_ICONST);
1779 temp->inst_c0 = ins->inst_imm;
1780 temp->dreg = mono_regstate_next_int (cfg->rs);
1781 ins->sreg2 = temp->dreg;
1782 ins->opcode = map_to_reg_reg_op (ins->opcode);
1787 if (ins->inst_imm == 1) {
1788 ins->opcode = OP_MOVE;
1791 if (ins->inst_imm == 0) {
1792 ins->opcode = OP_ICONST;
1796 imm = mono_is_power_of_two (ins->inst_imm);
1798 ins->opcode = OP_SHL_IMM;
1799 ins->inst_imm = imm;
1802 if (!ppc_is_imm16 (ins->inst_imm)) {
1803 NEW_INS (cfg, temp, OP_ICONST);
1804 temp->inst_c0 = ins->inst_imm;
1805 temp->dreg = mono_regstate_next_int (cfg->rs);
1806 ins->sreg2 = temp->dreg;
1807 ins->opcode = map_to_reg_reg_op (ins->opcode);
1810 case OP_LOAD_MEMBASE:
1811 case OP_LOADI4_MEMBASE:
1812 case OP_LOADU4_MEMBASE:
1813 case OP_LOADI2_MEMBASE:
1814 case OP_LOADU2_MEMBASE:
1815 case OP_LOADI1_MEMBASE:
1816 case OP_LOADU1_MEMBASE:
1817 case OP_LOADR4_MEMBASE:
1818 case OP_LOADR8_MEMBASE:
1819 case OP_STORE_MEMBASE_REG:
1820 case OP_STOREI4_MEMBASE_REG:
1821 case OP_STOREI2_MEMBASE_REG:
1822 case OP_STOREI1_MEMBASE_REG:
1823 case OP_STORER4_MEMBASE_REG:
1824 case OP_STORER8_MEMBASE_REG:
1825 /* we can do two things: load the immed in a register
1826 * and use an indexed load, or see if the immed can be
1827 * represented as an ad_imm + a load with a smaller offset
1828 * that fits. We just do the first for now, optimize later.
1830 if (ppc_is_imm16 (ins->inst_offset))
1832 NEW_INS (cfg, temp, OP_ICONST);
1833 temp->inst_c0 = ins->inst_offset;
1834 temp->dreg = mono_regstate_next_int (cfg->rs);
1835 ins->sreg2 = temp->dreg;
1836 ins->opcode = map_to_reg_reg_op (ins->opcode);
1838 case OP_STORE_MEMBASE_IMM:
1839 case OP_STOREI1_MEMBASE_IMM:
1840 case OP_STOREI2_MEMBASE_IMM:
1841 case OP_STOREI4_MEMBASE_IMM:
1842 NEW_INS (cfg, temp, OP_ICONST);
1843 temp->inst_c0 = ins->inst_imm;
1844 temp->dreg = mono_regstate_next_int (cfg->rs);
1845 ins->sreg1 = temp->dreg;
1846 ins->opcode = map_to_reg_reg_op (ins->opcode);
1848 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1853 bb->last_ins = last_ins;
1854 bb->max_vreg = cfg->rs->next_vreg;
1859 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1863 mono_arch_lowering_pass (cfg, bb);
1864 mono_local_regalloc (cfg, bb);
1868 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1870 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1871 ppc_fctiwz (code, ppc_f0, sreg);
1872 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1873 ppc_lwz (code, dreg, -4, ppc_sp);
1876 ppc_andid (code, dreg, dreg, 0xff);
1878 ppc_andid (code, dreg, dreg, 0xffff);
1881 ppc_extsb (code, dreg, dreg);
1883 ppc_extsh (code, dreg, dreg);
1888 static unsigned char*
1889 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1892 int sreg = tree->sreg1;
1893 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1894 if (tree->flags & MONO_INST_INIT) {
1896 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1897 x86_push_reg (code, X86_EAX);
1900 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1901 x86_push_reg (code, X86_ECX);
1904 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1905 x86_push_reg (code, X86_EDI);
1909 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1910 if (sreg != X86_ECX)
1911 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1912 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1914 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1916 x86_prefix (code, X86_REP_PREFIX);
1919 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1920 x86_pop_reg (code, X86_EDI);
1921 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1922 x86_pop_reg (code, X86_ECX);
1923 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1924 x86_pop_reg (code, X86_EAX);
1937 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1940 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1941 PatchData *pdata = (PatchData*)user_data;
1942 guchar *code = data;
1943 guint32 *thunks = data;
1944 guint32 *endthunks = (guint32*)(code + bsize);
1948 int difflow, diffhigh;
1950 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1951 difflow = (char*)pdata->code - (char*)thunks;
1952 diffhigh = (char*)pdata->code - (char*)endthunks;
1953 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1956 templ = (guchar*)load;
1957 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1958 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1960 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1961 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1962 while (thunks < endthunks) {
1963 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1964 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
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 lookup: %d\n", num_thunks);
1975 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1976 /* found a free slot instead: emit thunk */
1977 code = (guchar*)thunks;
1978 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1979 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1980 ppc_mtctr (code, ppc_r0);
1981 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1982 mono_arch_flush_icache ((guchar*)thunks, 16);
1984 ppc_patch (pdata->code, (guchar*)thunks);
1985 mono_arch_flush_icache (pdata->code, 4);
1988 static int num_thunks = 0;
1990 if ((num_thunks % 20) == 0)
1991 g_print ("num_thunks: %d\n", num_thunks);
1995 /* skip 16 bytes, the size of the thunk */
1999 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2005 handle_thunk (int absolute, guchar *code, guchar *target) {
2006 MonoDomain *domain = mono_domain_get ();
2010 pdata.target = target;
2011 pdata.absolute = absolute;
2014 mono_domain_lock (domain);
2015 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2018 /* this uses the first available slot */
2020 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2022 mono_domain_unlock (domain);
2024 if (pdata.found != 1)
2025 g_print ("thunk failed for %p from %p\n", target, code);
2026 g_assert (pdata.found == 1);
2030 ppc_patch (guchar *code, guchar *target)
2032 guint32 ins = *(guint32*)code;
2033 guint32 prim = ins >> 26;
2036 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2038 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2039 gint diff = target - code;
2041 if (diff <= 33554431){
2042 ins = (18 << 26) | (diff) | (ins & 1);
2043 *(guint32*)code = ins;
2047 /* diff between 0 and -33554432 */
2048 if (diff >= -33554432){
2049 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2050 *(guint32*)code = ins;
2055 if ((glong)target >= 0){
2056 if ((glong)target <= 33554431){
2057 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2058 *(guint32*)code = ins;
2062 if ((glong)target >= -33554432){
2063 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2064 *(guint32*)code = ins;
2069 handle_thunk (TRUE, code, target);
2072 g_assert_not_reached ();
2079 guint32 li = (guint32)target;
2080 ins = (ins & 0xffff0000) | (ins & 3);
2081 ovf = li & 0xffff0000;
2082 if (ovf != 0 && ovf != 0xffff0000)
2083 g_assert_not_reached ();
2086 // FIXME: assert the top bits of li are 0
2088 gint diff = target - code;
2089 ins = (ins & 0xffff0000) | (ins & 3);
2090 ovf = diff & 0xffff0000;
2091 if (ovf != 0 && ovf != 0xffff0000)
2092 g_assert_not_reached ();
2096 *(guint32*)code = ins;
2100 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2102 /* the trampoline code will try to patch the blrl, blr, bcctr */
2103 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2106 /* this is the lis/ori/mtlr/blrl sequence */
2107 seq = (guint32*)code;
2108 g_assert ((seq [0] >> 26) == 15);
2109 g_assert ((seq [1] >> 26) == 24);
2110 g_assert ((seq [2] >> 26) == 31);
2111 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2112 /* FIXME: make this thread safe */
2113 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2114 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2115 mono_arch_flush_icache (code - 8, 8);
2117 g_assert_not_reached ();
2119 // g_print ("patched with 0x%08x\n", ins);
2123 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2128 guint8 *code = cfg->native_code + cfg->code_len;
2129 MonoInst *last_ins = NULL;
2130 guint last_offset = 0;
2133 if (cfg->opt & MONO_OPT_PEEPHOLE)
2134 peephole_pass (cfg, bb);
2136 /* we don't align basic blocks of loops on ppc */
2138 if (cfg->verbose_level > 2)
2139 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2141 cpos = bb->max_offset;
2143 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2144 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2145 //g_assert (!mono_compile_aot);
2148 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2149 /* this is not thread save, but good enough */
2150 /* fixme: howto handle overflows? */
2151 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2156 offset = code - cfg->native_code;
2158 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2160 if (offset > (cfg->code_size - max_len - 16)) {
2161 cfg->code_size *= 2;
2162 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2163 code = cfg->native_code + offset;
2165 // if (ins->cil_code)
2166 // g_print ("cil code\n");
2167 mono_debug_record_line_number (cfg, ins, offset);
2169 switch (ins->opcode) {
2171 emit_tls_access (code, ins->dreg, ins->inst_offset);
2174 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2175 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2176 ppc_mr (code, ppc_r4, ppc_r0);
2179 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2180 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2181 ppc_mr (code, ppc_r4, ppc_r0);
2183 case OP_MEMORY_BARRIER:
2186 case OP_STOREI1_MEMBASE_REG:
2187 if (ppc_is_imm16 (ins->inst_offset)) {
2188 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2190 g_assert_not_reached ();
2193 case OP_STOREI2_MEMBASE_REG:
2194 if (ppc_is_imm16 (ins->inst_offset)) {
2195 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2197 g_assert_not_reached ();
2200 case OP_STORE_MEMBASE_REG:
2201 case OP_STOREI4_MEMBASE_REG:
2202 if (ppc_is_imm16 (ins->inst_offset)) {
2203 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2205 g_assert_not_reached ();
2208 case OP_STOREI1_MEMINDEX:
2209 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2211 case OP_STOREI2_MEMINDEX:
2212 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2214 case OP_STORE_MEMINDEX:
2215 case OP_STOREI4_MEMINDEX:
2216 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2221 g_assert_not_reached ();
2222 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2225 g_assert_not_reached ();
2227 case OP_LOAD_MEMBASE:
2228 case OP_LOADI4_MEMBASE:
2229 case OP_LOADU4_MEMBASE:
2230 if (ppc_is_imm16 (ins->inst_offset)) {
2231 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2233 g_assert_not_reached ();
2236 case OP_LOADI1_MEMBASE:
2237 case OP_LOADU1_MEMBASE:
2238 if (ppc_is_imm16 (ins->inst_offset)) {
2239 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2241 g_assert_not_reached ();
2243 if (ins->opcode == OP_LOADI1_MEMBASE)
2244 ppc_extsb (code, ins->dreg, ins->dreg);
2246 case OP_LOADU2_MEMBASE:
2247 if (ppc_is_imm16 (ins->inst_offset)) {
2248 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2250 g_assert_not_reached ();
2253 case OP_LOADI2_MEMBASE:
2254 if (ppc_is_imm16 (ins->inst_offset)) {
2255 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2257 g_assert_not_reached ();
2260 case OP_LOAD_MEMINDEX:
2261 case OP_LOADI4_MEMINDEX:
2262 case OP_LOADU4_MEMINDEX:
2263 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2265 case OP_LOADU2_MEMINDEX:
2266 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2268 case OP_LOADI2_MEMINDEX:
2269 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2271 case OP_LOADU1_MEMINDEX:
2272 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2274 case OP_LOADI1_MEMINDEX:
2275 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2276 ppc_extsb (code, ins->dreg, ins->dreg);
2279 ppc_extsb (code, ins->dreg, ins->sreg1);
2282 ppc_extsh (code, ins->dreg, ins->sreg1);
2285 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2288 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2291 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2292 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2294 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2296 case OP_COMPARE_IMM:
2297 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2298 if (ppc_is_uimm16 (ins->inst_imm)) {
2299 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2301 g_assert_not_reached ();
2304 if (ppc_is_imm16 (ins->inst_imm)) {
2305 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2307 g_assert_not_reached ();
2315 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2318 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2321 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2324 if (ppc_is_imm16 (ins->inst_imm)) {
2325 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2327 g_assert_not_reached ();
2331 if (ppc_is_imm16 (ins->inst_imm)) {
2332 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2334 g_assert_not_reached ();
2338 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2340 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2341 ppc_mfspr (code, ppc_r0, ppc_xer);
2342 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2343 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2345 case CEE_ADD_OVF_UN:
2346 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2348 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2349 ppc_mfspr (code, ppc_r0, ppc_xer);
2350 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2351 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2354 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2356 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2357 ppc_mfspr (code, ppc_r0, ppc_xer);
2358 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2359 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2361 case CEE_SUB_OVF_UN:
2362 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2364 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2365 ppc_mfspr (code, ppc_r0, ppc_xer);
2366 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2367 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2369 case OP_ADD_OVF_CARRY:
2370 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2372 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2373 ppc_mfspr (code, ppc_r0, ppc_xer);
2374 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2375 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2377 case OP_ADD_OVF_UN_CARRY:
2378 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2380 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2381 ppc_mfspr (code, ppc_r0, ppc_xer);
2382 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2383 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2385 case OP_SUB_OVF_CARRY:
2386 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2388 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2389 ppc_mfspr (code, ppc_r0, ppc_xer);
2390 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2391 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2393 case OP_SUB_OVF_UN_CARRY:
2394 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2396 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2397 ppc_mfspr (code, ppc_r0, ppc_xer);
2398 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2399 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2402 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2405 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2408 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2411 // we add the negated value
2412 if (ppc_is_imm16 (-ins->inst_imm))
2413 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2415 g_assert_not_reached ();
2419 g_assert (ppc_is_imm16 (ins->inst_imm));
2420 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2423 ppc_subfze (code, ins->dreg, ins->sreg1);
2426 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2427 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2430 if (!(ins->inst_imm & 0xffff0000)) {
2431 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2432 } else if (!(ins->inst_imm & 0xffff)) {
2433 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2435 g_assert_not_reached ();
2439 guint32 *divisor_is_m1;
2440 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2442 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2443 divisor_is_m1 = code;
2444 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2445 ppc_lis (code, ppc_r11, 0x8000);
2446 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2447 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2448 ppc_patch (divisor_is_m1, code);
2449 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2451 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2452 ppc_mfspr (code, ppc_r0, ppc_xer);
2453 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2454 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2458 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2459 ppc_mfspr (code, ppc_r0, ppc_xer);
2460 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2461 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2464 g_assert_not_reached ();
2466 ppc_load (code, ppc_r11, ins->inst_imm);
2467 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2468 ppc_mfspr (code, ppc_r0, ppc_xer);
2469 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2470 /* FIXME: use OverflowException for 0x80000000/-1 */
2471 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2475 guint32 *divisor_is_m1;
2476 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2477 divisor_is_m1 = code;
2478 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2479 ppc_lis (code, ppc_r11, 0x8000);
2480 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2481 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2482 ppc_patch (divisor_is_m1, code);
2483 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2484 ppc_mfspr (code, ppc_r0, ppc_xer);
2485 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2486 /* FIXME: use OverflowException for 0x80000000/-1 */
2487 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2488 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2489 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2493 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2494 ppc_mfspr (code, ppc_r0, ppc_xer);
2495 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2496 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2497 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2498 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2501 g_assert_not_reached ();
2503 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2506 if (!(ins->inst_imm & 0xffff0000)) {
2507 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2508 } else if (!(ins->inst_imm & 0xffff)) {
2509 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2511 g_assert_not_reached ();
2515 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2518 if (!(ins->inst_imm & 0xffff0000)) {
2519 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2520 } else if (!(ins->inst_imm & 0xffff)) {
2521 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2523 g_assert_not_reached ();
2527 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2530 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2533 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2536 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2540 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2542 ppc_mr (code, ins->dreg, ins->sreg1);
2545 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2548 ppc_not (code, ins->dreg, ins->sreg1);
2551 ppc_neg (code, ins->dreg, ins->sreg1);
2554 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2557 if (ppc_is_imm16 (ins->inst_imm)) {
2558 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2560 g_assert_not_reached ();
2564 /* we annot use mcrxr, since it's not implemented on some processors
2565 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2567 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2568 ppc_mfspr (code, ppc_r0, ppc_xer);
2569 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2570 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2572 case CEE_MUL_OVF_UN:
2573 /* we first multiply to get the high word and compare to 0
2574 * to set the flags, then the result is discarded and then
2575 * we multiply to get the lower * bits result
2577 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2578 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2579 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2580 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2584 ppc_load (code, ins->dreg, ins->inst_c0);
2587 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2588 ppc_lis (code, ins->dreg, 0);
2589 ppc_ori (code, ins->dreg, ins->dreg, 0);
2595 ppc_mr (code, ins->dreg, ins->sreg1);
2598 int saved = ins->sreg1;
2599 if (ins->sreg1 == ppc_r3) {
2600 ppc_mr (code, ppc_r0, ins->sreg1);
2603 if (ins->sreg2 != ppc_r3)
2604 ppc_mr (code, ppc_r3, ins->sreg2);
2605 if (saved != ppc_r4)
2606 ppc_mr (code, ppc_r4, saved);
2611 ppc_fmr (code, ins->dreg, ins->sreg1);
2613 case OP_FCONV_TO_R4:
2614 ppc_frsp (code, ins->dreg, ins->sreg1);
2620 * Keep in sync with mono_arch_emit_epilog
2622 g_assert (!cfg->method->save_lmf);
2623 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2624 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2625 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2627 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2628 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2630 ppc_mtlr (code, ppc_r0);
2632 if (ppc_is_imm16 (cfg->stack_usage)) {
2633 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2635 ppc_load (code, ppc_r11, cfg->stack_usage);
2636 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2638 if (!cfg->method->save_lmf) {
2639 /*for (i = 31; i >= 14; --i) {
2640 if (cfg->used_float_regs & (1 << i)) {
2641 pos += sizeof (double);
2642 ppc_lfd (code, i, -pos, cfg->frame_reg);
2645 for (i = 31; i >= 13; --i) {
2646 if (cfg->used_int_regs & (1 << i)) {
2647 pos += sizeof (gulong);
2648 ppc_lwz (code, i, -pos, cfg->frame_reg);
2652 /* FIXME restore from MonoLMF: though this can't happen yet */
2654 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2659 /* ensure ins->sreg1 is not NULL */
2660 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2663 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2664 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2666 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2667 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2669 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2677 call = (MonoCallInst*)ins;
2678 if (ins->flags & MONO_INST_HAS_METHOD)
2679 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2681 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2682 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2683 ppc_lis (code, ppc_r0, 0);
2684 ppc_ori (code, ppc_r0, ppc_r0, 0);
2685 ppc_mtlr (code, ppc_r0);
2694 case OP_VOIDCALL_REG:
2696 ppc_mtlr (code, ins->sreg1);
2699 case OP_FCALL_MEMBASE:
2700 case OP_LCALL_MEMBASE:
2701 case OP_VCALL_MEMBASE:
2702 case OP_VOIDCALL_MEMBASE:
2703 case OP_CALL_MEMBASE:
2704 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2705 ppc_mtlr (code, ppc_r0);
2709 g_assert_not_reached ();
2712 guint32 * zero_loop_jump, * zero_loop_start;
2713 /* keep alignment */
2714 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2715 int area_offset = alloca_waste;
2717 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2718 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2719 /* use ctr to store the number of words to 0 if needed */
2720 if (ins->flags & MONO_INST_INIT) {
2721 /* we zero 4 bytes at a time:
2722 * we add 7 instead of 3 so that we set the counter to
2723 * at least 1, otherwise the bdnz instruction will make
2724 * it negative and iterate billions of times.
2726 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2727 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2728 ppc_mtctr (code, ppc_r0);
2730 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2731 ppc_neg (code, ppc_r11, ppc_r11);
2732 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2734 if (ins->flags & MONO_INST_INIT) {
2735 /* adjust the dest reg by -4 so we can use stwu */
2736 /* we actually adjust -8 because we let the loop
2739 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2740 ppc_li (code, ppc_r11, 0);
2741 zero_loop_start = code;
2742 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2743 zero_loop_jump = code;
2744 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2745 ppc_patch (zero_loop_jump, zero_loop_start);
2747 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2755 ppc_mr (code, ppc_r3, ins->sreg1);
2756 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2757 (gpointer)"mono_arch_throw_exception");
2758 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2759 ppc_lis (code, ppc_r0, 0);
2760 ppc_ori (code, ppc_r0, ppc_r0, 0);
2761 ppc_mtlr (code, ppc_r0);
2770 ppc_mr (code, ppc_r3, ins->sreg1);
2771 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2772 (gpointer)"mono_arch_rethrow_exception");
2773 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2774 ppc_lis (code, ppc_r0, 0);
2775 ppc_ori (code, ppc_r0, ppc_r0, 0);
2776 ppc_mtlr (code, ppc_r0);
2783 case OP_START_HANDLER:
2784 ppc_mflr (code, ppc_r0);
2785 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2786 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2788 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2789 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2793 if (ins->sreg1 != ppc_r3)
2794 ppc_mr (code, ppc_r3, ins->sreg1);
2795 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2796 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2798 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2799 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2801 ppc_mtlr (code, ppc_r0);
2805 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2806 ppc_mtlr (code, ppc_r0);
2809 case OP_CALL_HANDLER:
2810 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2814 ins->inst_c0 = code - cfg->native_code;
2817 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2818 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2820 if (ins->flags & MONO_INST_BRLABEL) {
2821 /*if (ins->inst_i0->inst_c0) {
2823 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2825 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2829 /*if (ins->inst_target_bb->native_offset) {
2831 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2833 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2839 ppc_mtctr (code, ins->sreg1);
2840 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2843 ppc_li (code, ins->dreg, 0);
2844 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2845 ppc_li (code, ins->dreg, 1);
2849 ppc_li (code, ins->dreg, 1);
2850 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2851 ppc_li (code, ins->dreg, 0);
2855 ppc_li (code, ins->dreg, 1);
2856 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2857 ppc_li (code, ins->dreg, 0);
2859 case OP_COND_EXC_EQ:
2860 case OP_COND_EXC_NE_UN:
2861 case OP_COND_EXC_LT:
2862 case OP_COND_EXC_LT_UN:
2863 case OP_COND_EXC_GT:
2864 case OP_COND_EXC_GT_UN:
2865 case OP_COND_EXC_GE:
2866 case OP_COND_EXC_GE_UN:
2867 case OP_COND_EXC_LE:
2868 case OP_COND_EXC_LE_UN:
2869 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2872 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2874 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2875 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2876 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2878 case OP_COND_EXC_OV:
2879 /*ppc_mcrxr (code, 0);
2880 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2882 case OP_COND_EXC_NC:
2883 case OP_COND_EXC_NO:
2884 g_assert_not_reached ();
2896 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2899 /* floating point opcodes */
2901 ppc_load (code, ppc_r11, ins->inst_p0);
2902 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2905 ppc_load (code, ppc_r11, ins->inst_p0);
2906 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2908 case OP_STORER8_MEMBASE_REG:
2909 if (ppc_is_imm16 (ins->inst_offset)) {
2910 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2912 g_assert_not_reached ();
2915 case OP_LOADR8_MEMBASE:
2916 if (ppc_is_imm16 (ins->inst_offset)) {
2917 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2919 g_assert_not_reached ();
2922 case OP_STORER4_MEMBASE_REG:
2923 ppc_frsp (code, ins->sreg1, ins->sreg1);
2924 if (ppc_is_imm16 (ins->inst_offset)) {
2925 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2927 g_assert_not_reached ();
2930 case OP_LOADR4_MEMBASE:
2931 if (ppc_is_imm16 (ins->inst_offset)) {
2932 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2934 g_assert_not_reached ();
2937 case OP_LOADR4_MEMINDEX:
2938 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2940 case OP_LOADR8_MEMINDEX:
2941 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2943 case OP_STORER4_MEMINDEX:
2944 ppc_frsp (code, ins->sreg1, ins->sreg1);
2945 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2947 case OP_STORER8_MEMINDEX:
2948 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2950 case CEE_CONV_R_UN: {
2951 static const guint64 adjust_val = 0x4330000000000000ULL;
2952 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2953 ppc_stw (code, ppc_r0, -8, ppc_sp);
2954 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2955 ppc_load (code, ppc_r11, &adjust_val);
2956 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2957 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2958 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2961 case CEE_CONV_R4: /* FIXME: change precision */
2963 static const guint64 adjust_val = 0x4330000080000000ULL;
2964 // addis is special for ppc_r0
2965 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2966 ppc_stw (code, ppc_r0, -8, ppc_sp);
2967 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2968 ppc_stw (code, ppc_r11, -4, ppc_sp);
2969 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2970 ppc_load (code, ppc_r11, &adjust_val);
2971 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2972 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2975 case OP_FCONV_TO_I1:
2976 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2978 case OP_FCONV_TO_U1:
2979 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2981 case OP_FCONV_TO_I2:
2982 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2984 case OP_FCONV_TO_U2:
2985 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2987 case OP_FCONV_TO_I4:
2989 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2991 case OP_FCONV_TO_U4:
2993 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2995 case OP_FCONV_TO_I8:
2996 case OP_FCONV_TO_U8:
2997 g_assert_not_reached ();
2998 /* Implemented as helper calls */
3000 case OP_LCONV_TO_R_UN:
3001 g_assert_not_reached ();
3002 /* Implemented as helper calls */
3004 case OP_LCONV_TO_OVF_I: {
3005 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3006 // Check if its negative
3007 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3008 negative_branch = code;
3009 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3010 // Its positive msword == 0
3011 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3012 msword_positive_branch = code;
3013 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3015 ovf_ex_target = code;
3016 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3018 ppc_patch (negative_branch, code);
3019 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3020 msword_negative_branch = code;
3021 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3022 ppc_patch (msword_negative_branch, ovf_ex_target);
3024 ppc_patch (msword_positive_branch, code);
3025 if (ins->dreg != ins->sreg1)
3026 ppc_mr (code, ins->dreg, ins->sreg1);
3030 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3033 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3036 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3039 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3042 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3045 ppc_fneg (code, ins->dreg, ins->sreg1);
3049 g_assert_not_reached ();
3052 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3055 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3056 ppc_li (code, ins->dreg, 0);
3057 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3058 ppc_li (code, ins->dreg, 1);
3061 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3062 ppc_li (code, ins->dreg, 1);
3063 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3064 ppc_li (code, ins->dreg, 0);
3067 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3068 ppc_li (code, ins->dreg, 1);
3069 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3070 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3071 ppc_li (code, ins->dreg, 0);
3074 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3075 ppc_li (code, ins->dreg, 1);
3076 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3077 ppc_li (code, ins->dreg, 0);
3080 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3081 ppc_li (code, ins->dreg, 1);
3082 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3083 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3084 ppc_li (code, ins->dreg, 0);
3087 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3090 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3093 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3094 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3097 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3098 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3101 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3102 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3105 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3106 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3109 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3110 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3113 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3116 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3117 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3120 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3123 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3124 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3125 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3126 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3127 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3128 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3132 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3133 g_assert_not_reached ();
3136 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3137 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3138 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3139 g_assert_not_reached ();
3145 last_offset = offset;
3150 cfg->code_len = code - cfg->native_code;
3154 mono_arch_register_lowlevel_calls (void)
3158 #define patch_lis_ori(ip,val) do {\
3159 guint16 *__lis_ori = (guint16*)(ip); \
3160 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3161 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3165 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3167 MonoJumpInfo *patch_info;
3169 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3170 unsigned char *ip = patch_info->ip.i + code;
3171 const unsigned char *target;
3173 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3175 switch (patch_info->type) {
3176 case MONO_PATCH_INFO_IP:
3177 patch_lis_ori (ip, ip);
3179 case MONO_PATCH_INFO_METHOD_REL:
3180 g_assert_not_reached ();
3181 *((gpointer *)(ip)) = code + patch_info->data.offset;
3183 case MONO_PATCH_INFO_SWITCH: {
3184 gpointer *table = (gpointer *)patch_info->data.table->table;
3187 patch_lis_ori (ip, table);
3189 for (i = 0; i < patch_info->data.table->table_size; i++) {
3190 table [i] = (int)patch_info->data.table->table [i] + code;
3192 /* we put into the table the absolute address, no need for ppc_patch in this case */
3195 case MONO_PATCH_INFO_METHODCONST:
3196 case MONO_PATCH_INFO_CLASS:
3197 case MONO_PATCH_INFO_IMAGE:
3198 case MONO_PATCH_INFO_FIELD:
3199 case MONO_PATCH_INFO_VTABLE:
3200 case MONO_PATCH_INFO_IID:
3201 case MONO_PATCH_INFO_SFLDA:
3202 case MONO_PATCH_INFO_LDSTR:
3203 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3204 case MONO_PATCH_INFO_LDTOKEN:
3205 /* from OP_AOTCONST : lis + ori */
3206 patch_lis_ori (ip, target);
3208 case MONO_PATCH_INFO_R4:
3209 case MONO_PATCH_INFO_R8:
3210 g_assert_not_reached ();
3211 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3213 case MONO_PATCH_INFO_EXC_NAME:
3214 g_assert_not_reached ();
3215 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3217 case MONO_PATCH_INFO_NONE:
3218 case MONO_PATCH_INFO_BB_OVF:
3219 case MONO_PATCH_INFO_EXC_OVF:
3220 /* everything is dealt with at epilog output time */
3225 ppc_patch (ip, target);
3230 * Stack frame layout:
3232 * ------------------- sp
3233 * MonoLMF structure or saved registers
3234 * -------------------
3236 * -------------------
3238 * -------------------
3239 * optional 8 bytes for tracing
3240 * -------------------
3241 * param area size is cfg->param_area
3242 * -------------------
3243 * linkage area size is PPC_STACK_PARAM_OFFSET
3244 * ------------------- sp
3248 mono_arch_emit_prolog (MonoCompile *cfg)
3250 MonoMethod *method = cfg->method;
3252 MonoMethodSignature *sig;
3254 int alloc_size, pos, max_offset, i;
3260 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3263 sig = mono_method_signature (method);
3264 cfg->code_size = 256 + sig->param_count * 20;
3265 code = cfg->native_code = g_malloc (cfg->code_size);
3267 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3268 ppc_mflr (code, ppc_r0);
3269 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3272 alloc_size = cfg->stack_offset;
3275 if (!method->save_lmf) {
3276 /*for (i = 31; i >= 14; --i) {
3277 if (cfg->used_float_regs & (1 << i)) {
3278 pos += sizeof (gdouble);
3279 ppc_stfd (code, i, -pos, ppc_sp);
3282 for (i = 31; i >= 13; --i) {
3283 if (cfg->used_int_regs & (1 << i)) {
3284 pos += sizeof (gulong);
3285 ppc_stw (code, i, -pos, ppc_sp);
3290 pos += sizeof (MonoLMF);
3292 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3293 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3294 for (i = 14; i < 32; i++) {
3295 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3299 // align to PPC_STACK_ALIGNMENT bytes
3300 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3301 alloc_size += PPC_STACK_ALIGNMENT - 1;
3302 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3305 cfg->stack_usage = alloc_size;
3306 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3308 if (ppc_is_imm16 (-alloc_size)) {
3309 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3311 ppc_load (code, ppc_r11, -alloc_size);
3312 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3315 if (cfg->frame_reg != ppc_sp)
3316 ppc_mr (code, cfg->frame_reg, ppc_sp);
3318 /* compute max_offset in order to use short forward jumps
3319 * we always do it on ppc because the immediate displacement
3320 * for jumps is too small
3323 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3324 MonoInst *ins = bb->code;
3325 bb->max_offset = max_offset;
3327 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3331 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3336 /* load arguments allocated to register from the stack */
3339 cinfo = calculate_sizes (sig, sig->pinvoke);
3341 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3342 ArgInfo *ainfo = &cinfo->ret;
3344 if (ppc_is_imm16 (inst->inst_offset)) {
3345 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3347 ppc_load (code, ppc_r11, inst->inst_offset);
3348 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3351 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3352 ArgInfo *ainfo = cinfo->args + i;
3353 inst = cfg->args [pos];
3355 if (cfg->verbose_level > 2)
3356 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3357 if (inst->opcode == OP_REGVAR) {
3358 if (ainfo->regtype == RegTypeGeneral)
3359 ppc_mr (code, inst->dreg, ainfo->reg);
3360 else if (ainfo->regtype == RegTypeFP)
3361 ppc_fmr (code, inst->dreg, ainfo->reg);
3362 else if (ainfo->regtype == RegTypeBase) {
3363 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3364 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3366 g_assert_not_reached ();
3368 if (cfg->verbose_level > 2)
3369 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3371 /* the argument should be put on the stack: FIXME handle size != word */
3372 if (ainfo->regtype == RegTypeGeneral) {
3373 switch (ainfo->size) {
3375 if (ppc_is_imm16 (inst->inst_offset)) {
3376 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3378 ppc_load (code, ppc_r11, inst->inst_offset);
3379 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3383 if (ppc_is_imm16 (inst->inst_offset)) {
3384 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3386 ppc_load (code, ppc_r11, inst->inst_offset);
3387 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3391 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3392 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3393 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3395 ppc_load (code, ppc_r11, inst->inst_offset);
3396 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3397 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3398 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3402 if (ppc_is_imm16 (inst->inst_offset)) {
3403 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3405 ppc_load (code, ppc_r11, inst->inst_offset);
3406 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3410 } else if (ainfo->regtype == RegTypeBase) {
3411 /* load the previous stack pointer in r11 */
3412 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3413 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3414 switch (ainfo->size) {
3416 if (ppc_is_imm16 (inst->inst_offset)) {
3417 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3419 ppc_load (code, ppc_r11, inst->inst_offset);
3420 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3424 if (ppc_is_imm16 (inst->inst_offset)) {
3425 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3427 ppc_load (code, ppc_r11, inst->inst_offset);
3428 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3432 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3433 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3434 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3435 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3438 g_assert_not_reached ();
3442 if (ppc_is_imm16 (inst->inst_offset)) {
3443 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3445 ppc_load (code, ppc_r11, inst->inst_offset);
3446 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3450 } else if (ainfo->regtype == RegTypeFP) {
3451 g_assert (ppc_is_imm16 (inst->inst_offset));
3452 if (ainfo->size == 8)
3453 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3454 else if (ainfo->size == 4)
3455 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3457 g_assert_not_reached ();
3458 } else if (ainfo->regtype == RegTypeStructByVal) {
3459 int doffset = inst->inst_offset;
3463 g_assert (ppc_is_imm16 (inst->inst_offset));
3464 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3465 if (mono_class_from_mono_type (inst->inst_vtype))
3466 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3467 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3469 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3470 register. Should this case include linux/ppc?
3474 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3476 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3479 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3480 soffset += sizeof (gpointer);
3481 doffset += sizeof (gpointer);
3483 if (ainfo->vtsize) {
3484 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3485 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3486 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3487 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3489 } else if (ainfo->regtype == RegTypeStructByAddr) {
3490 /* if it was originally a RegTypeBase */
3491 if (ainfo->offset) {
3492 /* load the previous stack pointer in r11 */
3493 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3494 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3496 ppc_mr (code, ppc_r11, ainfo->reg);
3498 g_assert (ppc_is_imm16 (inst->inst_offset));
3499 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3500 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3502 g_assert_not_reached ();
3507 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3508 ppc_load (code, ppc_r3, cfg->domain);
3509 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3510 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3511 ppc_lis (code, ppc_r0, 0);
3512 ppc_ori (code, ppc_r0, ppc_r0, 0);
3513 ppc_mtlr (code, ppc_r0);
3520 if (method->save_lmf) {
3521 if (lmf_pthread_key != -1) {
3522 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3523 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3524 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3526 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3527 (gpointer)"mono_get_lmf_addr");
3528 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3529 ppc_lis (code, ppc_r0, 0);
3530 ppc_ori (code, ppc_r0, ppc_r0, 0);
3531 ppc_mtlr (code, ppc_r0);
3537 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3538 /* lmf_offset is the offset from the previous stack pointer,
3539 * alloc_size is the total stack space allocated, so the offset
3540 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3541 * The pointer to the struct is put in ppc_r11 (new_lmf).
3542 * The callee-saved registers are already in the MonoLMF structure
3544 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3545 /* ppc_r3 is the result from mono_get_lmf_addr () */
3546 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3547 /* new_lmf->previous_lmf = *lmf_addr */
3548 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3549 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3550 /* *(lmf_addr) = r11 */
3551 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3552 /* save method info */
3553 ppc_load (code, ppc_r0, method);
3554 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3555 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3556 /* save the current IP */
3557 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3558 ppc_load (code, ppc_r0, 0x01010101);
3559 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3563 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3565 cfg->code_len = code - cfg->native_code;
3566 g_assert (cfg->code_len < cfg->code_size);
3573 mono_arch_emit_epilog (MonoCompile *cfg)
3575 MonoJumpInfo *patch_info;
3576 MonoMethod *method = cfg->method;
3578 int max_epilog_size = 16 + 20*4;
3581 if (cfg->method->save_lmf)
3582 max_epilog_size += 128;
3584 if (mono_jit_trace_calls != NULL)
3585 max_epilog_size += 50;
3587 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3588 max_epilog_size += 50;
3590 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3591 cfg->code_size *= 2;
3592 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3593 mono_jit_stats.code_reallocs++;
3597 * Keep in sync with OP_JMP
3599 code = cfg->native_code + cfg->code_len;
3601 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3602 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3606 if (method->save_lmf) {
3608 pos += sizeof (MonoLMF);
3610 /* save the frame reg in r8 */
3611 ppc_mr (code, ppc_r8, cfg->frame_reg);
3612 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3613 /* r5 = previous_lmf */
3614 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3616 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3617 /* *(lmf_addr) = previous_lmf */
3618 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3619 /* FIXME: speedup: there is no actual need to restore the registers if
3620 * we didn't actually change them (idea from Zoltan).
3623 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3625 /*for (i = 14; i < 32; i++) {
3626 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3628 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3629 /* use the saved copy of the frame reg in r8 */
3630 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3631 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3632 ppc_mtlr (code, ppc_r0);
3634 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3636 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3637 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3638 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3640 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3641 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3643 ppc_mtlr (code, ppc_r0);
3645 if (ppc_is_imm16 (cfg->stack_usage)) {
3646 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3648 ppc_load (code, ppc_r11, cfg->stack_usage);
3649 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3652 /*for (i = 31; i >= 14; --i) {
3653 if (cfg->used_float_regs & (1 << i)) {
3654 pos += sizeof (double);
3655 ppc_lfd (code, i, -pos, ppc_sp);
3658 for (i = 31; i >= 13; --i) {
3659 if (cfg->used_int_regs & (1 << i)) {
3660 pos += sizeof (gulong);
3661 ppc_lwz (code, i, -pos, ppc_sp);
3667 cfg->code_len = code - cfg->native_code;
3669 g_assert (cfg->code_len < cfg->code_size);
3673 /* remove once throw_exception_by_name is eliminated */
3675 exception_id_by_name (const char *name)
3677 if (strcmp (name, "IndexOutOfRangeException") == 0)
3678 return MONO_EXC_INDEX_OUT_OF_RANGE;
3679 if (strcmp (name, "OverflowException") == 0)
3680 return MONO_EXC_OVERFLOW;
3681 if (strcmp (name, "ArithmeticException") == 0)
3682 return MONO_EXC_ARITHMETIC;
3683 if (strcmp (name, "DivideByZeroException") == 0)
3684 return MONO_EXC_DIVIDE_BY_ZERO;
3685 if (strcmp (name, "InvalidCastException") == 0)
3686 return MONO_EXC_INVALID_CAST;
3687 if (strcmp (name, "NullReferenceException") == 0)
3688 return MONO_EXC_NULL_REF;
3689 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3690 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3691 g_error ("Unknown intrinsic exception %s\n", name);
3696 mono_arch_emit_exceptions (MonoCompile *cfg)
3698 MonoJumpInfo *patch_info;
3701 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3702 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3705 int max_epilog_size = 50;
3707 /* count the number of exception infos */
3710 * make sure we have enough space for exceptions
3711 * 24 is the simulated call to throw_exception_by_name
3713 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3714 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3715 i = exception_id_by_name (patch_info->data.target);
3716 if (!exc_throw_found [i]) {
3717 max_epilog_size += 24;
3718 exc_throw_found [i] = TRUE;
3720 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3721 max_epilog_size += 12;
3722 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3723 MonoOvfJump *ovfj = patch_info->data.target;
3724 i = exception_id_by_name (ovfj->data.exception);
3725 if (!exc_throw_found [i]) {
3726 max_epilog_size += 24;
3727 exc_throw_found [i] = TRUE;
3729 max_epilog_size += 8;
3733 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3734 cfg->code_size *= 2;
3735 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3736 mono_jit_stats.code_reallocs++;
3739 code = cfg->native_code + cfg->code_len;
3741 /* add code to raise exceptions */
3742 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3743 switch (patch_info->type) {
3744 case MONO_PATCH_INFO_BB_OVF: {
3745 MonoOvfJump *ovfj = patch_info->data.target;
3746 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3747 /* patch the initial jump */
3748 ppc_patch (ip, code);
3749 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3751 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3752 /* jump back to the true target */
3754 ip = ovfj->data.bb->native_offset + cfg->native_code;
3755 ppc_patch (code - 4, ip);
3758 case MONO_PATCH_INFO_EXC_OVF: {
3759 MonoOvfJump *ovfj = patch_info->data.target;
3760 MonoJumpInfo *newji;
3761 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3762 unsigned char *bcl = code;
3763 /* patch the initial jump: we arrived here with a call */
3764 ppc_patch (ip, code);
3765 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3767 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3768 /* patch the conditional jump to the right handler */
3769 /* make it processed next */
3770 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3771 newji->type = MONO_PATCH_INFO_EXC;
3772 newji->ip.i = bcl - cfg->native_code;
3773 newji->data.target = ovfj->data.exception;
3774 newji->next = patch_info->next;
3775 patch_info->next = newji;
3778 case MONO_PATCH_INFO_EXC: {
3779 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3780 i = exception_id_by_name (patch_info->data.target);
3781 if (exc_throw_pos [i]) {
3782 ppc_patch (ip, exc_throw_pos [i]);
3783 patch_info->type = MONO_PATCH_INFO_NONE;
3786 exc_throw_pos [i] = code;
3788 ppc_patch (ip, code);
3789 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3790 ppc_load (code, ppc_r3, patch_info->data.target);
3791 /* we got here from a conditional call, so the calling ip is set in lr already */
3792 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3793 patch_info->data.name = "mono_arch_throw_exception_by_name";
3794 patch_info->ip.i = code - cfg->native_code;
3795 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3796 ppc_lis (code, ppc_r0, 0);
3797 ppc_ori (code, ppc_r0, ppc_r0, 0);
3798 ppc_mtctr (code, ppc_r0);
3799 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3811 cfg->code_len = code - cfg->native_code;
3813 g_assert (cfg->code_len < cfg->code_size);
3818 try_offset_access (void *value, guint32 idx)
3820 register void* me __asm__ ("r2");
3821 void ***p = (void***)((char*)me + 284);
3822 int idx1 = idx / 32;
3823 int idx2 = idx % 32;
3826 if (value != p[idx1][idx2])
3832 setup_tls_access (void)
3835 guint32 *ins, *code;
3836 guint32 cmplwi_1023, li_0x48, blr_ins;
3837 if (tls_mode == TLS_MODE_FAILED)
3840 if (g_getenv ("MONO_NO_TLS")) {
3841 tls_mode = TLS_MODE_FAILED;
3845 if (tls_mode == TLS_MODE_DETECT) {
3846 ins = (guint32*)pthread_getspecific;
3847 /* uncond branch to the real method */
3848 if ((*ins >> 26) == 18) {
3850 val = (*ins & ~3) << 6;
3854 ins = (guint32*)val;
3856 ins = (guint32*) ((char*)ins + val);
3859 code = &cmplwi_1023;
3860 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3862 ppc_li (code, ppc_r4, 0x48);
3865 if (*ins == cmplwi_1023) {
3866 int found_lwz_284 = 0;
3867 for (ptk = 0; ptk < 20; ++ptk) {
3869 if (!*ins || *ins == blr_ins)
3871 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3876 if (!found_lwz_284) {
3877 tls_mode = TLS_MODE_FAILED;
3880 tls_mode = TLS_MODE_LTHREADS;
3881 } else if (*ins == li_0x48) {
3883 /* uncond branch to the real method */
3884 if ((*ins >> 26) == 18) {
3886 val = (*ins & ~3) << 6;
3890 ins = (guint32*)val;
3892 ins = (guint32*) ((char*)ins + val);
3895 ppc_li (code, ppc_r0, 0x7FF2);
3896 if (ins [1] == val) {
3897 /* Darwin on G4, implement */
3898 tls_mode = TLS_MODE_FAILED;
3902 ppc_mfspr (code, ppc_r3, 104);
3903 if (ins [1] != val) {
3904 tls_mode = TLS_MODE_FAILED;
3907 tls_mode = TLS_MODE_DARWIN_G5;
3910 tls_mode = TLS_MODE_FAILED;
3914 tls_mode = TLS_MODE_FAILED;
3918 if (monodomain_key == -1) {
3919 ptk = mono_domain_get_tls_key ();
3921 ptk = mono_pthread_key_for_tls (ptk);
3923 monodomain_key = ptk;
3927 if (lmf_pthread_key == -1) {
3928 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3930 /*g_print ("MonoLMF at: %d\n", ptk);*/
3931 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3932 init_tls_failed = 1;
3935 lmf_pthread_key = ptk;
3938 if (monothread_key == -1) {
3939 ptk = mono_thread_get_tls_key ();
3941 ptk = mono_pthread_key_for_tls (ptk);
3943 monothread_key = ptk;
3944 /*g_print ("thread inited: %d\n", ptk);*/
3947 /*g_print ("thread not inited yet %d\n", ptk);*/
3953 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3955 setup_tls_access ();
3959 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3964 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3966 int this_dreg = ppc_r3;
3971 /* add the this argument */
3972 if (this_reg != -1) {
3974 MONO_INST_NEW (cfg, this, OP_SETREG);
3975 this->type = this_type;
3976 this->sreg1 = this_reg;
3977 this->dreg = mono_regstate_next_int (cfg->rs);
3978 mono_bblock_add_inst (cfg->cbb, this);
3979 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3984 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3985 vtarg->type = STACK_MP;
3986 vtarg->sreg1 = vt_reg;
3987 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3988 mono_bblock_add_inst (cfg->cbb, vtarg);
3989 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3993 #ifdef MONO_ARCH_HAVE_IMT
3997 #define JUMP_IMM_SIZE 12
3998 #define ENABLE_WRONG_METHOD_CHECK 0
4001 * LOCKING: called with the domain lock held
4004 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4008 guint8 *code, *start;
4010 for (i = 0; i < count; ++i) {
4011 MonoIMTCheckItem *item = imt_entries [i];
4012 if (item->is_equals) {
4013 if (item->check_target_idx) {
4014 if (!item->compare_done)
4015 item->chunk_size += CMP_SIZE;
4016 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4018 item->chunk_size += JUMP_IMM_SIZE;
4019 #if ENABLE_WRONG_METHOD_CHECK
4020 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4024 item->chunk_size += CMP_SIZE + BR_SIZE;
4025 imt_entries [item->check_target_idx]->compare_done = TRUE;
4027 size += item->chunk_size;
4029 /* the initial load of the vtable address */
4031 code = mono_code_manager_reserve (domain->code_mp, size);
4033 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4034 for (i = 0; i < count; ++i) {
4035 MonoIMTCheckItem *item = imt_entries [i];
4036 item->code_target = code;
4037 if (item->is_equals) {
4038 if (item->check_target_idx) {
4039 if (!item->compare_done) {
4040 ppc_load (code, ppc_r0, (guint32)item->method);
4041 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4043 item->jmp_code = code;
4044 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4045 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4046 ppc_mtctr (code, ppc_r0);
4047 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4049 /* enable the commented code to assert on wrong method */
4050 #if ENABLE_WRONG_METHOD_CHECK
4051 ppc_load (code, ppc_r0, (guint32)item->method);
4052 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4053 item->jmp_code = code;
4054 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4056 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4057 ppc_mtctr (code, ppc_r0);
4058 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4059 #if ENABLE_WRONG_METHOD_CHECK
4060 ppc_patch (item->jmp_code, code);
4062 item->jmp_code = NULL;
4066 ppc_load (code, ppc_r0, (guint32)item->method);
4067 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4068 item->jmp_code = code;
4069 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4072 /* patch the branches to get to the target items */
4073 for (i = 0; i < count; ++i) {
4074 MonoIMTCheckItem *item = imt_entries [i];
4075 if (item->jmp_code) {
4076 if (item->check_target_idx) {
4077 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4082 mono_stats.imt_thunks_size += code - start;
4083 g_assert (code - start <= size);
4084 mono_arch_flush_icache (start, size);
4089 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4091 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4095 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
4097 return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
4102 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4104 MonoInst *ins = NULL;
4106 if (cmethod->klass == mono_defaults.thread_class &&
4107 strcmp (cmethod->name, "MemoryBarrier") == 0) {
4108 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4110 /*if (cmethod->klass == mono_defaults.math_class) {
4111 if (strcmp (cmethod->name, "Sqrt") == 0) {
4112 MONO_INST_NEW (cfg, ins, OP_SQRT);
4113 ins->inst_i0 = args [0];
4120 mono_arch_print_tree (MonoInst *tree, int arity)
4125 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4129 setup_tls_access ();
4130 if (monodomain_key == -1)
4133 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4134 ins->inst_offset = monodomain_key;
4139 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4143 setup_tls_access ();
4144 if (monothread_key == -1)
4147 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4148 ins->inst_offset = monothread_key;