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>
26 alloc_ireg (MonoCompile *cfg)
28 return cfg->next_vreg ++;
32 alloc_lreg (MonoCompile *cfg)
34 #if SIZEOF_VOID_P == 8
35 return cfg->next_vreg ++;
37 /* Use a pair of consecutive vregs */
38 guint32 res = cfg->next_vreg;
47 alloc_freg (MonoCompile *cfg)
49 #ifdef MONO_ARCH_SOFT_FLOAT
50 /* Allocate an lvreg so float ops can be decomposed into long ops */
51 return alloc_lreg (cfg);
53 /* Allocate these from the same pool as the int regs */
54 return cfg->next_vreg ++;
59 alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
66 return alloc_ireg (cfg);
68 return alloc_freg (cfg);
70 return alloc_lreg (cfg);
72 return alloc_ireg (cfg);
74 g_assert_not_reached ();
78 #ifdef MONO_ARCH_SOFT_FLOAT
79 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
81 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
84 #define NEW_VARLOADA(cfg,dest,var,vartype) do { \
85 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
86 (dest)->inst_p0 = (var); \
87 (var)->flags |= MONO_INST_INDIRECT; \
88 (dest)->type = STACK_MP; \
89 (dest)->klass = (var)->klass; \
90 (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
91 if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
94 #define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
96 #define FORCE_INDIR_CALL 1
107 /* This mutex protects architecture specific caches */
108 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
109 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
110 static CRITICAL_SECTION mini_arch_mutex;
112 int mono_exc_esp_offset = 0;
113 static int tls_mode = TLS_MODE_DETECT;
114 static int lmf_pthread_key = -1;
115 static int monothread_key = -1;
116 static int monodomain_key = -1;
119 offsets_from_pthread_key (guint32 key, int *offset2)
123 *offset2 = idx2 * sizeof (gpointer);
124 return 284 + idx1 * sizeof (gpointer);
127 #define emit_linuxthreads_tls(code,dreg,key) do {\
129 off1 = offsets_from_pthread_key ((key), &off2); \
130 ppc_lwz ((code), (dreg), off1, ppc_r2); \
131 ppc_lwz ((code), (dreg), off2, (dreg)); \
134 #define emit_darwing5_tls(code,dreg,key) do {\
135 int off1 = 0x48 + key * sizeof (gpointer); \
136 ppc_mfspr ((code), (dreg), 104); \
137 ppc_lwz ((code), (dreg), off1, (dreg)); \
140 /* FIXME: ensure the sc call preserves all but r3 */
141 #define emit_darwing4_tls(code,dreg,key) do {\
142 int off1 = 0x48 + key * sizeof (gpointer); \
143 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
144 ppc_li ((code), ppc_r0, 0x7FF2); \
146 ppc_lwz ((code), (dreg), off1, ppc_r3); \
147 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
150 #define emit_tls_access(code,dreg,key) do { \
151 switch (tls_mode) { \
152 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
153 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
154 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
155 default: g_assert_not_reached (); \
160 mono_arch_regname (int reg) {
161 static const char rnames[][4] = {
162 "r0", "sp", "r2", "r3", "r4",
163 "r5", "r6", "r7", "r8", "r9",
164 "r10", "r11", "r12", "r13", "r14",
165 "r15", "r16", "r17", "r18", "r19",
166 "r20", "r21", "r22", "r23", "r24",
167 "r25", "r26", "r27", "r28", "r29",
170 if (reg >= 0 && reg < 32)
176 mono_arch_fregname (int reg) {
177 static const char rnames[][4] = {
178 "f0", "f1", "f2", "f3", "f4",
179 "f5", "f6", "f7", "f8", "f9",
180 "f10", "f11", "f12", "f13", "f14",
181 "f15", "f16", "f17", "f18", "f19",
182 "f20", "f21", "f22", "f23", "f24",
183 "f25", "f26", "f27", "f28", "f29",
186 if (reg >= 0 && reg < 32)
191 /* this function overwrites r0, r11, r12 */
193 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
195 /* unrolled, use the counter in big */
196 if (size > sizeof (gpointer) * 5) {
197 int shifted = size >> 2;
198 guint8 *copy_loop_start, *copy_loop_jump;
200 ppc_load (code, ppc_r0, shifted);
201 ppc_mtctr (code, ppc_r0);
202 g_assert (sreg == ppc_r11);
203 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
204 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
205 copy_loop_start = code;
206 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
207 ppc_stwu (code, ppc_r0, 4, ppc_r12);
208 copy_loop_jump = code;
209 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
210 ppc_patch (copy_loop_jump, copy_loop_start);
212 doffset = soffset = 0;
216 ppc_lwz (code, ppc_r0, soffset, sreg);
217 ppc_stw (code, ppc_r0, doffset, dreg);
223 ppc_lhz (code, ppc_r0, soffset, sreg);
224 ppc_sth (code, ppc_r0, doffset, dreg);
230 ppc_lbz (code, ppc_r0, soffset, sreg);
231 ppc_stb (code, ppc_r0, doffset, dreg);
240 * mono_arch_get_argument_info:
241 * @csig: a method signature
242 * @param_count: the number of parameters to consider
243 * @arg_info: an array to store the result infos
245 * Gathers information on parameters such as size, alignment and
246 * padding. arg_info should be large enought to hold param_count + 1 entries.
248 * Returns the size of the activation frame.
251 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
253 int k, frame_size = 0;
254 int size, align, pad;
257 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
258 frame_size += sizeof (gpointer);
262 arg_info [0].offset = offset;
265 frame_size += sizeof (gpointer);
269 arg_info [0].size = frame_size;
271 for (k = 0; k < param_count; k++) {
274 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
276 size = mini_type_stack_size (NULL, csig->params [k], &align);
278 /* ignore alignment for now */
281 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
282 arg_info [k].pad = pad;
284 arg_info [k + 1].pad = 0;
285 arg_info [k + 1].size = size;
287 arg_info [k + 1].offset = offset;
291 align = MONO_ARCH_FRAME_ALIGNMENT;
292 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
293 arg_info [k].pad = pad;
299 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
303 guint32* code = (guint32*)code_ptr;
307 /* This is the 'blrl' instruction */
310 /* Sanity check: instruction must be 'blrl' */
311 if (*code != 0x4e800021)
314 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
315 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
319 /* OK, we're now at the 'blrl' instruction. Now walk backwards
320 till we get to a 'mtlr rA' */
322 if((*code & 0x7c0803a6) == 0x7c0803a6) {
324 /* Here we are: we reached the 'mtlr rA'.
325 Extract the register from the instruction */
326 reg = (*code & 0x03e00000) >> 21;
328 /* ok, this is a lwz reg, offset (vtreg)
329 * it is emitted with:
330 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
332 soff = (*code & 0xffff);
334 reg = (*code >> 16) & 0x1f;
335 g_assert (reg != ppc_r1);
336 /*g_print ("patching reg is %d\n", reg);*/
338 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
339 /* saved in the MonoLMF structure */
340 o = (gpointer)lmf->iregs [reg - 13];
347 *displacement = offset;
352 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
356 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
359 return (gpointer*)((char*)vt + displacement);
362 #define MAX_ARCH_DELEGATE_PARAMS 7
365 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
367 guint8 *code, *start;
369 /* FIXME: Support more cases */
370 if (MONO_TYPE_ISSTRUCT (sig->ret))
374 static guint8* cached = NULL;
375 mono_mini_arch_lock ();
377 mono_mini_arch_unlock ();
381 start = code = mono_global_codeman_reserve (16);
383 /* Replace the this argument with the target */
384 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
385 ppc_mtctr (code, ppc_r0);
386 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
387 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
389 g_assert ((code - start) <= 16);
391 mono_arch_flush_icache (start, 16);
393 mono_mini_arch_unlock ();
396 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
399 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
401 for (i = 0; i < sig->param_count; ++i)
402 if (!mono_is_regsize_var (sig->params [i]))
405 mono_mini_arch_lock ();
406 code = cache [sig->param_count];
408 mono_mini_arch_unlock ();
412 size = 12 + sig->param_count * 4;
413 start = code = mono_global_codeman_reserve (size);
415 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 ppc_mtctr (code, ppc_r0);
417 /* slide down the arguments */
418 for (i = 0; i < sig->param_count; ++i) {
419 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
421 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
423 g_assert ((code - start) <= size);
425 mono_arch_flush_icache (start, size);
426 cache [sig->param_count] = start;
427 mono_mini_arch_unlock ();
434 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
436 /* FIXME: handle returning a struct */
437 if (MONO_TYPE_ISSTRUCT (sig->ret))
438 return (gpointer)regs [ppc_r4];
439 return (gpointer)regs [ppc_r3];
443 * Initialize the cpu to execute managed code.
446 mono_arch_cpu_init (void)
451 * Initialize architecture specific code.
454 mono_arch_init (void)
456 InitializeCriticalSection (&mini_arch_mutex);
460 * Cleanup architecture specific code.
463 mono_arch_cleanup (void)
465 DeleteCriticalSection (&mini_arch_mutex);
469 * This function returns the optimizations supported on this cpu.
472 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
476 /* no ppc-specific optimizations yet */
482 is_regsize_var (MonoType *t) {
485 t = mini_type_get_underlying_type (NULL, t);
492 case MONO_TYPE_FNPTR:
494 case MONO_TYPE_OBJECT:
495 case MONO_TYPE_STRING:
496 case MONO_TYPE_CLASS:
497 case MONO_TYPE_SZARRAY:
498 case MONO_TYPE_ARRAY:
500 case MONO_TYPE_GENERICINST:
501 if (!mono_type_generic_inst_is_valuetype (t))
504 case MONO_TYPE_VALUETYPE:
511 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
516 for (i = 0; i < cfg->num_varinfo; i++) {
517 MonoInst *ins = cfg->varinfo [i];
518 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
521 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
524 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
527 /* we can only allocate 32 bit values */
528 if (is_regsize_var (ins->inst_vtype)) {
529 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
530 g_assert (i == vmv->idx);
531 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
539 mono_arch_get_global_int_regs (MonoCompile *cfg)
543 if (cfg->frame_reg != ppc_sp)
545 /* ppc_r13 is used by the system on PPC EABI */
546 for (i = 14; i < top; ++i)
547 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
553 * mono_arch_regalloc_cost:
555 * Return the cost, in number of memory references, of the action of
556 * allocating the variable VMV into a register during global register
560 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
572 mono_arch_flush_icache (guint8 *code, gint size)
574 guint8 *p, *endp, *start;
575 static int cachelinesize = 0;
576 static int cachelineinc = 16;
578 if (!cachelinesize) {
583 mib [1] = HW_CACHELINE;
584 len = sizeof (cachelinesize);
585 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
589 cachelineinc = cachelinesize;
590 /*g_print ("setting cl size to %d\n", cachelinesize);*/
592 #elif defined(__linux__)
593 /* sadly this will work only with 2.6 kernels... */
594 FILE* f = fopen ("/proc/self/auxv", "rb");
597 while (fread (&vec, sizeof (vec), 1, f) == 1) {
598 if (vec.type == 19) {
599 cachelinesize = vec.value;
608 #warning Need a way to get cache line size
614 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
615 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
617 for (p = start; p < endp; p += cachelineinc) {
618 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
621 for (p = start; p < endp; p += cachelineinc) {
622 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
627 for (p = start; p < endp; p += cachelineinc) {
628 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
635 mono_arch_flush_register_windows (void)
640 #define ALWAYS_ON_STACK(s) s
641 #define FP_ALSO_IN_REG(s) s
643 #define ALWAYS_ON_STACK(s)
644 #define FP_ALSO_IN_REG(s)
645 #define ALIGN_DOUBLES
658 guint32 vtsize; /* in param area */
660 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
661 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
676 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
679 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
680 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
681 ainfo->reg = ppc_sp; /* in the caller */
682 ainfo->regtype = RegTypeBase;
685 ALWAYS_ON_STACK (*stack_size += 4);
689 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
691 //*stack_size += (*stack_size % 8);
693 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
694 ainfo->reg = ppc_sp; /* in the caller */
695 ainfo->regtype = RegTypeBase;
702 ALWAYS_ON_STACK (*stack_size += 8);
712 has_only_a_r48_field (MonoClass *klass)
716 gboolean have_field = FALSE;
718 while ((f = mono_class_get_fields (klass, &iter))) {
719 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
722 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
733 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
736 int n = sig->hasthis + sig->param_count;
738 guint32 stack_size = 0;
739 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
741 fr = PPC_FIRST_FPARG_REG;
742 gr = PPC_FIRST_ARG_REG;
744 /* FIXME: handle returning a struct */
745 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
746 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
747 cinfo->struct_ret = PPC_FIRST_ARG_REG;
752 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
755 DEBUG(printf("params: %d\n", sig->param_count));
756 for (i = 0; i < sig->param_count; ++i) {
757 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
758 /* Prevent implicit arguments and sig_cookie from
759 being passed in registers */
760 gr = PPC_LAST_ARG_REG + 1;
761 /* FIXME: don't we have to set fr, too? */
762 /* Emit the signature cookie just before the implicit arguments */
763 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
765 DEBUG(printf("param %d: ", i));
766 if (sig->params [i]->byref) {
767 DEBUG(printf("byref\n"));
768 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
772 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
773 switch (simpletype) {
774 case MONO_TYPE_BOOLEAN:
777 cinfo->args [n].size = 1;
778 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
784 cinfo->args [n].size = 2;
785 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
790 cinfo->args [n].size = 4;
791 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
797 case MONO_TYPE_FNPTR:
798 case MONO_TYPE_CLASS:
799 case MONO_TYPE_OBJECT:
800 case MONO_TYPE_STRING:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_ARRAY:
803 cinfo->args [n].size = sizeof (gpointer);
804 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
807 case MONO_TYPE_GENERICINST:
808 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
809 cinfo->args [n].size = sizeof (gpointer);
810 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
815 case MONO_TYPE_VALUETYPE: {
818 klass = mono_class_from_mono_type (sig->params [i]);
820 size = mono_class_native_size (klass, NULL);
822 size = mono_class_value_size (klass, NULL);
824 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
825 cinfo->args [n].size = size;
827 /* It was 7, now it is 8 in LinuxPPC */
828 if (fr <= PPC_LAST_FPARG_REG) {
829 cinfo->args [n].regtype = RegTypeFP;
830 cinfo->args [n].reg = fr;
832 FP_ALSO_IN_REG (gr ++);
834 FP_ALSO_IN_REG (gr ++);
835 ALWAYS_ON_STACK (stack_size += size);
837 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
838 cinfo->args [n].regtype = RegTypeBase;
839 cinfo->args [n].reg = ppc_sp; /* in the caller*/
846 DEBUG(printf ("load %d bytes struct\n",
847 mono_class_native_size (sig->params [i]->data.klass, NULL)));
848 #if PPC_PASS_STRUCTS_BY_VALUE
850 int align_size = size;
852 int rest = PPC_LAST_ARG_REG - gr + 1;
854 align_size += (sizeof (gpointer) - 1);
855 align_size &= ~(sizeof (gpointer) - 1);
856 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
857 n_in_regs = rest >= nwords? nwords: rest;
858 cinfo->args [n].regtype = RegTypeStructByVal;
859 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
860 cinfo->args [n].size = 0;
861 cinfo->args [n].vtsize = nwords;
863 cinfo->args [n].size = n_in_regs;
864 cinfo->args [n].vtsize = nwords - n_in_regs;
865 cinfo->args [n].reg = gr;
868 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
869 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
870 stack_size += nwords * sizeof (gpointer);
873 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
874 cinfo->args [n].regtype = RegTypeStructByAddr;
875 cinfo->args [n].vtsize = size;
880 case MONO_TYPE_TYPEDBYREF: {
881 int size = sizeof (MonoTypedRef);
882 /* keep in sync or merge with the valuetype case */
883 #if PPC_PASS_STRUCTS_BY_VALUE
885 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
886 cinfo->args [n].regtype = RegTypeStructByVal;
887 if (gr <= PPC_LAST_ARG_REG) {
888 int rest = PPC_LAST_ARG_REG - gr + 1;
889 int n_in_regs = rest >= nwords? nwords: rest;
890 cinfo->args [n].size = n_in_regs;
891 cinfo->args [n].vtsize = nwords - n_in_regs;
892 cinfo->args [n].reg = gr;
895 cinfo->args [n].size = 0;
896 cinfo->args [n].vtsize = nwords;
898 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
899 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
900 stack_size += nwords * sizeof (gpointer);
903 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
904 cinfo->args [n].regtype = RegTypeStructByAddr;
905 cinfo->args [n].vtsize = size;
912 cinfo->args [n].size = 8;
913 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
917 cinfo->args [n].size = 4;
919 /* It was 7, now it is 8 in LinuxPPC */
920 if (fr <= PPC_LAST_FPARG_REG) {
921 cinfo->args [n].regtype = RegTypeFP;
922 cinfo->args [n].reg = fr;
924 FP_ALSO_IN_REG (gr ++);
925 ALWAYS_ON_STACK (stack_size += 4);
927 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
928 cinfo->args [n].regtype = RegTypeBase;
929 cinfo->args [n].reg = ppc_sp; /* in the caller*/
935 cinfo->args [n].size = 8;
936 /* It was 7, now it is 8 in LinuxPPC */
937 if (fr <= PPC_LAST_FPARG_REG) {
938 cinfo->args [n].regtype = RegTypeFP;
939 cinfo->args [n].reg = fr;
941 FP_ALSO_IN_REG (gr += 2);
942 ALWAYS_ON_STACK (stack_size += 8);
944 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
945 cinfo->args [n].regtype = RegTypeBase;
946 cinfo->args [n].reg = ppc_sp; /* in the caller*/
952 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
956 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
957 /* Prevent implicit arguments and sig_cookie from
958 being passed in registers */
959 gr = PPC_LAST_ARG_REG + 1;
960 /* Emit the signature cookie just before the implicit arguments */
961 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
965 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
966 switch (simpletype) {
967 case MONO_TYPE_BOOLEAN:
978 case MONO_TYPE_FNPTR:
979 case MONO_TYPE_CLASS:
980 case MONO_TYPE_OBJECT:
981 case MONO_TYPE_SZARRAY:
982 case MONO_TYPE_ARRAY:
983 case MONO_TYPE_STRING:
984 cinfo->ret.reg = ppc_r3;
988 cinfo->ret.reg = ppc_r3;
992 cinfo->ret.reg = ppc_f1;
993 cinfo->ret.regtype = RegTypeFP;
995 case MONO_TYPE_GENERICINST:
996 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
997 cinfo->ret.reg = ppc_r3;
1001 case MONO_TYPE_VALUETYPE:
1003 case MONO_TYPE_TYPEDBYREF:
1004 case MONO_TYPE_VOID:
1007 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1011 /* align stack size to 16 */
1012 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1013 stack_size = (stack_size + 15) & ~15;
1015 cinfo->stack_usage = stack_size;
1020 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1022 #if !PPC_PASS_STRUCTS_BY_VALUE
1023 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1024 int num_structs = 0;
1027 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1030 for (i = 0; i < sig->param_count; ++i) {
1031 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1032 if (type->type == MONO_TYPE_VALUETYPE)
1037 cfg->tailcall_valuetype_addrs =
1038 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1039 for (i = 0; i < num_structs; ++i) {
1040 cfg->tailcall_valuetype_addrs [i] =
1041 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1042 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1049 * Set var information according to the calling convention. ppc version.
1050 * The locals var stuff should most likely be split in another method.
1053 mono_arch_allocate_vars (MonoCompile *m)
1055 MonoMethodSignature *sig;
1056 MonoMethodHeader *header;
1058 int i, offset, size, align, curinst;
1059 int frame_reg = ppc_sp;
1061 guint32 locals_stack_size, locals_stack_align;
1063 allocate_tailcall_valuetype_addrs (m);
1065 m->flags |= MONO_CFG_HAS_SPILLUP;
1067 /* allow room for the vararg method args: void* and long/double */
1068 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1069 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1070 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1071 * call convs needs to be handled this way.
1073 if (m->flags & MONO_CFG_HAS_VARARGS)
1074 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1075 /* gtk-sharp and other broken code will dllimport vararg functions even with
1076 * non-varargs signatures. Since there is little hope people will get this right
1077 * we assume they won't.
1079 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1080 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1082 header = mono_method_get_header (m->method);
1085 * We use the frame register also for any method that has
1086 * exception clauses. This way, when the handlers are called,
1087 * the code will reference local variables using the frame reg instead of
1088 * the stack pointer: if we had to restore the stack pointer, we'd
1089 * corrupt the method frames that are already on the stack (since
1090 * filters get called before stack unwinding happens) when the filter
1091 * code would call any method (this also applies to finally etc.).
1093 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1094 frame_reg = ppc_r31;
1095 m->frame_reg = frame_reg;
1096 if (frame_reg != ppc_sp) {
1097 m->used_int_regs |= 1 << frame_reg;
1100 sig = mono_method_signature (m->method);
1104 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1105 m->ret->opcode = OP_REGVAR;
1106 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1108 /* FIXME: handle long values? */
1109 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1110 case MONO_TYPE_VOID:
1114 m->ret->opcode = OP_REGVAR;
1115 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1118 m->ret->opcode = OP_REGVAR;
1119 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1123 /* local vars are at a positive offset from the stack pointer */
1125 * also note that if the function uses alloca, we use ppc_r31
1126 * to point at the local variables.
1128 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1129 /* align the offset to 16 bytes: not sure this is needed here */
1131 //offset &= ~(16 - 1);
1133 /* add parameter area size for called functions */
1134 offset += m->param_area;
1136 offset &= ~(16 - 1);
1138 /* allow room to save the return value */
1139 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1142 /* the MonoLMF structure is stored just below the stack pointer */
1145 /* this stuff should not be needed on ppc and the new jit,
1146 * because a call on ppc to the handlers doesn't change the
1147 * stack pointer and the jist doesn't manipulate the stack pointer
1148 * for operations involving valuetypes.
1150 /* reserve space to store the esp */
1151 offset += sizeof (gpointer);
1153 /* this is a global constant */
1154 mono_exc_esp_offset = offset;
1156 if (sig->call_convention == MONO_CALL_VARARG) {
1157 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1160 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1161 offset += sizeof(gpointer) - 1;
1162 offset &= ~(sizeof(gpointer) - 1);
1165 m->vret_addr->opcode = OP_REGOFFSET;
1166 m->vret_addr->inst_basereg = frame_reg;
1167 m->vret_addr->inst_offset = offset;
1169 if (G_UNLIKELY (m->verbose_level > 1)) {
1170 printf ("vret_addr =");
1171 mono_print_ins (m->vret_addr);
1175 inst->inst_offset = offset;
1176 inst->opcode = OP_REGOFFSET;
1177 inst->inst_basereg = frame_reg;
1180 offset += sizeof(gpointer);
1181 if (sig->call_convention == MONO_CALL_VARARG)
1182 m->sig_cookie += sizeof (gpointer);
1185 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1186 if (locals_stack_align) {
1187 offset += (locals_stack_align - 1);
1188 offset &= ~(locals_stack_align - 1);
1190 for (i = m->locals_start; i < m->num_varinfo; i++) {
1191 if (offsets [i] != -1) {
1192 MonoInst *inst = m->varinfo [i];
1193 inst->opcode = OP_REGOFFSET;
1194 inst->inst_basereg = frame_reg;
1195 inst->inst_offset = offset + offsets [i];
1197 g_print ("allocating local %d (%s) to %d\n",
1198 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1202 offset += locals_stack_size;
1206 inst = m->args [curinst];
1207 if (inst->opcode != OP_REGVAR) {
1208 inst->opcode = OP_REGOFFSET;
1209 inst->inst_basereg = frame_reg;
1210 offset += sizeof (gpointer) - 1;
1211 offset &= ~(sizeof (gpointer) - 1);
1212 inst->inst_offset = offset;
1213 offset += sizeof (gpointer);
1214 if (sig->call_convention == MONO_CALL_VARARG)
1215 m->sig_cookie += sizeof (gpointer);
1220 for (i = 0; i < sig->param_count; ++i) {
1221 inst = m->args [curinst];
1222 if (inst->opcode != OP_REGVAR) {
1223 inst->opcode = OP_REGOFFSET;
1224 inst->inst_basereg = frame_reg;
1226 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1227 inst->backend.is_pinvoke = 1;
1229 size = mono_type_size (sig->params [i], &align);
1231 offset += align - 1;
1232 offset &= ~(align - 1);
1233 inst->inst_offset = offset;
1235 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1236 m->sig_cookie += size;
1241 /* align the offset to 16 bytes */
1243 offset &= ~(16 - 1);
1246 m->stack_offset = offset;
1248 if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1249 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1251 m->sig_cookie = cinfo->sig_cookie.offset;
1258 mono_arch_create_vars (MonoCompile *cfg)
1260 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1262 if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1263 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1267 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1268 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1272 * take the arguments and generate the arch-specific
1273 * instructions to properly call the function in call.
1274 * This includes pushing, moving arguments to the right register
1276 * Issue: who does the spilling if needed, and when?
1279 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1281 MonoMethodSignature *sig;
1286 sig = call->signature;
1287 n = sig->param_count + sig->hasthis;
1289 cinfo = calculate_sizes (sig, sig->pinvoke);
1290 if (cinfo->struct_ret)
1291 call->used_iregs |= 1 << cinfo->struct_ret;
1293 for (i = 0; i < n; ++i) {
1294 ainfo = cinfo->args + i;
1295 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1297 cfg->disable_aot = TRUE;
1299 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1300 sig_arg->inst_p0 = call->signature;
1302 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1303 arg->inst_imm = cinfo->sig_cookie.offset;
1304 arg->inst_left = sig_arg;
1305 arg->inst_call = call;
1306 /* prepend, so they get reversed */
1307 arg->next = call->out_args;
1308 call->out_args = arg;
1310 if (is_virtual && i == 0) {
1311 /* the argument will be attached to the call instrucion */
1312 in = call->args [i];
1313 call->used_iregs |= 1 << ainfo->reg;
1315 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1316 in = call->args [i];
1317 arg->cil_code = in->cil_code;
1318 arg->inst_left = in;
1319 arg->inst_call = call;
1320 arg->type = in->type;
1321 /* prepend, so they get reversed */
1322 arg->next = call->out_args;
1323 call->out_args = arg;
1324 if (ainfo->regtype == RegTypeGeneral) {
1325 arg->backend.reg3 = ainfo->reg;
1326 call->used_iregs |= 1 << ainfo->reg;
1327 if (arg->type == STACK_I8)
1328 call->used_iregs |= 1 << (ainfo->reg + 1);
1329 } else if (ainfo->regtype == RegTypeStructByAddr) {
1330 if (ainfo->offset) {
1331 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1332 arg->opcode = OP_OUTARG_MEMBASE;
1333 ai->reg = ainfo->reg;
1334 ai->size = sizeof (gpointer);
1335 ai->offset = ainfo->offset;
1336 arg->backend.data = ai;
1338 arg->backend.reg3 = ainfo->reg;
1339 call->used_iregs |= 1 << ainfo->reg;
1341 } else if (ainfo->regtype == RegTypeStructByVal) {
1343 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1344 /* mark the used regs */
1345 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1346 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1348 arg->opcode = OP_OUTARG_VT;
1349 ai->reg = ainfo->reg;
1350 ai->size = ainfo->size;
1351 ai->vtsize = ainfo->vtsize;
1352 ai->offset = ainfo->offset;
1353 arg->backend.data = ai;
1354 } else if (ainfo->regtype == RegTypeBase) {
1355 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1356 arg->opcode = OP_OUTARG_MEMBASE;
1357 ai->reg = ainfo->reg;
1358 ai->size = ainfo->size;
1359 ai->offset = ainfo->offset;
1360 arg->backend.data = ai;
1361 } else if (ainfo->regtype == RegTypeFP) {
1362 arg->opcode = OP_OUTARG_R8;
1363 arg->backend.reg3 = ainfo->reg;
1364 call->used_fregs |= 1 << ainfo->reg;
1365 if (ainfo->size == 4) {
1366 arg->opcode = OP_OUTARG_R8;
1367 /* we reduce the precision */
1369 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1370 conv->inst_left = arg->inst_left;
1371 arg->inst_left = conv;*/
1374 g_assert_not_reached ();
1379 * Reverse the call->out_args list.
1382 MonoInst *prev = NULL, *list = call->out_args, *next;
1389 call->out_args = prev;
1392 call->stack_usage = cinfo->stack_usage;
1393 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1394 cfg->flags |= MONO_CFG_HAS_CALLS;
1396 * should set more info in call, such as the stack space
1397 * used by the args that needs to be added back to esp
1405 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1407 int sig_reg = mono_alloc_ireg (cfg);
1409 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1411 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1415 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1418 MonoMethodSignature *sig;
1422 sig = call->signature;
1423 n = sig->param_count + sig->hasthis;
1425 cinfo = calculate_sizes (sig, sig->pinvoke);
1427 for (i = 0; i < n; ++i) {
1428 ArgInfo *ainfo = cinfo->args + i;
1431 if (i >= sig->hasthis)
1432 t = sig->params [i - sig->hasthis];
1434 t = &mono_defaults.int_class->byval_arg;
1435 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1437 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1438 emit_sig_cookie (cfg, call, cinfo);
1440 in = call->args [i];
1442 if (ainfo->regtype == RegTypeGeneral) {
1443 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1444 MONO_INST_NEW (cfg, ins, OP_MOVE);
1445 ins->dreg = mono_alloc_ireg (cfg);
1446 ins->sreg1 = in->dreg + 1;
1447 MONO_ADD_INS (cfg->cbb, ins);
1448 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1450 MONO_INST_NEW (cfg, ins, OP_MOVE);
1451 ins->dreg = mono_alloc_ireg (cfg);
1452 ins->sreg1 = in->dreg + 2;
1453 MONO_ADD_INS (cfg->cbb, ins);
1454 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1456 MONO_INST_NEW (cfg, ins, OP_MOVE);
1457 ins->dreg = mono_alloc_ireg (cfg);
1458 ins->sreg1 = in->dreg;
1459 MONO_ADD_INS (cfg->cbb, ins);
1461 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1463 } else if (ainfo->regtype == RegTypeStructByAddr) {
1464 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1465 ins->opcode = OP_OUTARG_VT;
1466 ins->sreg1 = in->dreg;
1467 ins->klass = in->klass;
1468 ins->inst_p0 = call;
1469 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1470 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1471 MONO_ADD_INS (cfg->cbb, ins);
1472 } else if (ainfo->regtype == RegTypeStructByVal) {
1473 /* this is further handled in mono_arch_emit_outarg_vt () */
1474 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1475 ins->opcode = OP_OUTARG_VT;
1476 ins->sreg1 = in->dreg;
1477 ins->klass = in->klass;
1478 ins->inst_p0 = call;
1479 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1480 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1481 MONO_ADD_INS (cfg->cbb, ins);
1482 } else if (ainfo->regtype == RegTypeBase) {
1483 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1484 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1485 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1486 if (t->type == MONO_TYPE_R8)
1487 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1489 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1491 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1493 } else if (ainfo->regtype == RegTypeFP) {
1494 if (t->type == MONO_TYPE_VALUETYPE) {
1495 /* this is further handled in mono_arch_emit_outarg_vt () */
1496 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1497 ins->opcode = OP_OUTARG_VT;
1498 ins->sreg1 = in->dreg;
1499 ins->klass = in->klass;
1500 ins->inst_p0 = call;
1501 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1502 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1503 MONO_ADD_INS (cfg->cbb, ins);
1505 cfg->flags |= MONO_CFG_HAS_FPOUT;
1507 int dreg = mono_alloc_freg (cfg);
1509 if (ainfo->size == 4) {
1510 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1512 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1514 ins->sreg1 = in->dreg;
1515 MONO_ADD_INS (cfg->cbb, ins);
1518 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1519 cfg->flags |= MONO_CFG_HAS_FPOUT;
1522 g_assert_not_reached ();
1526 /* Emit the signature cookie in the case that there is no
1527 additional argument */
1528 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1529 emit_sig_cookie (cfg, call, cinfo);
1531 if (cinfo->struct_ret) {
1534 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1535 vtarg->sreg1 = call->vret_var->dreg;
1536 vtarg->dreg = mono_alloc_preg (cfg);
1537 MONO_ADD_INS (cfg->cbb, vtarg);
1539 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1542 call->stack_usage = cinfo->stack_usage;
1543 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1544 cfg->flags |= MONO_CFG_HAS_CALLS;
1550 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1552 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1553 ArgInfo *ainfo = ins->inst_p1;
1554 int ovf_size = ainfo->vtsize;
1555 int doffset = ainfo->offset;
1556 int i, soffset, dreg;
1558 if (ainfo->regtype == RegTypeStructByVal) {
1563 * Darwin pinvokes needs some special handling for 1
1564 * and 2 byte arguments
1566 g_assert (ins->klass);
1567 if (call->signature->pinvoke)
1568 size = mono_class_native_size (ins->klass, NULL);
1569 if (size == 2 || size == 1) {
1570 int tmpr = mono_alloc_ireg (cfg);
1572 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1574 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1575 dreg = mono_alloc_ireg (cfg);
1576 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1577 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1580 for (i = 0; i < ainfo->size; ++i) {
1581 dreg = mono_alloc_ireg (cfg);
1582 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1583 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1584 soffset += sizeof (gpointer);
1587 mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1588 } else if (ainfo->regtype == RegTypeFP) {
1589 int tmpr = mono_alloc_freg (cfg);
1590 if (ainfo->size == 4)
1591 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1593 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1594 dreg = mono_alloc_freg (cfg);
1595 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1596 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1598 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1602 /* FIXME: alignment? */
1603 if (call->signature->pinvoke) {
1604 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1605 vtcopy->backend.is_pinvoke = 1;
1607 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1610 g_assert (ovf_size > 0);
1612 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1613 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1616 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1618 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1623 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1625 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1626 mono_method_signature (method)->ret);
1629 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1632 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1633 ins->sreg1 = val->dreg + 1;
1634 ins->sreg2 = val->dreg + 2;
1635 MONO_ADD_INS (cfg->cbb, ins);
1638 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1639 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1643 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1646 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1648 mono_arch_is_inst_imm (gint64 imm)
1654 * Allow tracing to work with this interface (with an optional argument)
1658 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1662 ppc_load (code, ppc_r3, cfg->method);
1663 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1664 ppc_load (code, ppc_r0, func);
1665 ppc_mtlr (code, ppc_r0);
1679 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1682 int save_mode = SAVE_NONE;
1684 MonoMethod *method = cfg->method;
1685 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1686 mono_method_signature (method)->ret)->type;
1687 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1691 offset = code - cfg->native_code;
1692 /* we need about 16 instructions */
1693 if (offset > (cfg->code_size - 16 * 4)) {
1694 cfg->code_size *= 2;
1695 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1696 code = cfg->native_code + offset;
1700 case MONO_TYPE_VOID:
1701 /* special case string .ctor icall */
1702 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1703 save_mode = SAVE_ONE;
1705 save_mode = SAVE_NONE;
1709 save_mode = SAVE_TWO;
1713 save_mode = SAVE_FP;
1715 case MONO_TYPE_VALUETYPE:
1716 save_mode = SAVE_STRUCT;
1719 save_mode = SAVE_ONE;
1723 switch (save_mode) {
1725 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1726 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1727 if (enable_arguments) {
1728 ppc_mr (code, ppc_r5, ppc_r4);
1729 ppc_mr (code, ppc_r4, ppc_r3);
1733 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1734 if (enable_arguments) {
1735 ppc_mr (code, ppc_r4, ppc_r3);
1739 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1740 if (enable_arguments) {
1741 /* FIXME: what reg? */
1742 ppc_fmr (code, ppc_f3, ppc_f1);
1743 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1744 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1748 if (enable_arguments) {
1749 /* FIXME: get the actual address */
1750 ppc_mr (code, ppc_r4, ppc_r3);
1758 ppc_load (code, ppc_r3, cfg->method);
1759 ppc_load (code, ppc_r0, func);
1760 ppc_mtlr (code, ppc_r0);
1763 switch (save_mode) {
1765 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1766 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1769 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1772 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1782 * Conditional branches have a small offset, so if it is likely overflowed,
1783 * we do a branch to the end of the method (uncond branches have much larger
1784 * offsets) where we perform the conditional and jump back unconditionally.
1785 * It's slightly slower, since we add two uncond branches, but it's very simple
1786 * with the current patch implementation and such large methods are likely not
1787 * going to be perf critical anyway.
1792 const char *exception;
1799 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1800 if (ins->flags & MONO_INST_BRLABEL) { \
1801 if (0 && ins->inst_i0->inst_c0) { \
1802 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1804 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1805 ppc_bc (code, (b0), (b1), 0); \
1808 if (0 && ins->inst_true_bb->native_offset) { \
1809 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1811 int br_disp = ins->inst_true_bb->max_offset - offset; \
1812 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1813 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1814 ovfj->data.bb = ins->inst_true_bb; \
1815 ovfj->ip_offset = 0; \
1816 ovfj->b0_cond = (b0); \
1817 ovfj->b1_cond = (b1); \
1818 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1821 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1822 ppc_bc (code, (b0), (b1), 0); \
1827 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1829 /* emit an exception if condition is fail
1831 * We assign the extra code used to throw the implicit exceptions
1832 * to cfg->bb_exit as far as the big branch handling is concerned
1834 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1836 int br_disp = cfg->bb_exit->max_offset - offset; \
1837 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1838 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1839 ovfj->data.exception = (exc_name); \
1840 ovfj->ip_offset = code - cfg->native_code; \
1841 ovfj->b0_cond = (b0); \
1842 ovfj->b1_cond = (b1); \
1843 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1845 cfg->bb_exit->max_offset += 24; \
1847 mono_add_patch_info (cfg, code - cfg->native_code, \
1848 MONO_PATCH_INFO_EXC, exc_name); \
1849 ppc_bcl (code, (b0), (b1), 0); \
1853 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1856 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1861 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1863 MonoInst *ins, *n, *last_ins = NULL;
1865 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1866 switch (ins->opcode) {
1868 /* remove unnecessary multiplication with 1 */
1869 if (ins->inst_imm == 1) {
1870 if (ins->dreg != ins->sreg1) {
1871 ins->opcode = OP_MOVE;
1873 MONO_DELETE_INS (bb, ins);
1877 int power2 = mono_is_power_of_two (ins->inst_imm);
1879 ins->opcode = OP_SHL_IMM;
1880 ins->inst_imm = power2;
1884 case OP_LOAD_MEMBASE:
1885 case OP_LOADI4_MEMBASE:
1887 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1888 * OP_LOAD_MEMBASE offset(basereg), reg
1890 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1891 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1892 ins->inst_basereg == last_ins->inst_destbasereg &&
1893 ins->inst_offset == last_ins->inst_offset) {
1894 if (ins->dreg == last_ins->sreg1) {
1895 MONO_DELETE_INS (bb, ins);
1898 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1899 ins->opcode = OP_MOVE;
1900 ins->sreg1 = last_ins->sreg1;
1904 * Note: reg1 must be different from the basereg in the second load
1905 * OP_LOAD_MEMBASE offset(basereg), reg1
1906 * OP_LOAD_MEMBASE offset(basereg), reg2
1908 * OP_LOAD_MEMBASE offset(basereg), reg1
1909 * OP_MOVE reg1, reg2
1911 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1912 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1913 ins->inst_basereg != last_ins->dreg &&
1914 ins->inst_basereg == last_ins->inst_basereg &&
1915 ins->inst_offset == last_ins->inst_offset) {
1917 if (ins->dreg == last_ins->dreg) {
1918 MONO_DELETE_INS (bb, ins);
1921 ins->opcode = OP_MOVE;
1922 ins->sreg1 = last_ins->dreg;
1925 //g_assert_not_reached ();
1929 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1930 * OP_LOAD_MEMBASE offset(basereg), reg
1932 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1933 * OP_ICONST reg, imm
1935 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1936 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1937 ins->inst_basereg == last_ins->inst_destbasereg &&
1938 ins->inst_offset == last_ins->inst_offset) {
1939 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1940 ins->opcode = OP_ICONST;
1941 ins->inst_c0 = last_ins->inst_imm;
1942 g_assert_not_reached (); // check this rule
1946 case OP_LOADU1_MEMBASE:
1947 case OP_LOADI1_MEMBASE:
1948 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1949 ins->inst_basereg == last_ins->inst_destbasereg &&
1950 ins->inst_offset == last_ins->inst_offset) {
1951 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1952 ins->sreg1 = last_ins->sreg1;
1955 case OP_LOADU2_MEMBASE:
1956 case OP_LOADI2_MEMBASE:
1957 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1958 ins->inst_basereg == last_ins->inst_destbasereg &&
1959 ins->inst_offset == last_ins->inst_offset) {
1960 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1961 ins->sreg1 = last_ins->sreg1;
1965 ins->opcode = OP_MOVE;
1969 if (ins->dreg == ins->sreg1) {
1970 MONO_DELETE_INS (bb, ins);
1974 * OP_MOVE sreg, dreg
1975 * OP_MOVE dreg, sreg
1977 if (last_ins && last_ins->opcode == OP_MOVE &&
1978 ins->sreg1 == last_ins->dreg &&
1979 ins->dreg == last_ins->sreg1) {
1980 MONO_DELETE_INS (bb, ins);
1988 bb->last_ins = last_ins;
1992 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1994 g_assert (cfg->new_ir);
1996 switch (ins->opcode) {
1997 case OP_ICONV_TO_R_UN: {
1998 static const guint64 adjust_val = 0x4330000000000000ULL;
1999 int msw_reg = mono_alloc_ireg (cfg);
2000 int adj_reg = mono_alloc_freg (cfg);
2001 int tmp_reg = mono_alloc_freg (cfg);
2002 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2003 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2004 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
2005 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2006 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2007 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2008 ins->opcode = OP_NOP;
2011 case OP_ICONV_TO_R4:
2012 case OP_ICONV_TO_R8: {
2013 /* FIXME: change precision for CEE_CONV_R4 */
2014 static const guint64 adjust_val = 0x4330000080000000ULL;
2015 int msw_reg = mono_alloc_ireg (cfg);
2016 int xored = mono_alloc_ireg (cfg);
2017 int adj_reg = mono_alloc_freg (cfg);
2018 int tmp_reg = mono_alloc_freg (cfg);
2019 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2020 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2021 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2022 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2023 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2024 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2025 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2026 if (ins->opcode == OP_ICONV_TO_R4)
2027 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2028 ins->opcode = OP_NOP;
2032 int msw_reg = mono_alloc_ireg (cfg);
2033 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2034 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2035 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2036 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2037 ins->opcode = OP_NOP;
2044 * the branch_b0_table should maintain the order of these
2058 branch_b0_table [] = {
2073 branch_b1_table [] = {
2087 #define NEW_INS(cfg,dest,op) do { \
2088 MONO_INST_NEW((cfg), (dest), (op)); \
2089 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2093 map_to_reg_reg_op (int op)
2102 case OP_COMPARE_IMM:
2104 case OP_ICOMPARE_IMM:
2120 case OP_LOAD_MEMBASE:
2121 return OP_LOAD_MEMINDEX;
2122 case OP_LOADI4_MEMBASE:
2123 return OP_LOADI4_MEMINDEX;
2124 case OP_LOADU4_MEMBASE:
2125 return OP_LOADU4_MEMINDEX;
2126 case OP_LOADU1_MEMBASE:
2127 return OP_LOADU1_MEMINDEX;
2128 case OP_LOADI2_MEMBASE:
2129 return OP_LOADI2_MEMINDEX;
2130 case OP_LOADU2_MEMBASE:
2131 return OP_LOADU2_MEMINDEX;
2132 case OP_LOADI1_MEMBASE:
2133 return OP_LOADI1_MEMINDEX;
2134 case OP_LOADR4_MEMBASE:
2135 return OP_LOADR4_MEMINDEX;
2136 case OP_LOADR8_MEMBASE:
2137 return OP_LOADR8_MEMINDEX;
2138 case OP_STOREI1_MEMBASE_REG:
2139 return OP_STOREI1_MEMINDEX;
2140 case OP_STOREI2_MEMBASE_REG:
2141 return OP_STOREI2_MEMINDEX;
2142 case OP_STOREI4_MEMBASE_REG:
2143 return OP_STOREI4_MEMINDEX;
2144 case OP_STORE_MEMBASE_REG:
2145 return OP_STORE_MEMINDEX;
2146 case OP_STORER4_MEMBASE_REG:
2147 return OP_STORER4_MEMINDEX;
2148 case OP_STORER8_MEMBASE_REG:
2149 return OP_STORER8_MEMINDEX;
2150 case OP_STORE_MEMBASE_IMM:
2151 return OP_STORE_MEMBASE_REG;
2152 case OP_STOREI1_MEMBASE_IMM:
2153 return OP_STOREI1_MEMBASE_REG;
2154 case OP_STOREI2_MEMBASE_IMM:
2155 return OP_STOREI2_MEMBASE_REG;
2156 case OP_STOREI4_MEMBASE_IMM:
2157 return OP_STOREI4_MEMBASE_REG;
2159 return mono_op_imm_to_op (op);
2162 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2164 #define compare_opcode_is_unsigned(opcode) \
2165 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2166 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2167 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2168 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2169 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2171 * Remove from the instruction list the instructions that can't be
2172 * represented with very simple instructions with no register
2176 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2178 MonoInst *ins, *next, *temp, *last_ins = NULL;
2181 /* setup the virtual reg allocator */
2182 if (bb->max_vreg > cfg->rs->next_vreg)
2183 cfg->rs->next_vreg = bb->max_vreg;
2185 MONO_BB_FOR_EACH_INS (bb, ins) {
2187 switch (ins->opcode) {
2188 case OP_IDIV_UN_IMM:
2191 case OP_IREM_UN_IMM:
2192 NEW_INS (cfg, temp, OP_ICONST);
2193 temp->inst_c0 = ins->inst_imm;
2194 temp->dreg = mono_regstate_next_int (cfg->rs);
2195 ins->sreg2 = temp->dreg;
2196 if (ins->opcode == OP_IDIV_IMM)
2197 ins->opcode = OP_IDIV;
2198 else if (ins->opcode == OP_IREM_IMM)
2199 ins->opcode = OP_IREM;
2200 else if (ins->opcode == OP_IDIV_UN_IMM)
2201 ins->opcode = OP_IDIV_UN;
2202 else if (ins->opcode == OP_IREM_UN_IMM)
2203 ins->opcode = OP_IREM_UN;
2205 /* handle rem separately */
2210 /* we change a rem dest, src1, src2 to
2211 * div temp1, src1, src2
2212 * mul temp2, temp1, src2
2213 * sub dest, src1, temp2
2215 NEW_INS (cfg, mul, OP_IMUL);
2216 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2217 temp->sreg1 = ins->sreg1;
2218 temp->sreg2 = ins->sreg2;
2219 temp->dreg = mono_regstate_next_int (cfg->rs);
2220 mul->sreg1 = temp->dreg;
2221 mul->sreg2 = ins->sreg2;
2222 mul->dreg = mono_regstate_next_int (cfg->rs);
2223 ins->opcode = OP_ISUB;
2224 ins->sreg2 = mul->dreg;
2230 if (!ppc_is_imm16 (ins->inst_imm)) {
2231 NEW_INS (cfg, temp, OP_ICONST);
2232 temp->inst_c0 = ins->inst_imm;
2233 temp->dreg = mono_regstate_next_int (cfg->rs);
2234 ins->sreg2 = temp->dreg;
2235 ins->opcode = map_to_reg_reg_op (ins->opcode);
2240 if (!ppc_is_imm16 (-ins->inst_imm)) {
2241 NEW_INS (cfg, temp, OP_ICONST);
2242 temp->inst_c0 = ins->inst_imm;
2243 temp->dreg = mono_regstate_next_int (cfg->rs);
2244 ins->sreg2 = temp->dreg;
2245 ins->opcode = map_to_reg_reg_op (ins->opcode);
2254 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2255 NEW_INS (cfg, temp, OP_ICONST);
2256 temp->inst_c0 = ins->inst_imm;
2257 temp->dreg = mono_regstate_next_int (cfg->rs);
2258 ins->sreg2 = temp->dreg;
2259 ins->opcode = map_to_reg_reg_op (ins->opcode);
2267 NEW_INS (cfg, temp, OP_ICONST);
2268 temp->inst_c0 = ins->inst_imm;
2269 temp->dreg = mono_regstate_next_int (cfg->rs);
2270 ins->sreg2 = temp->dreg;
2271 ins->opcode = map_to_reg_reg_op (ins->opcode);
2273 case OP_COMPARE_IMM:
2274 case OP_ICOMPARE_IMM:
2276 /* Branch opts can eliminate the branch */
2277 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2278 ins->opcode = OP_NOP;
2282 if (compare_opcode_is_unsigned (next->opcode)) {
2283 if (!ppc_is_uimm16 (ins->inst_imm)) {
2284 NEW_INS (cfg, temp, OP_ICONST);
2285 temp->inst_c0 = ins->inst_imm;
2286 temp->dreg = mono_regstate_next_int (cfg->rs);
2287 ins->sreg2 = temp->dreg;
2288 ins->opcode = map_to_reg_reg_op (ins->opcode);
2291 if (!ppc_is_imm16 (ins->inst_imm)) {
2292 NEW_INS (cfg, temp, OP_ICONST);
2293 temp->inst_c0 = ins->inst_imm;
2294 temp->dreg = mono_regstate_next_int (cfg->rs);
2295 ins->sreg2 = temp->dreg;
2296 ins->opcode = map_to_reg_reg_op (ins->opcode);
2302 if (ins->inst_imm == 1) {
2303 ins->opcode = OP_MOVE;
2306 if (ins->inst_imm == 0) {
2307 ins->opcode = OP_ICONST;
2311 imm = mono_is_power_of_two (ins->inst_imm);
2313 ins->opcode = OP_SHL_IMM;
2314 ins->inst_imm = imm;
2317 if (!ppc_is_imm16 (ins->inst_imm)) {
2318 NEW_INS (cfg, temp, OP_ICONST);
2319 temp->inst_c0 = ins->inst_imm;
2320 temp->dreg = mono_regstate_next_int (cfg->rs);
2321 ins->sreg2 = temp->dreg;
2322 ins->opcode = map_to_reg_reg_op (ins->opcode);
2325 case OP_LOCALLOC_IMM:
2326 NEW_INS (cfg, temp, OP_ICONST);
2327 temp->inst_c0 = ins->inst_imm;
2328 temp->dreg = mono_regstate_next_int (cfg->rs);
2329 ins->sreg1 = temp->dreg;
2330 ins->opcode = OP_LOCALLOC;
2332 case OP_LOAD_MEMBASE:
2333 case OP_LOADI4_MEMBASE:
2334 case OP_LOADU4_MEMBASE:
2335 case OP_LOADI2_MEMBASE:
2336 case OP_LOADU2_MEMBASE:
2337 case OP_LOADI1_MEMBASE:
2338 case OP_LOADU1_MEMBASE:
2339 case OP_LOADR4_MEMBASE:
2340 case OP_LOADR8_MEMBASE:
2341 case OP_STORE_MEMBASE_REG:
2342 case OP_STOREI4_MEMBASE_REG:
2343 case OP_STOREI2_MEMBASE_REG:
2344 case OP_STOREI1_MEMBASE_REG:
2345 case OP_STORER4_MEMBASE_REG:
2346 case OP_STORER8_MEMBASE_REG:
2347 /* we can do two things: load the immed in a register
2348 * and use an indexed load, or see if the immed can be
2349 * represented as an ad_imm + a load with a smaller offset
2350 * that fits. We just do the first for now, optimize later.
2352 if (ppc_is_imm16 (ins->inst_offset))
2354 NEW_INS (cfg, temp, OP_ICONST);
2355 temp->inst_c0 = ins->inst_offset;
2356 temp->dreg = mono_regstate_next_int (cfg->rs);
2357 ins->sreg2 = temp->dreg;
2358 ins->opcode = map_to_reg_reg_op (ins->opcode);
2360 case OP_STORE_MEMBASE_IMM:
2361 case OP_STOREI1_MEMBASE_IMM:
2362 case OP_STOREI2_MEMBASE_IMM:
2363 case OP_STOREI4_MEMBASE_IMM:
2364 NEW_INS (cfg, temp, OP_ICONST);
2365 temp->inst_c0 = ins->inst_imm;
2366 temp->dreg = mono_regstate_next_int (cfg->rs);
2367 ins->sreg1 = temp->dreg;
2368 ins->opcode = map_to_reg_reg_op (ins->opcode);
2370 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2373 NEW_INS (cfg, temp, OP_ICONST);
2374 temp->inst_c0 = (guint32)ins->inst_p0;
2375 temp->dreg = mono_regstate_next_int (cfg->rs);
2376 ins->inst_basereg = temp->dreg;
2377 ins->inst_offset = 0;
2378 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2380 /* make it handle the possibly big ins->inst_offset
2381 * later optimize to use lis + load_membase
2387 bb->last_ins = last_ins;
2388 bb->max_vreg = cfg->rs->next_vreg;
2393 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2395 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2396 ppc_fctiwz (code, ppc_f0, sreg);
2397 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2398 ppc_lwz (code, dreg, -4, ppc_sp);
2401 ppc_andid (code, dreg, dreg, 0xff);
2403 ppc_andid (code, dreg, dreg, 0xffff);
2406 ppc_extsb (code, dreg, dreg);
2408 ppc_extsh (code, dreg, dreg);
2415 const guchar *target;
2420 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2423 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2424 PatchData *pdata = (PatchData*)user_data;
2425 guchar *code = data;
2426 guint32 *thunks = data;
2427 guint32 *endthunks = (guint32*)(code + bsize);
2431 int difflow, diffhigh;
2433 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2434 difflow = (char*)pdata->code - (char*)thunks;
2435 diffhigh = (char*)pdata->code - (char*)endthunks;
2436 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2439 templ = (guchar*)load;
2440 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2441 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2443 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2444 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2445 while (thunks < endthunks) {
2446 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2447 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2448 ppc_patch (pdata->code, (guchar*)thunks);
2449 mono_arch_flush_icache (pdata->code, 4);
2452 static int num_thunks = 0;
2454 if ((num_thunks % 20) == 0)
2455 g_print ("num_thunks lookup: %d\n", num_thunks);
2458 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2459 /* found a free slot instead: emit thunk */
2460 code = (guchar*)thunks;
2461 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2462 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2463 ppc_mtctr (code, ppc_r0);
2464 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2465 mono_arch_flush_icache ((guchar*)thunks, 16);
2467 ppc_patch (pdata->code, (guchar*)thunks);
2468 mono_arch_flush_icache (pdata->code, 4);
2471 static int num_thunks = 0;
2473 if ((num_thunks % 20) == 0)
2474 g_print ("num_thunks: %d\n", num_thunks);
2478 /* skip 16 bytes, the size of the thunk */
2482 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2488 handle_thunk (int absolute, guchar *code, const guchar *target) {
2489 MonoDomain *domain = mono_domain_get ();
2493 pdata.target = target;
2494 pdata.absolute = absolute;
2497 mono_domain_lock (domain);
2498 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2501 /* this uses the first available slot */
2503 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2505 mono_domain_unlock (domain);
2507 if (pdata.found != 1)
2508 g_print ("thunk failed for %p from %p\n", target, code);
2509 g_assert (pdata.found == 1);
2513 ppc_patch (guchar *code, const guchar *target)
2515 guint32 ins = *(guint32*)code;
2516 guint32 prim = ins >> 26;
2519 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2521 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2522 gint diff = target - code;
2524 if (diff <= 33554431){
2525 ins = (18 << 26) | (diff) | (ins & 1);
2526 *(guint32*)code = ins;
2530 /* diff between 0 and -33554432 */
2531 if (diff >= -33554432){
2532 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2533 *(guint32*)code = ins;
2538 if ((glong)target >= 0){
2539 if ((glong)target <= 33554431){
2540 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2541 *(guint32*)code = ins;
2545 if ((glong)target >= -33554432){
2546 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2547 *(guint32*)code = ins;
2552 handle_thunk (TRUE, code, target);
2555 g_assert_not_reached ();
2562 guint32 li = (guint32)target;
2563 ins = (ins & 0xffff0000) | (ins & 3);
2564 ovf = li & 0xffff0000;
2565 if (ovf != 0 && ovf != 0xffff0000)
2566 g_assert_not_reached ();
2569 // FIXME: assert the top bits of li are 0
2571 gint diff = target - code;
2572 ins = (ins & 0xffff0000) | (ins & 3);
2573 ovf = diff & 0xffff0000;
2574 if (ovf != 0 && ovf != 0xffff0000)
2575 g_assert_not_reached ();
2579 *(guint32*)code = ins;
2583 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2585 /* the trampoline code will try to patch the blrl, blr, bcctr */
2586 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2589 /* this is the lis/ori/mtlr/blrl sequence */
2590 seq = (guint32*)code;
2591 g_assert ((seq [0] >> 26) == 15);
2592 g_assert ((seq [1] >> 26) == 24);
2593 g_assert ((seq [2] >> 26) == 31);
2594 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2595 /* FIXME: make this thread safe */
2596 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2597 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2598 mono_arch_flush_icache (code - 8, 8);
2600 g_assert_not_reached ();
2602 // g_print ("patched with 0x%08x\n", ins);
2606 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2608 switch (ins->opcode) {
2611 case OP_FCALL_MEMBASE:
2612 if (ins->dreg != ppc_f1)
2613 ppc_fmr (code, ins->dreg, ppc_f1);
2621 * emit_load_volatile_arguments:
2623 * Load volatile arguments from the stack to the original input registers.
2624 * Required before a tail call.
2627 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2629 MonoMethod *method = cfg->method;
2630 MonoMethodSignature *sig;
2634 int struct_index = 0;
2636 /* FIXME: Generate intermediate code instead */
2638 sig = mono_method_signature (method);
2640 /* This is the opposite of the code in emit_prolog */
2644 cinfo = calculate_sizes (sig, sig->pinvoke);
2646 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2647 ArgInfo *ainfo = &cinfo->ret;
2648 inst = cfg->vret_addr;
2649 g_assert (ppc_is_imm16 (inst->inst_offset));
2650 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2652 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2653 ArgInfo *ainfo = cinfo->args + i;
2654 inst = cfg->args [pos];
2656 g_assert (inst->opcode != OP_REGVAR);
2657 g_assert (ppc_is_imm16 (inst->inst_offset));
2659 switch (ainfo->regtype) {
2660 case RegTypeGeneral:
2661 switch (ainfo->size) {
2663 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2666 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2669 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2675 switch (ainfo->size) {
2677 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2680 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2683 g_assert_not_reached ();
2691 case RegTypeStructByVal: {
2699 * Darwin pinvokes needs some special handling
2700 * for 1 and 2 byte arguments
2702 if (method->signature->pinvoke)
2703 size = mono_class_native_size (inst->klass, NULL);
2704 if (size == 1 || size == 2) {
2709 for (i = 0; i < ainfo->size; ++i) {
2710 ppc_lwz (code, ainfo->reg + i,
2711 inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
2716 case RegTypeStructByAddr: {
2717 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2719 g_assert (ppc_is_imm16 (addr->inst_offset));
2720 g_assert (!ainfo->offset);
2721 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2728 g_assert_not_reached ();
2740 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2742 MonoInst *ins, *next;
2745 guint8 *code = cfg->native_code + cfg->code_len;
2746 MonoInst *last_ins = NULL;
2747 guint last_offset = 0;
2750 /* we don't align basic blocks of loops on ppc */
2752 if (cfg->verbose_level > 2)
2753 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2755 cpos = bb->max_offset;
2757 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2758 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2759 //g_assert (!mono_compile_aot);
2762 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2763 /* this is not thread save, but good enough */
2764 /* fixme: howto handle overflows? */
2765 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2768 MONO_BB_FOR_EACH_INS (bb, ins) {
2769 offset = code - cfg->native_code;
2771 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2773 if (offset > (cfg->code_size - max_len - 16)) {
2774 cfg->code_size *= 2;
2775 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2776 code = cfg->native_code + offset;
2778 // if (ins->cil_code)
2779 // g_print ("cil code\n");
2780 mono_debug_record_line_number (cfg, ins, offset);
2782 switch (ins->opcode) {
2783 case OP_RELAXED_NOP:
2786 case OP_DUMMY_STORE:
2787 case OP_NOT_REACHED:
2791 emit_tls_access (code, ins->dreg, ins->inst_offset);
2794 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2795 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2796 ppc_mr (code, ppc_r4, ppc_r0);
2799 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2800 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2801 ppc_mr (code, ppc_r4, ppc_r0);
2803 case OP_MEMORY_BARRIER:
2806 case OP_STOREI1_MEMBASE_REG:
2807 if (ppc_is_imm16 (ins->inst_offset)) {
2808 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2810 ppc_load (code, ppc_r0, ins->inst_offset);
2811 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2814 case OP_STOREI2_MEMBASE_REG:
2815 if (ppc_is_imm16 (ins->inst_offset)) {
2816 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2818 ppc_load (code, ppc_r0, ins->inst_offset);
2819 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2822 case OP_STORE_MEMBASE_REG:
2823 case OP_STOREI4_MEMBASE_REG:
2824 if (ppc_is_imm16 (ins->inst_offset)) {
2825 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2827 ppc_load (code, ppc_r0, ins->inst_offset);
2828 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2831 case OP_STOREI1_MEMINDEX:
2832 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2834 case OP_STOREI2_MEMINDEX:
2835 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2837 case OP_STORE_MEMINDEX:
2838 case OP_STOREI4_MEMINDEX:
2839 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2842 g_assert_not_reached ();
2844 case OP_LOAD_MEMBASE:
2845 case OP_LOADI4_MEMBASE:
2846 case OP_LOADU4_MEMBASE:
2847 if (ppc_is_imm16 (ins->inst_offset)) {
2848 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2850 ppc_load (code, ppc_r0, ins->inst_offset);
2851 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2854 case OP_LOADI1_MEMBASE:
2855 case OP_LOADU1_MEMBASE:
2856 if (ppc_is_imm16 (ins->inst_offset)) {
2857 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2859 ppc_load (code, ppc_r0, ins->inst_offset);
2860 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2862 if (ins->opcode == OP_LOADI1_MEMBASE)
2863 ppc_extsb (code, ins->dreg, ins->dreg);
2865 case OP_LOADU2_MEMBASE:
2866 if (ppc_is_imm16 (ins->inst_offset)) {
2867 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2869 ppc_load (code, ppc_r0, ins->inst_offset);
2870 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2873 case OP_LOADI2_MEMBASE:
2874 if (ppc_is_imm16 (ins->inst_offset)) {
2875 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2877 ppc_load (code, ppc_r0, ins->inst_offset);
2878 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2881 case OP_LOAD_MEMINDEX:
2882 case OP_LOADI4_MEMINDEX:
2883 case OP_LOADU4_MEMINDEX:
2884 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2886 case OP_LOADU2_MEMINDEX:
2887 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2889 case OP_LOADI2_MEMINDEX:
2890 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2892 case OP_LOADU1_MEMINDEX:
2893 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2895 case OP_LOADI1_MEMINDEX:
2896 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2897 ppc_extsb (code, ins->dreg, ins->dreg);
2899 case OP_ICONV_TO_I1:
2900 ppc_extsb (code, ins->dreg, ins->sreg1);
2902 case OP_ICONV_TO_I2:
2903 ppc_extsh (code, ins->dreg, ins->sreg1);
2905 case OP_ICONV_TO_U1:
2906 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2908 case OP_ICONV_TO_U2:
2909 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2914 if (next && compare_opcode_is_unsigned (next->opcode))
2915 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2917 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2919 case OP_COMPARE_IMM:
2920 case OP_ICOMPARE_IMM:
2922 if (next && compare_opcode_is_unsigned (next->opcode)) {
2923 if (ppc_is_uimm16 (ins->inst_imm)) {
2924 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2926 g_assert_not_reached ();
2929 if (ppc_is_imm16 (ins->inst_imm)) {
2930 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2932 g_assert_not_reached ();
2941 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2944 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2948 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2951 if (ppc_is_imm16 (ins->inst_imm)) {
2952 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2954 g_assert_not_reached ();
2959 if (ppc_is_imm16 (ins->inst_imm)) {
2960 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2962 g_assert_not_reached ();
2966 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2968 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2969 ppc_mfspr (code, ppc_r0, ppc_xer);
2970 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2971 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2973 case OP_IADD_OVF_UN:
2974 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2976 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2977 ppc_mfspr (code, ppc_r0, ppc_xer);
2978 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2979 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2982 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2984 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2985 ppc_mfspr (code, ppc_r0, ppc_xer);
2986 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2987 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2989 case OP_ISUB_OVF_UN:
2990 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2992 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2993 ppc_mfspr (code, ppc_r0, ppc_xer);
2994 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2995 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2997 case OP_ADD_OVF_CARRY:
2998 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3000 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3001 ppc_mfspr (code, ppc_r0, ppc_xer);
3002 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3003 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3005 case OP_ADD_OVF_UN_CARRY:
3006 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3008 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3009 ppc_mfspr (code, ppc_r0, ppc_xer);
3010 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3011 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3013 case OP_SUB_OVF_CARRY:
3014 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3016 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3017 ppc_mfspr (code, ppc_r0, ppc_xer);
3018 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3019 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3021 case OP_SUB_OVF_UN_CARRY:
3022 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3024 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3025 ppc_mfspr (code, ppc_r0, ppc_xer);
3026 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3027 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3031 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3034 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3038 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3042 // we add the negated value
3043 if (ppc_is_imm16 (-ins->inst_imm))
3044 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3046 g_assert_not_reached ();
3050 g_assert (ppc_is_imm16 (ins->inst_imm));
3051 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3054 ppc_subfze (code, ins->dreg, ins->sreg1);
3057 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3058 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3062 if (!(ins->inst_imm & 0xffff0000)) {
3063 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3064 } else if (!(ins->inst_imm & 0xffff)) {
3065 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3067 g_assert_not_reached ();
3071 guint8 *divisor_is_m1;
3072 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3074 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3075 divisor_is_m1 = code;
3076 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3077 ppc_lis (code, ppc_r0, 0x8000);
3078 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3079 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3080 ppc_patch (divisor_is_m1, code);
3081 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3083 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3084 ppc_mfspr (code, ppc_r0, ppc_xer);
3085 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3086 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3090 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3091 ppc_mfspr (code, ppc_r0, ppc_xer);
3092 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3093 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3099 g_assert_not_reached ();
3101 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3105 if (!(ins->inst_imm & 0xffff0000)) {
3106 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3107 } else if (!(ins->inst_imm & 0xffff)) {
3108 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3110 g_assert_not_reached ();
3114 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3118 if (!(ins->inst_imm & 0xffff0000)) {
3119 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3120 } else if (!(ins->inst_imm & 0xffff)) {
3121 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3123 g_assert_not_reached ();
3127 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3131 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3134 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3138 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3141 case OP_ISHR_UN_IMM:
3143 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3145 ppc_mr (code, ins->dreg, ins->sreg1);
3148 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3151 ppc_not (code, ins->dreg, ins->sreg1);
3154 ppc_neg (code, ins->dreg, ins->sreg1);
3157 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3161 if (ppc_is_imm16 (ins->inst_imm)) {
3162 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3164 g_assert_not_reached ();
3168 /* we annot use mcrxr, since it's not implemented on some processors
3169 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3171 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3172 ppc_mfspr (code, ppc_r0, ppc_xer);
3173 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3174 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3176 case OP_IMUL_OVF_UN:
3177 /* we first multiply to get the high word and compare to 0
3178 * to set the flags, then the result is discarded and then
3179 * we multiply to get the lower * bits result
3181 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3182 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3183 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3184 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3187 ppc_load (code, ins->dreg, ins->inst_c0);
3190 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3191 ppc_lis (code, ins->dreg, 0);
3192 ppc_ori (code, ins->dreg, ins->dreg, 0);
3194 case OP_ICONV_TO_I4:
3195 case OP_ICONV_TO_U4:
3197 ppc_mr (code, ins->dreg, ins->sreg1);
3200 int saved = ins->sreg1;
3201 if (ins->sreg1 == ppc_r3) {
3202 ppc_mr (code, ppc_r0, ins->sreg1);
3205 if (ins->sreg2 != ppc_r3)
3206 ppc_mr (code, ppc_r3, ins->sreg2);
3207 if (saved != ppc_r4)
3208 ppc_mr (code, ppc_r4, saved);
3212 ppc_fmr (code, ins->dreg, ins->sreg1);
3214 case OP_FCONV_TO_R4:
3215 ppc_frsp (code, ins->dreg, ins->sreg1);
3221 * Keep in sync with mono_arch_emit_epilog
3223 g_assert (!cfg->method->save_lmf);
3225 * Note: we can use ppc_r11 here because it is dead anyway:
3226 * we're leaving the method.
3228 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3229 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3230 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3232 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3233 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3235 ppc_mtlr (code, ppc_r0);
3238 code = emit_load_volatile_arguments (cfg, code);
3240 if (ppc_is_imm16 (cfg->stack_usage)) {
3241 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3243 ppc_load (code, ppc_r11, cfg->stack_usage);
3244 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3246 if (!cfg->method->save_lmf) {
3247 /*for (i = 31; i >= 14; --i) {
3248 if (cfg->used_float_regs & (1 << i)) {
3249 pos += sizeof (double);
3250 ppc_lfd (code, i, -pos, cfg->frame_reg);
3253 for (i = 31; i >= 13; --i) {
3254 if (cfg->used_int_regs & (1 << i)) {
3255 pos += sizeof (gulong);
3256 ppc_lwz (code, i, -pos, cfg->frame_reg);
3260 /* FIXME restore from MonoLMF: though this can't happen yet */
3262 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3267 /* ensure ins->sreg1 is not NULL */
3268 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3271 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3272 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3274 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3275 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3277 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3286 call = (MonoCallInst*)ins;
3287 if (ins->flags & MONO_INST_HAS_METHOD)
3288 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3290 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3291 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3292 ppc_lis (code, ppc_r0, 0);
3293 ppc_ori (code, ppc_r0, ppc_r0, 0);
3294 ppc_mtlr (code, ppc_r0);
3299 /* FIXME: this should be handled somewhere else in the new jit */
3300 code = emit_move_return_value (cfg, ins, code);
3306 case OP_VOIDCALL_REG:
3308 ppc_mtlr (code, ins->sreg1);
3310 /* FIXME: this should be handled somewhere else in the new jit */
3311 code = emit_move_return_value (cfg, ins, code);
3313 case OP_FCALL_MEMBASE:
3314 case OP_LCALL_MEMBASE:
3315 case OP_VCALL_MEMBASE:
3316 case OP_VCALL2_MEMBASE:
3317 case OP_VOIDCALL_MEMBASE:
3318 case OP_CALL_MEMBASE:
3319 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3320 ppc_mtlr (code, ppc_r0);
3322 /* FIXME: this should be handled somewhere else in the new jit */
3323 code = emit_move_return_value (cfg, ins, code);
3326 g_assert_not_reached ();
3329 guint8 * zero_loop_jump, * zero_loop_start;
3330 /* keep alignment */
3331 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3332 int area_offset = alloca_waste;
3334 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3335 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3336 /* use ctr to store the number of words to 0 if needed */
3337 if (ins->flags & MONO_INST_INIT) {
3338 /* we zero 4 bytes at a time:
3339 * we add 7 instead of 3 so that we set the counter to
3340 * at least 1, otherwise the bdnz instruction will make
3341 * it negative and iterate billions of times.
3343 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3344 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3345 ppc_mtctr (code, ppc_r0);
3347 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3348 ppc_neg (code, ppc_r11, ppc_r11);
3349 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3351 if (ins->flags & MONO_INST_INIT) {
3352 /* adjust the dest reg by -4 so we can use stwu */
3353 /* we actually adjust -8 because we let the loop
3356 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3357 ppc_li (code, ppc_r11, 0);
3358 zero_loop_start = code;
3359 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3360 zero_loop_jump = code;
3361 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3362 ppc_patch (zero_loop_jump, zero_loop_start);
3364 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3369 ppc_mr (code, ppc_r3, ins->sreg1);
3370 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3371 (gpointer)"mono_arch_throw_exception");
3372 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3373 ppc_lis (code, ppc_r0, 0);
3374 ppc_ori (code, ppc_r0, ppc_r0, 0);
3375 ppc_mtlr (code, ppc_r0);
3384 ppc_mr (code, ppc_r3, ins->sreg1);
3385 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3386 (gpointer)"mono_arch_rethrow_exception");
3387 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3388 ppc_lis (code, ppc_r0, 0);
3389 ppc_ori (code, ppc_r0, ppc_r0, 0);
3390 ppc_mtlr (code, ppc_r0);
3397 case OP_START_HANDLER: {
3398 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3399 ppc_mflr (code, ppc_r0);
3400 if (ppc_is_imm16 (spvar->inst_offset)) {
3401 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3403 ppc_load (code, ppc_r11, spvar->inst_offset);
3404 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3408 case OP_ENDFILTER: {
3409 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3410 if (ins->sreg1 != ppc_r3)
3411 ppc_mr (code, ppc_r3, ins->sreg1);
3412 if (ppc_is_imm16 (spvar->inst_offset)) {
3413 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3415 ppc_load (code, ppc_r11, spvar->inst_offset);
3416 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3418 ppc_mtlr (code, ppc_r0);
3422 case OP_ENDFINALLY: {
3423 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3424 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3425 ppc_mtlr (code, ppc_r0);
3429 case OP_CALL_HANDLER:
3430 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3434 ins->inst_c0 = code - cfg->native_code;
3437 if (ins->flags & MONO_INST_BRLABEL) {
3438 /*if (ins->inst_i0->inst_c0) {
3440 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3442 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3446 /*if (ins->inst_target_bb->native_offset) {
3448 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3450 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3456 ppc_mtctr (code, ins->sreg1);
3457 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3461 ppc_li (code, ins->dreg, 0);
3462 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3463 ppc_li (code, ins->dreg, 1);
3469 ppc_li (code, ins->dreg, 1);
3470 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3471 ppc_li (code, ins->dreg, 0);
3477 ppc_li (code, ins->dreg, 1);
3478 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3479 ppc_li (code, ins->dreg, 0);
3481 case OP_COND_EXC_EQ:
3482 case OP_COND_EXC_NE_UN:
3483 case OP_COND_EXC_LT:
3484 case OP_COND_EXC_LT_UN:
3485 case OP_COND_EXC_GT:
3486 case OP_COND_EXC_GT_UN:
3487 case OP_COND_EXC_GE:
3488 case OP_COND_EXC_GE_UN:
3489 case OP_COND_EXC_LE:
3490 case OP_COND_EXC_LE_UN:
3491 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3493 case OP_COND_EXC_IEQ:
3494 case OP_COND_EXC_INE_UN:
3495 case OP_COND_EXC_ILT:
3496 case OP_COND_EXC_ILT_UN:
3497 case OP_COND_EXC_IGT:
3498 case OP_COND_EXC_IGT_UN:
3499 case OP_COND_EXC_IGE:
3500 case OP_COND_EXC_IGE_UN:
3501 case OP_COND_EXC_ILE:
3502 case OP_COND_EXC_ILE_UN:
3503 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3506 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3508 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3509 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3510 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3512 case OP_COND_EXC_OV:
3513 /*ppc_mcrxr (code, 0);
3514 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3516 case OP_COND_EXC_NC:
3517 case OP_COND_EXC_NO:
3518 g_assert_not_reached ();
3530 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3533 /* floating point opcodes */
3536 g_assert_not_reached ();
3537 case OP_STORER8_MEMBASE_REG:
3538 if (ppc_is_imm16 (ins->inst_offset)) {
3539 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3541 ppc_load (code, ppc_r0, ins->inst_offset);
3542 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3545 case OP_LOADR8_MEMBASE:
3546 if (ppc_is_imm16 (ins->inst_offset)) {
3547 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3549 ppc_load (code, ppc_r0, ins->inst_offset);
3550 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3553 case OP_STORER4_MEMBASE_REG:
3554 ppc_frsp (code, ins->sreg1, ins->sreg1);
3555 if (ppc_is_imm16 (ins->inst_offset)) {
3556 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3558 ppc_load (code, ppc_r0, ins->inst_offset);
3559 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3562 case OP_LOADR4_MEMBASE:
3563 if (ppc_is_imm16 (ins->inst_offset)) {
3564 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3566 ppc_load (code, ppc_r0, ins->inst_offset);
3567 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3570 case OP_LOADR4_MEMINDEX:
3571 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3573 case OP_LOADR8_MEMINDEX:
3574 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3576 case OP_STORER4_MEMINDEX:
3577 ppc_frsp (code, ins->sreg1, ins->sreg1);
3578 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3580 case OP_STORER8_MEMINDEX:
3581 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3584 case CEE_CONV_R4: /* FIXME: change precision */
3586 g_assert_not_reached ();
3587 case OP_FCONV_TO_I1:
3588 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3590 case OP_FCONV_TO_U1:
3591 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3593 case OP_FCONV_TO_I2:
3594 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3596 case OP_FCONV_TO_U2:
3597 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3599 case OP_FCONV_TO_I4:
3601 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3603 case OP_FCONV_TO_U4:
3605 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3607 case OP_FCONV_TO_I8:
3608 case OP_FCONV_TO_U8:
3609 g_assert_not_reached ();
3610 /* Implemented as helper calls */
3612 case OP_LCONV_TO_R_UN:
3613 g_assert_not_reached ();
3614 /* Implemented as helper calls */
3616 case OP_LCONV_TO_OVF_I4_2:
3617 case OP_LCONV_TO_OVF_I: {
3618 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3619 // Check if its negative
3620 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3621 negative_branch = code;
3622 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3623 // Its positive msword == 0
3624 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3625 msword_positive_branch = code;
3626 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3628 ovf_ex_target = code;
3629 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3631 ppc_patch (negative_branch, code);
3632 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3633 msword_negative_branch = code;
3634 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3635 ppc_patch (msword_negative_branch, ovf_ex_target);
3637 ppc_patch (msword_positive_branch, code);
3638 if (ins->dreg != ins->sreg1)
3639 ppc_mr (code, ins->dreg, ins->sreg1);
3643 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3646 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3649 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3652 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3655 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3658 ppc_fneg (code, ins->dreg, ins->sreg1);
3662 g_assert_not_reached ();
3665 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3668 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3669 ppc_li (code, ins->dreg, 0);
3670 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3671 ppc_li (code, ins->dreg, 1);
3674 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3675 ppc_li (code, ins->dreg, 1);
3676 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3677 ppc_li (code, ins->dreg, 0);
3680 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3681 ppc_li (code, ins->dreg, 1);
3682 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3683 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3684 ppc_li (code, ins->dreg, 0);
3687 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3688 ppc_li (code, ins->dreg, 1);
3689 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3690 ppc_li (code, ins->dreg, 0);
3693 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3694 ppc_li (code, ins->dreg, 1);
3695 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3696 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3697 ppc_li (code, ins->dreg, 0);
3700 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3703 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3706 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3707 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3710 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3711 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3714 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3715 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3718 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3719 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3722 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3723 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3726 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3729 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3730 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3733 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3736 g_assert_not_reached ();
3737 case OP_CHECK_FINITE: {
3738 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3739 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3740 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3741 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3744 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3745 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3749 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3750 g_assert_not_reached ();
3753 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3754 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3755 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3756 g_assert_not_reached ();
3762 last_offset = offset;
3765 cfg->code_len = code - cfg->native_code;
3769 mono_arch_register_lowlevel_calls (void)
3773 #define patch_lis_ori(ip,val) do {\
3774 guint16 *__lis_ori = (guint16*)(ip); \
3775 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3776 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3780 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3782 MonoJumpInfo *patch_info;
3784 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3785 unsigned char *ip = patch_info->ip.i + code;
3786 unsigned char *target;
3788 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3790 switch (patch_info->type) {
3791 case MONO_PATCH_INFO_IP:
3792 patch_lis_ori (ip, ip);
3794 case MONO_PATCH_INFO_METHOD_REL:
3795 g_assert_not_reached ();
3796 *((gpointer *)(ip)) = code + patch_info->data.offset;
3798 case MONO_PATCH_INFO_SWITCH: {
3799 gpointer *table = (gpointer *)patch_info->data.table->table;
3802 patch_lis_ori (ip, table);
3804 for (i = 0; i < patch_info->data.table->table_size; i++) {
3805 table [i] = (int)patch_info->data.table->table [i] + code;
3807 /* we put into the table the absolute address, no need for ppc_patch in this case */
3810 case MONO_PATCH_INFO_METHODCONST:
3811 case MONO_PATCH_INFO_CLASS:
3812 case MONO_PATCH_INFO_IMAGE:
3813 case MONO_PATCH_INFO_FIELD:
3814 case MONO_PATCH_INFO_VTABLE:
3815 case MONO_PATCH_INFO_IID:
3816 case MONO_PATCH_INFO_SFLDA:
3817 case MONO_PATCH_INFO_LDSTR:
3818 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3819 case MONO_PATCH_INFO_LDTOKEN:
3820 /* from OP_AOTCONST : lis + ori */
3821 patch_lis_ori (ip, target);
3823 case MONO_PATCH_INFO_R4:
3824 case MONO_PATCH_INFO_R8:
3825 g_assert_not_reached ();
3826 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3828 case MONO_PATCH_INFO_EXC_NAME:
3829 g_assert_not_reached ();
3830 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3832 case MONO_PATCH_INFO_NONE:
3833 case MONO_PATCH_INFO_BB_OVF:
3834 case MONO_PATCH_INFO_EXC_OVF:
3835 /* everything is dealt with at epilog output time */
3840 ppc_patch (ip, target);
3845 * Stack frame layout:
3847 * ------------------- sp
3848 * MonoLMF structure or saved registers
3849 * -------------------
3851 * -------------------
3853 * -------------------
3854 * optional 8 bytes for tracing
3855 * -------------------
3856 * param area size is cfg->param_area
3857 * -------------------
3858 * linkage area size is PPC_STACK_PARAM_OFFSET
3859 * ------------------- sp
3863 mono_arch_emit_prolog (MonoCompile *cfg)
3865 MonoMethod *method = cfg->method;
3867 MonoMethodSignature *sig;
3869 int alloc_size, pos, max_offset, i;
3874 int tailcall_struct_index;
3876 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3879 sig = mono_method_signature (method);
3880 cfg->code_size = 256 + sig->param_count * 20;
3881 code = cfg->native_code = g_malloc (cfg->code_size);
3883 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3884 ppc_mflr (code, ppc_r0);
3885 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3888 alloc_size = cfg->stack_offset;
3891 if (!method->save_lmf) {
3892 /*for (i = 31; i >= 14; --i) {
3893 if (cfg->used_float_regs & (1 << i)) {
3894 pos += sizeof (gdouble);
3895 ppc_stfd (code, i, -pos, ppc_sp);
3898 for (i = 31; i >= 13; --i) {
3899 if (cfg->used_int_regs & (1 << i)) {
3900 pos += sizeof (gulong);
3901 ppc_stw (code, i, -pos, ppc_sp);
3906 pos += sizeof (MonoLMF);
3908 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3909 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3910 for (i = 14; i < 32; i++) {
3911 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3915 // align to PPC_STACK_ALIGNMENT bytes
3916 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3917 alloc_size += PPC_STACK_ALIGNMENT - 1;
3918 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3921 cfg->stack_usage = alloc_size;
3922 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3924 if (ppc_is_imm16 (-alloc_size)) {
3925 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3927 ppc_load (code, ppc_r11, -alloc_size);
3928 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3931 if (cfg->frame_reg != ppc_sp)
3932 ppc_mr (code, cfg->frame_reg, ppc_sp);
3934 /* store runtime generic context */
3935 if (cfg->rgctx_var) {
3936 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3937 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3939 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3942 /* compute max_offset in order to use short forward jumps
3943 * we always do it on ppc because the immediate displacement
3944 * for jumps is too small
3947 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3949 bb->max_offset = max_offset;
3951 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3954 MONO_BB_FOR_EACH_INS (bb, ins)
3955 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3958 /* load arguments allocated to register from the stack */
3961 cinfo = calculate_sizes (sig, sig->pinvoke);
3963 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3964 ArgInfo *ainfo = &cinfo->ret;
3967 inst = cfg->vret_addr;
3972 if (ppc_is_imm16 (inst->inst_offset)) {
3973 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3975 ppc_load (code, ppc_r11, inst->inst_offset);
3976 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3980 tailcall_struct_index = 0;
3981 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3982 ArgInfo *ainfo = cinfo->args + i;
3983 inst = cfg->args [pos];
3985 if (cfg->verbose_level > 2)
3986 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3987 if (inst->opcode == OP_REGVAR) {
3988 if (ainfo->regtype == RegTypeGeneral)
3989 ppc_mr (code, inst->dreg, ainfo->reg);
3990 else if (ainfo->regtype == RegTypeFP)
3991 ppc_fmr (code, inst->dreg, ainfo->reg);
3992 else if (ainfo->regtype == RegTypeBase) {
3993 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3994 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3996 g_assert_not_reached ();
3998 if (cfg->verbose_level > 2)
3999 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4001 /* the argument should be put on the stack: FIXME handle size != word */
4002 if (ainfo->regtype == RegTypeGeneral) {
4003 switch (ainfo->size) {
4005 if (ppc_is_imm16 (inst->inst_offset)) {
4006 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4008 ppc_load (code, ppc_r11, inst->inst_offset);
4009 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4013 if (ppc_is_imm16 (inst->inst_offset)) {
4014 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4016 ppc_load (code, ppc_r11, inst->inst_offset);
4017 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4021 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4022 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4023 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4025 ppc_load (code, ppc_r11, inst->inst_offset);
4026 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4027 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4028 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4032 if (ppc_is_imm16 (inst->inst_offset)) {
4033 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4035 ppc_load (code, ppc_r11, inst->inst_offset);
4036 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4040 } else if (ainfo->regtype == RegTypeBase) {
4041 /* load the previous stack pointer in r11 */
4042 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4043 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4044 switch (ainfo->size) {
4046 if (ppc_is_imm16 (inst->inst_offset)) {
4047 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4049 ppc_load (code, ppc_r11, inst->inst_offset);
4050 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4054 if (ppc_is_imm16 (inst->inst_offset)) {
4055 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4057 ppc_load (code, ppc_r11, inst->inst_offset);
4058 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4062 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4063 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4064 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4065 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4068 g_assert_not_reached ();
4072 if (ppc_is_imm16 (inst->inst_offset)) {
4073 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4075 ppc_load (code, ppc_r11, inst->inst_offset);
4076 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4080 } else if (ainfo->regtype == RegTypeFP) {
4081 g_assert (ppc_is_imm16 (inst->inst_offset));
4082 if (ainfo->size == 8)
4083 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4084 else if (ainfo->size == 4)
4085 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4087 g_assert_not_reached ();
4088 } else if (ainfo->regtype == RegTypeStructByVal) {
4089 int doffset = inst->inst_offset;
4093 g_assert (ppc_is_imm16 (inst->inst_offset));
4094 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4095 /* FIXME: what if there is no class? */
4096 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4097 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4098 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4101 * Darwin handles 1 and 2 byte
4102 * structs specially by
4103 * loading h/b into the arg
4104 * register. Only done for
4108 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4110 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4113 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4114 soffset += sizeof (gpointer);
4115 doffset += sizeof (gpointer);
4117 if (ainfo->vtsize) {
4118 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4119 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4120 if ((size & 3) != 0) {
4121 code = emit_memcpy (code, size - soffset,
4122 inst->inst_basereg, doffset,
4123 ppc_r11, ainfo->offset + soffset);
4125 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4126 inst->inst_basereg, doffset,
4127 ppc_r11, ainfo->offset + soffset);
4130 } else if (ainfo->regtype == RegTypeStructByAddr) {
4131 /* if it was originally a RegTypeBase */
4132 if (ainfo->offset) {
4133 /* load the previous stack pointer in r11 */
4134 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4135 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4137 ppc_mr (code, ppc_r11, ainfo->reg);
4140 if (cfg->tailcall_valuetype_addrs) {
4141 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4143 g_assert (ppc_is_imm16 (addr->inst_offset));
4144 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4146 tailcall_struct_index++;
4149 g_assert (ppc_is_imm16 (inst->inst_offset));
4150 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4151 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4153 g_assert_not_reached ();
4158 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4159 ppc_load (code, ppc_r3, cfg->domain);
4160 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4161 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4162 ppc_lis (code, ppc_r0, 0);
4163 ppc_ori (code, ppc_r0, ppc_r0, 0);
4164 ppc_mtlr (code, ppc_r0);
4171 if (method->save_lmf) {
4172 if (lmf_pthread_key != -1) {
4173 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4174 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4175 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4177 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4178 (gpointer)"mono_get_lmf_addr");
4179 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4180 ppc_lis (code, ppc_r0, 0);
4181 ppc_ori (code, ppc_r0, ppc_r0, 0);
4182 ppc_mtlr (code, ppc_r0);
4188 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4189 /* lmf_offset is the offset from the previous stack pointer,
4190 * alloc_size is the total stack space allocated, so the offset
4191 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4192 * The pointer to the struct is put in ppc_r11 (new_lmf).
4193 * The callee-saved registers are already in the MonoLMF structure
4195 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4196 /* ppc_r3 is the result from mono_get_lmf_addr () */
4197 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4198 /* new_lmf->previous_lmf = *lmf_addr */
4199 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4200 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4201 /* *(lmf_addr) = r11 */
4202 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4203 /* save method info */
4204 ppc_load (code, ppc_r0, method);
4205 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4206 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4207 /* save the current IP */
4208 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4209 ppc_load (code, ppc_r0, 0x01010101);
4210 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4214 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4216 cfg->code_len = code - cfg->native_code;
4217 g_assert (cfg->code_len < cfg->code_size);
4224 mono_arch_emit_epilog (MonoCompile *cfg)
4226 MonoMethod *method = cfg->method;
4228 int max_epilog_size = 16 + 20*4;
4231 if (cfg->method->save_lmf)
4232 max_epilog_size += 128;
4234 if (mono_jit_trace_calls != NULL)
4235 max_epilog_size += 50;
4237 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4238 max_epilog_size += 50;
4240 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4241 cfg->code_size *= 2;
4242 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4243 mono_jit_stats.code_reallocs++;
4247 * Keep in sync with OP_JMP
4249 code = cfg->native_code + cfg->code_len;
4251 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4252 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4256 if (method->save_lmf) {
4258 pos += sizeof (MonoLMF);
4260 /* save the frame reg in r8 */
4261 ppc_mr (code, ppc_r8, cfg->frame_reg);
4262 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4263 /* r5 = previous_lmf */
4264 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4266 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4267 /* *(lmf_addr) = previous_lmf */
4268 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4269 /* FIXME: speedup: there is no actual need to restore the registers if
4270 * we didn't actually change them (idea from Zoltan).
4273 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4275 /*for (i = 14; i < 32; i++) {
4276 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4278 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4279 /* use the saved copy of the frame reg in r8 */
4280 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4281 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4282 ppc_mtlr (code, ppc_r0);
4284 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4286 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4287 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4288 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4290 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4291 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4293 ppc_mtlr (code, ppc_r0);
4295 if (ppc_is_imm16 (cfg->stack_usage)) {
4296 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4298 ppc_load (code, ppc_r11, cfg->stack_usage);
4299 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4302 /*for (i = 31; i >= 14; --i) {
4303 if (cfg->used_float_regs & (1 << i)) {
4304 pos += sizeof (double);
4305 ppc_lfd (code, i, -pos, ppc_sp);
4308 for (i = 31; i >= 13; --i) {
4309 if (cfg->used_int_regs & (1 << i)) {
4310 pos += sizeof (gulong);
4311 ppc_lwz (code, i, -pos, ppc_sp);
4317 cfg->code_len = code - cfg->native_code;
4319 g_assert (cfg->code_len < cfg->code_size);
4323 /* remove once throw_exception_by_name is eliminated */
4325 exception_id_by_name (const char *name)
4327 if (strcmp (name, "IndexOutOfRangeException") == 0)
4328 return MONO_EXC_INDEX_OUT_OF_RANGE;
4329 if (strcmp (name, "OverflowException") == 0)
4330 return MONO_EXC_OVERFLOW;
4331 if (strcmp (name, "ArithmeticException") == 0)
4332 return MONO_EXC_ARITHMETIC;
4333 if (strcmp (name, "DivideByZeroException") == 0)
4334 return MONO_EXC_DIVIDE_BY_ZERO;
4335 if (strcmp (name, "InvalidCastException") == 0)
4336 return MONO_EXC_INVALID_CAST;
4337 if (strcmp (name, "NullReferenceException") == 0)
4338 return MONO_EXC_NULL_REF;
4339 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4340 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4341 g_error ("Unknown intrinsic exception %s\n", name);
4346 mono_arch_emit_exceptions (MonoCompile *cfg)
4348 MonoJumpInfo *patch_info;
4351 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4352 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4353 int max_epilog_size = 50;
4355 /* count the number of exception infos */
4358 * make sure we have enough space for exceptions
4359 * 24 is the simulated call to throw_exception_by_name
4361 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4362 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4363 i = exception_id_by_name (patch_info->data.target);
4364 if (!exc_throw_found [i]) {
4365 max_epilog_size += 24;
4366 exc_throw_found [i] = TRUE;
4368 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4369 max_epilog_size += 12;
4370 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4371 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4372 i = exception_id_by_name (ovfj->data.exception);
4373 if (!exc_throw_found [i]) {
4374 max_epilog_size += 24;
4375 exc_throw_found [i] = TRUE;
4377 max_epilog_size += 8;
4381 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4382 cfg->code_size *= 2;
4383 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4384 mono_jit_stats.code_reallocs++;
4387 code = cfg->native_code + cfg->code_len;
4389 /* add code to raise exceptions */
4390 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4391 switch (patch_info->type) {
4392 case MONO_PATCH_INFO_BB_OVF: {
4393 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4394 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4395 /* patch the initial jump */
4396 ppc_patch (ip, code);
4397 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4399 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4400 /* jump back to the true target */
4402 ip = ovfj->data.bb->native_offset + cfg->native_code;
4403 ppc_patch (code - 4, ip);
4406 case MONO_PATCH_INFO_EXC_OVF: {
4407 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4408 MonoJumpInfo *newji;
4409 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4410 unsigned char *bcl = code;
4411 /* patch the initial jump: we arrived here with a call */
4412 ppc_patch (ip, code);
4413 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4415 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4416 /* patch the conditional jump to the right handler */
4417 /* make it processed next */
4418 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4419 newji->type = MONO_PATCH_INFO_EXC;
4420 newji->ip.i = bcl - cfg->native_code;
4421 newji->data.target = ovfj->data.exception;
4422 newji->next = patch_info->next;
4423 patch_info->next = newji;
4426 case MONO_PATCH_INFO_EXC: {
4427 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4428 i = exception_id_by_name (patch_info->data.target);
4429 if (exc_throw_pos [i]) {
4430 ppc_patch (ip, exc_throw_pos [i]);
4431 patch_info->type = MONO_PATCH_INFO_NONE;
4434 exc_throw_pos [i] = code;
4436 ppc_patch (ip, code);
4437 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4438 ppc_load (code, ppc_r3, patch_info->data.target);
4439 /* we got here from a conditional call, so the calling ip is set in lr already */
4440 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4441 patch_info->data.name = "mono_arch_throw_exception_by_name";
4442 patch_info->ip.i = code - cfg->native_code;
4443 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4444 ppc_lis (code, ppc_r0, 0);
4445 ppc_ori (code, ppc_r0, ppc_r0, 0);
4446 ppc_mtctr (code, ppc_r0);
4447 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4459 cfg->code_len = code - cfg->native_code;
4461 g_assert (cfg->code_len < cfg->code_size);
4466 try_offset_access (void *value, guint32 idx)
4468 register void* me __asm__ ("r2");
4469 void ***p = (void***)((char*)me + 284);
4470 int idx1 = idx / 32;
4471 int idx2 = idx % 32;
4474 if (value != p[idx1][idx2])
4480 setup_tls_access (void)
4483 guint32 *ins, *code;
4484 guint32 cmplwi_1023, li_0x48, blr_ins;
4485 if (tls_mode == TLS_MODE_FAILED)
4488 if (g_getenv ("MONO_NO_TLS")) {
4489 tls_mode = TLS_MODE_FAILED;
4493 if (tls_mode == TLS_MODE_DETECT) {
4494 ins = (guint32*)pthread_getspecific;
4495 /* uncond branch to the real method */
4496 if ((*ins >> 26) == 18) {
4498 val = (*ins & ~3) << 6;
4502 ins = (guint32*)val;
4504 ins = (guint32*) ((char*)ins + val);
4507 code = &cmplwi_1023;
4508 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4510 ppc_li (code, ppc_r4, 0x48);
4513 if (*ins == cmplwi_1023) {
4514 int found_lwz_284 = 0;
4515 for (ptk = 0; ptk < 20; ++ptk) {
4517 if (!*ins || *ins == blr_ins)
4519 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4524 if (!found_lwz_284) {
4525 tls_mode = TLS_MODE_FAILED;
4528 tls_mode = TLS_MODE_LTHREADS;
4529 } else if (*ins == li_0x48) {
4531 /* uncond branch to the real method */
4532 if ((*ins >> 26) == 18) {
4534 val = (*ins & ~3) << 6;
4538 ins = (guint32*)val;
4540 ins = (guint32*) ((char*)ins + val);
4542 code = (guint32*)&val;
4543 ppc_li (code, ppc_r0, 0x7FF2);
4544 if (ins [1] == val) {
4545 /* Darwin on G4, implement */
4546 tls_mode = TLS_MODE_FAILED;
4549 code = (guint32*)&val;
4550 ppc_mfspr (code, ppc_r3, 104);
4551 if (ins [1] != val) {
4552 tls_mode = TLS_MODE_FAILED;
4555 tls_mode = TLS_MODE_DARWIN_G5;
4558 tls_mode = TLS_MODE_FAILED;
4562 tls_mode = TLS_MODE_FAILED;
4566 if (monodomain_key == -1) {
4567 ptk = mono_domain_get_tls_key ();
4569 ptk = mono_pthread_key_for_tls (ptk);
4571 monodomain_key = ptk;
4575 if (lmf_pthread_key == -1) {
4576 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4578 /*g_print ("MonoLMF at: %d\n", ptk);*/
4579 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4580 init_tls_failed = 1;
4583 lmf_pthread_key = ptk;
4586 if (monothread_key == -1) {
4587 ptk = mono_thread_get_tls_key ();
4589 ptk = mono_pthread_key_for_tls (ptk);
4591 monothread_key = ptk;
4592 /*g_print ("thread inited: %d\n", ptk);*/
4595 /*g_print ("thread not inited yet %d\n", ptk);*/
4601 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4603 setup_tls_access ();
4607 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4612 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4614 int this_dreg = ppc_r3;
4619 /* add the this argument */
4620 if (this_reg != -1) {
4622 MONO_INST_NEW (cfg, this, OP_MOVE);
4623 this->type = this_type;
4624 this->sreg1 = this_reg;
4625 this->dreg = mono_regstate_next_int (cfg->rs);
4626 mono_bblock_add_inst (cfg->cbb, this);
4627 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4632 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4633 vtarg->type = STACK_MP;
4634 vtarg->sreg1 = vt_reg;
4635 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4636 mono_bblock_add_inst (cfg->cbb, vtarg);
4637 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4641 #ifdef MONO_ARCH_HAVE_IMT
4645 #define JUMP_IMM_SIZE 12
4646 #define ENABLE_WRONG_METHOD_CHECK 0
4649 * LOCKING: called with the domain lock held
4652 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4653 gpointer fail_tramp)
4657 guint8 *code, *start;
4659 g_assert (!fail_tramp);
4661 for (i = 0; i < count; ++i) {
4662 MonoIMTCheckItem *item = imt_entries [i];
4663 if (item->is_equals) {
4664 if (item->check_target_idx) {
4665 if (!item->compare_done)
4666 item->chunk_size += CMP_SIZE;
4667 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4669 item->chunk_size += JUMP_IMM_SIZE;
4670 #if ENABLE_WRONG_METHOD_CHECK
4671 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4675 item->chunk_size += CMP_SIZE + BR_SIZE;
4676 imt_entries [item->check_target_idx]->compare_done = TRUE;
4678 size += item->chunk_size;
4680 /* the initial load of the vtable address */
4682 code = mono_code_manager_reserve (domain->code_mp, size);
4684 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4685 for (i = 0; i < count; ++i) {
4686 MonoIMTCheckItem *item = imt_entries [i];
4687 item->code_target = code;
4688 if (item->is_equals) {
4689 if (item->check_target_idx) {
4690 if (!item->compare_done) {
4691 ppc_load (code, ppc_r0, (guint32)item->key);
4692 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4694 item->jmp_code = code;
4695 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4696 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4697 ppc_mtctr (code, ppc_r0);
4698 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4700 /* enable the commented code to assert on wrong method */
4701 #if ENABLE_WRONG_METHOD_CHECK
4702 ppc_load (code, ppc_r0, (guint32)item->key);
4703 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4704 item->jmp_code = code;
4705 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4707 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4708 ppc_mtctr (code, ppc_r0);
4709 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4710 #if ENABLE_WRONG_METHOD_CHECK
4711 ppc_patch (item->jmp_code, code);
4713 item->jmp_code = NULL;
4717 ppc_load (code, ppc_r0, (guint32)item->key);
4718 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4719 item->jmp_code = code;
4720 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4723 /* patch the branches to get to the target items */
4724 for (i = 0; i < count; ++i) {
4725 MonoIMTCheckItem *item = imt_entries [i];
4726 if (item->jmp_code) {
4727 if (item->check_target_idx) {
4728 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4733 mono_stats.imt_thunks_size += code - start;
4734 g_assert (code - start <= size);
4735 mono_arch_flush_icache (start, size);
4740 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4742 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4746 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4748 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4753 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4755 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4759 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4761 MonoInst *ins = NULL;
4763 /*if (cmethod->klass == mono_defaults.math_class) {
4764 if (strcmp (cmethod->name, "Sqrt") == 0) {
4765 MONO_INST_NEW (cfg, ins, OP_SQRT);
4766 ins->inst_i0 = args [0];
4773 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4780 mono_arch_print_tree (MonoInst *tree, int arity)
4785 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4789 setup_tls_access ();
4790 if (monodomain_key == -1)
4793 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4794 ins->inst_offset = monodomain_key;
4799 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4803 setup_tls_access ();
4804 if (monothread_key == -1)
4807 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4808 ins->inst_offset = monothread_key;
4813 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4815 g_assert (reg >= ppc_r13);
4817 return (gpointer)ctx->regs [reg - ppc_r13];