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);
1628 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1631 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1632 ins->sreg1 = val->dreg + 1;
1633 ins->sreg2 = val->dreg + 2;
1634 MONO_ADD_INS (cfg->cbb, ins);
1637 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1638 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1641 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1644 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1646 mono_arch_is_inst_imm (gint64 imm)
1652 * Allow tracing to work with this interface (with an optional argument)
1656 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1660 ppc_load (code, ppc_r3, cfg->method);
1661 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1662 ppc_load (code, ppc_r0, func);
1663 ppc_mtlr (code, ppc_r0);
1677 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1680 int save_mode = SAVE_NONE;
1682 MonoMethod *method = cfg->method;
1683 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1684 mono_method_signature (method)->ret)->type;
1685 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1689 offset = code - cfg->native_code;
1690 /* we need about 16 instructions */
1691 if (offset > (cfg->code_size - 16 * 4)) {
1692 cfg->code_size *= 2;
1693 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1694 code = cfg->native_code + offset;
1698 case MONO_TYPE_VOID:
1699 /* special case string .ctor icall */
1700 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1701 save_mode = SAVE_ONE;
1703 save_mode = SAVE_NONE;
1707 save_mode = SAVE_TWO;
1711 save_mode = SAVE_FP;
1713 case MONO_TYPE_VALUETYPE:
1714 save_mode = SAVE_STRUCT;
1717 save_mode = SAVE_ONE;
1721 switch (save_mode) {
1723 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1724 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1725 if (enable_arguments) {
1726 ppc_mr (code, ppc_r5, ppc_r4);
1727 ppc_mr (code, ppc_r4, ppc_r3);
1731 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1732 if (enable_arguments) {
1733 ppc_mr (code, ppc_r4, ppc_r3);
1737 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1738 if (enable_arguments) {
1739 /* FIXME: what reg? */
1740 ppc_fmr (code, ppc_f3, ppc_f1);
1741 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1742 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1746 if (enable_arguments) {
1747 /* FIXME: get the actual address */
1748 ppc_mr (code, ppc_r4, ppc_r3);
1756 ppc_load (code, ppc_r3, cfg->method);
1757 ppc_load (code, ppc_r0, func);
1758 ppc_mtlr (code, ppc_r0);
1761 switch (save_mode) {
1763 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1764 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1767 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1770 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1780 * Conditional branches have a small offset, so if it is likely overflowed,
1781 * we do a branch to the end of the method (uncond branches have much larger
1782 * offsets) where we perform the conditional and jump back unconditionally.
1783 * It's slightly slower, since we add two uncond branches, but it's very simple
1784 * with the current patch implementation and such large methods are likely not
1785 * going to be perf critical anyway.
1790 const char *exception;
1797 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1798 if (ins->flags & MONO_INST_BRLABEL) { \
1799 if (0 && ins->inst_i0->inst_c0) { \
1800 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1802 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1803 ppc_bc (code, (b0), (b1), 0); \
1806 if (0 && ins->inst_true_bb->native_offset) { \
1807 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1809 int br_disp = ins->inst_true_bb->max_offset - offset; \
1810 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1811 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1812 ovfj->data.bb = ins->inst_true_bb; \
1813 ovfj->ip_offset = 0; \
1814 ovfj->b0_cond = (b0); \
1815 ovfj->b1_cond = (b1); \
1816 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1819 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1820 ppc_bc (code, (b0), (b1), 0); \
1825 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1827 /* emit an exception if condition is fail
1829 * We assign the extra code used to throw the implicit exceptions
1830 * to cfg->bb_exit as far as the big branch handling is concerned
1832 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1834 int br_disp = cfg->bb_exit->max_offset - offset; \
1835 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1836 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1837 ovfj->data.exception = (exc_name); \
1838 ovfj->ip_offset = code - cfg->native_code; \
1839 ovfj->b0_cond = (b0); \
1840 ovfj->b1_cond = (b1); \
1841 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1843 cfg->bb_exit->max_offset += 24; \
1845 mono_add_patch_info (cfg, code - cfg->native_code, \
1846 MONO_PATCH_INFO_EXC, exc_name); \
1847 ppc_bcl (code, (b0), (b1), 0); \
1851 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1854 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1859 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1861 MonoInst *ins, *n, *last_ins = NULL;
1863 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1864 switch (ins->opcode) {
1866 /* remove unnecessary multiplication with 1 */
1867 if (ins->inst_imm == 1) {
1868 if (ins->dreg != ins->sreg1) {
1869 ins->opcode = OP_MOVE;
1871 MONO_DELETE_INS (bb, ins);
1875 int power2 = mono_is_power_of_two (ins->inst_imm);
1877 ins->opcode = OP_SHL_IMM;
1878 ins->inst_imm = power2;
1882 case OP_LOAD_MEMBASE:
1883 case OP_LOADI4_MEMBASE:
1885 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1886 * OP_LOAD_MEMBASE offset(basereg), reg
1888 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1889 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1890 ins->inst_basereg == last_ins->inst_destbasereg &&
1891 ins->inst_offset == last_ins->inst_offset) {
1892 if (ins->dreg == last_ins->sreg1) {
1893 MONO_DELETE_INS (bb, ins);
1896 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1897 ins->opcode = OP_MOVE;
1898 ins->sreg1 = last_ins->sreg1;
1902 * Note: reg1 must be different from the basereg in the second load
1903 * OP_LOAD_MEMBASE offset(basereg), reg1
1904 * OP_LOAD_MEMBASE offset(basereg), reg2
1906 * OP_LOAD_MEMBASE offset(basereg), reg1
1907 * OP_MOVE reg1, reg2
1909 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1910 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1911 ins->inst_basereg != last_ins->dreg &&
1912 ins->inst_basereg == last_ins->inst_basereg &&
1913 ins->inst_offset == last_ins->inst_offset) {
1915 if (ins->dreg == last_ins->dreg) {
1916 MONO_DELETE_INS (bb, ins);
1919 ins->opcode = OP_MOVE;
1920 ins->sreg1 = last_ins->dreg;
1923 //g_assert_not_reached ();
1927 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1928 * OP_LOAD_MEMBASE offset(basereg), reg
1930 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1931 * OP_ICONST reg, imm
1933 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1934 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1935 ins->inst_basereg == last_ins->inst_destbasereg &&
1936 ins->inst_offset == last_ins->inst_offset) {
1937 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1938 ins->opcode = OP_ICONST;
1939 ins->inst_c0 = last_ins->inst_imm;
1940 g_assert_not_reached (); // check this rule
1944 case OP_LOADU1_MEMBASE:
1945 case OP_LOADI1_MEMBASE:
1946 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1947 ins->inst_basereg == last_ins->inst_destbasereg &&
1948 ins->inst_offset == last_ins->inst_offset) {
1949 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1950 ins->sreg1 = last_ins->sreg1;
1953 case OP_LOADU2_MEMBASE:
1954 case OP_LOADI2_MEMBASE:
1955 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1956 ins->inst_basereg == last_ins->inst_destbasereg &&
1957 ins->inst_offset == last_ins->inst_offset) {
1958 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1959 ins->sreg1 = last_ins->sreg1;
1963 ins->opcode = OP_MOVE;
1967 if (ins->dreg == ins->sreg1) {
1968 MONO_DELETE_INS (bb, ins);
1972 * OP_MOVE sreg, dreg
1973 * OP_MOVE dreg, sreg
1975 if (last_ins && last_ins->opcode == OP_MOVE &&
1976 ins->sreg1 == last_ins->dreg &&
1977 ins->dreg == last_ins->sreg1) {
1978 MONO_DELETE_INS (bb, ins);
1986 bb->last_ins = last_ins;
1990 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1992 g_assert (cfg->new_ir);
1994 switch (ins->opcode) {
1995 case OP_ICONV_TO_R_UN: {
1996 static const guint64 adjust_val = 0x4330000000000000ULL;
1997 int msw_reg = mono_alloc_ireg (cfg);
1998 int adj_reg = mono_alloc_freg (cfg);
1999 int tmp_reg = mono_alloc_freg (cfg);
2000 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2001 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2002 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
2003 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2004 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2005 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2006 ins->opcode = OP_NOP;
2009 case OP_ICONV_TO_R4:
2010 case OP_ICONV_TO_R8: {
2011 /* FIXME: change precision for CEE_CONV_R4 */
2012 static const guint64 adjust_val = 0x4330000080000000ULL;
2013 int msw_reg = mono_alloc_ireg (cfg);
2014 int xored = mono_alloc_ireg (cfg);
2015 int adj_reg = mono_alloc_freg (cfg);
2016 int tmp_reg = mono_alloc_freg (cfg);
2017 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2018 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2019 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2020 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2021 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2022 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2023 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2024 if (ins->opcode == OP_ICONV_TO_R4)
2025 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2026 ins->opcode = OP_NOP;
2030 int msw_reg = mono_alloc_ireg (cfg);
2031 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2032 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2033 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2034 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2035 ins->opcode = OP_NOP;
2042 * the branch_b0_table should maintain the order of these
2056 branch_b0_table [] = {
2071 branch_b1_table [] = {
2085 #define NEW_INS(cfg,dest,op) do { \
2086 MONO_INST_NEW((cfg), (dest), (op)); \
2087 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2091 map_to_reg_reg_op (int op)
2100 case OP_COMPARE_IMM:
2102 case OP_ICOMPARE_IMM:
2118 case OP_LOAD_MEMBASE:
2119 return OP_LOAD_MEMINDEX;
2120 case OP_LOADI4_MEMBASE:
2121 return OP_LOADI4_MEMINDEX;
2122 case OP_LOADU4_MEMBASE:
2123 return OP_LOADU4_MEMINDEX;
2124 case OP_LOADU1_MEMBASE:
2125 return OP_LOADU1_MEMINDEX;
2126 case OP_LOADI2_MEMBASE:
2127 return OP_LOADI2_MEMINDEX;
2128 case OP_LOADU2_MEMBASE:
2129 return OP_LOADU2_MEMINDEX;
2130 case OP_LOADI1_MEMBASE:
2131 return OP_LOADI1_MEMINDEX;
2132 case OP_LOADR4_MEMBASE:
2133 return OP_LOADR4_MEMINDEX;
2134 case OP_LOADR8_MEMBASE:
2135 return OP_LOADR8_MEMINDEX;
2136 case OP_STOREI1_MEMBASE_REG:
2137 return OP_STOREI1_MEMINDEX;
2138 case OP_STOREI2_MEMBASE_REG:
2139 return OP_STOREI2_MEMINDEX;
2140 case OP_STOREI4_MEMBASE_REG:
2141 return OP_STOREI4_MEMINDEX;
2142 case OP_STORE_MEMBASE_REG:
2143 return OP_STORE_MEMINDEX;
2144 case OP_STORER4_MEMBASE_REG:
2145 return OP_STORER4_MEMINDEX;
2146 case OP_STORER8_MEMBASE_REG:
2147 return OP_STORER8_MEMINDEX;
2148 case OP_STORE_MEMBASE_IMM:
2149 return OP_STORE_MEMBASE_REG;
2150 case OP_STOREI1_MEMBASE_IMM:
2151 return OP_STOREI1_MEMBASE_REG;
2152 case OP_STOREI2_MEMBASE_IMM:
2153 return OP_STOREI2_MEMBASE_REG;
2154 case OP_STOREI4_MEMBASE_IMM:
2155 return OP_STOREI4_MEMBASE_REG;
2157 return mono_op_imm_to_op (op);
2160 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2162 #define compare_opcode_is_unsigned(opcode) \
2163 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2164 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2165 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2166 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2167 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2169 * Remove from the instruction list the instructions that can't be
2170 * represented with very simple instructions with no register
2174 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2176 MonoInst *ins, *next, *temp, *last_ins = NULL;
2179 /* setup the virtual reg allocator */
2180 if (bb->max_vreg > cfg->rs->next_vreg)
2181 cfg->rs->next_vreg = bb->max_vreg;
2183 MONO_BB_FOR_EACH_INS (bb, ins) {
2185 switch (ins->opcode) {
2186 case OP_IDIV_UN_IMM:
2189 case OP_IREM_UN_IMM:
2190 NEW_INS (cfg, temp, OP_ICONST);
2191 temp->inst_c0 = ins->inst_imm;
2192 temp->dreg = mono_regstate_next_int (cfg->rs);
2193 ins->sreg2 = temp->dreg;
2194 if (ins->opcode == OP_IDIV_IMM)
2195 ins->opcode = OP_IDIV;
2196 else if (ins->opcode == OP_IREM_IMM)
2197 ins->opcode = OP_IREM;
2198 else if (ins->opcode == OP_IDIV_UN_IMM)
2199 ins->opcode = OP_IDIV_UN;
2200 else if (ins->opcode == OP_IREM_UN_IMM)
2201 ins->opcode = OP_IREM_UN;
2203 /* handle rem separately */
2208 /* we change a rem dest, src1, src2 to
2209 * div temp1, src1, src2
2210 * mul temp2, temp1, src2
2211 * sub dest, src1, temp2
2213 NEW_INS (cfg, mul, OP_IMUL);
2214 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2215 temp->sreg1 = ins->sreg1;
2216 temp->sreg2 = ins->sreg2;
2217 temp->dreg = mono_regstate_next_int (cfg->rs);
2218 mul->sreg1 = temp->dreg;
2219 mul->sreg2 = ins->sreg2;
2220 mul->dreg = mono_regstate_next_int (cfg->rs);
2221 ins->opcode = OP_ISUB;
2222 ins->sreg2 = mul->dreg;
2228 if (!ppc_is_imm16 (ins->inst_imm)) {
2229 NEW_INS (cfg, temp, OP_ICONST);
2230 temp->inst_c0 = ins->inst_imm;
2231 temp->dreg = mono_regstate_next_int (cfg->rs);
2232 ins->sreg2 = temp->dreg;
2233 ins->opcode = map_to_reg_reg_op (ins->opcode);
2238 if (!ppc_is_imm16 (-ins->inst_imm)) {
2239 NEW_INS (cfg, temp, OP_ICONST);
2240 temp->inst_c0 = ins->inst_imm;
2241 temp->dreg = mono_regstate_next_int (cfg->rs);
2242 ins->sreg2 = temp->dreg;
2243 ins->opcode = map_to_reg_reg_op (ins->opcode);
2252 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2253 NEW_INS (cfg, temp, OP_ICONST);
2254 temp->inst_c0 = ins->inst_imm;
2255 temp->dreg = mono_regstate_next_int (cfg->rs);
2256 ins->sreg2 = temp->dreg;
2257 ins->opcode = map_to_reg_reg_op (ins->opcode);
2265 NEW_INS (cfg, temp, OP_ICONST);
2266 temp->inst_c0 = ins->inst_imm;
2267 temp->dreg = mono_regstate_next_int (cfg->rs);
2268 ins->sreg2 = temp->dreg;
2269 ins->opcode = map_to_reg_reg_op (ins->opcode);
2271 case OP_COMPARE_IMM:
2272 case OP_ICOMPARE_IMM:
2274 /* Branch opts can eliminate the branch */
2275 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2276 ins->opcode = OP_NOP;
2280 if (compare_opcode_is_unsigned (next->opcode)) {
2281 if (!ppc_is_uimm16 (ins->inst_imm)) {
2282 NEW_INS (cfg, temp, OP_ICONST);
2283 temp->inst_c0 = ins->inst_imm;
2284 temp->dreg = mono_regstate_next_int (cfg->rs);
2285 ins->sreg2 = temp->dreg;
2286 ins->opcode = map_to_reg_reg_op (ins->opcode);
2289 if (!ppc_is_imm16 (ins->inst_imm)) {
2290 NEW_INS (cfg, temp, OP_ICONST);
2291 temp->inst_c0 = ins->inst_imm;
2292 temp->dreg = mono_regstate_next_int (cfg->rs);
2293 ins->sreg2 = temp->dreg;
2294 ins->opcode = map_to_reg_reg_op (ins->opcode);
2300 if (ins->inst_imm == 1) {
2301 ins->opcode = OP_MOVE;
2304 if (ins->inst_imm == 0) {
2305 ins->opcode = OP_ICONST;
2309 imm = mono_is_power_of_two (ins->inst_imm);
2311 ins->opcode = OP_SHL_IMM;
2312 ins->inst_imm = imm;
2315 if (!ppc_is_imm16 (ins->inst_imm)) {
2316 NEW_INS (cfg, temp, OP_ICONST);
2317 temp->inst_c0 = ins->inst_imm;
2318 temp->dreg = mono_regstate_next_int (cfg->rs);
2319 ins->sreg2 = temp->dreg;
2320 ins->opcode = map_to_reg_reg_op (ins->opcode);
2323 case OP_LOCALLOC_IMM:
2324 NEW_INS (cfg, temp, OP_ICONST);
2325 temp->inst_c0 = ins->inst_imm;
2326 temp->dreg = mono_regstate_next_int (cfg->rs);
2327 ins->sreg1 = temp->dreg;
2328 ins->opcode = OP_LOCALLOC;
2330 case OP_LOAD_MEMBASE:
2331 case OP_LOADI4_MEMBASE:
2332 case OP_LOADU4_MEMBASE:
2333 case OP_LOADI2_MEMBASE:
2334 case OP_LOADU2_MEMBASE:
2335 case OP_LOADI1_MEMBASE:
2336 case OP_LOADU1_MEMBASE:
2337 case OP_LOADR4_MEMBASE:
2338 case OP_LOADR8_MEMBASE:
2339 case OP_STORE_MEMBASE_REG:
2340 case OP_STOREI4_MEMBASE_REG:
2341 case OP_STOREI2_MEMBASE_REG:
2342 case OP_STOREI1_MEMBASE_REG:
2343 case OP_STORER4_MEMBASE_REG:
2344 case OP_STORER8_MEMBASE_REG:
2345 /* we can do two things: load the immed in a register
2346 * and use an indexed load, or see if the immed can be
2347 * represented as an ad_imm + a load with a smaller offset
2348 * that fits. We just do the first for now, optimize later.
2350 if (ppc_is_imm16 (ins->inst_offset))
2352 NEW_INS (cfg, temp, OP_ICONST);
2353 temp->inst_c0 = ins->inst_offset;
2354 temp->dreg = mono_regstate_next_int (cfg->rs);
2355 ins->sreg2 = temp->dreg;
2356 ins->opcode = map_to_reg_reg_op (ins->opcode);
2358 case OP_STORE_MEMBASE_IMM:
2359 case OP_STOREI1_MEMBASE_IMM:
2360 case OP_STOREI2_MEMBASE_IMM:
2361 case OP_STOREI4_MEMBASE_IMM:
2362 NEW_INS (cfg, temp, OP_ICONST);
2363 temp->inst_c0 = ins->inst_imm;
2364 temp->dreg = mono_regstate_next_int (cfg->rs);
2365 ins->sreg1 = temp->dreg;
2366 ins->opcode = map_to_reg_reg_op (ins->opcode);
2368 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2371 NEW_INS (cfg, temp, OP_ICONST);
2372 temp->inst_c0 = (guint32)ins->inst_p0;
2373 temp->dreg = mono_regstate_next_int (cfg->rs);
2374 ins->inst_basereg = temp->dreg;
2375 ins->inst_offset = 0;
2376 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2378 /* make it handle the possibly big ins->inst_offset
2379 * later optimize to use lis + load_membase
2385 bb->last_ins = last_ins;
2386 bb->max_vreg = cfg->rs->next_vreg;
2391 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2393 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2394 ppc_fctiwz (code, ppc_f0, sreg);
2395 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2396 ppc_lwz (code, dreg, -4, ppc_sp);
2399 ppc_andid (code, dreg, dreg, 0xff);
2401 ppc_andid (code, dreg, dreg, 0xffff);
2404 ppc_extsb (code, dreg, dreg);
2406 ppc_extsh (code, dreg, dreg);
2413 const guchar *target;
2418 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2421 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2422 PatchData *pdata = (PatchData*)user_data;
2423 guchar *code = data;
2424 guint32 *thunks = data;
2425 guint32 *endthunks = (guint32*)(code + bsize);
2429 int difflow, diffhigh;
2431 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2432 difflow = (char*)pdata->code - (char*)thunks;
2433 diffhigh = (char*)pdata->code - (char*)endthunks;
2434 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2437 templ = (guchar*)load;
2438 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2439 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2441 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2442 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2443 while (thunks < endthunks) {
2444 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2445 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2446 ppc_patch (pdata->code, (guchar*)thunks);
2447 mono_arch_flush_icache (pdata->code, 4);
2450 static int num_thunks = 0;
2452 if ((num_thunks % 20) == 0)
2453 g_print ("num_thunks lookup: %d\n", num_thunks);
2456 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2457 /* found a free slot instead: emit thunk */
2458 code = (guchar*)thunks;
2459 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2460 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2461 ppc_mtctr (code, ppc_r0);
2462 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2463 mono_arch_flush_icache ((guchar*)thunks, 16);
2465 ppc_patch (pdata->code, (guchar*)thunks);
2466 mono_arch_flush_icache (pdata->code, 4);
2469 static int num_thunks = 0;
2471 if ((num_thunks % 20) == 0)
2472 g_print ("num_thunks: %d\n", num_thunks);
2476 /* skip 16 bytes, the size of the thunk */
2480 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2486 handle_thunk (int absolute, guchar *code, const guchar *target) {
2487 MonoDomain *domain = mono_domain_get ();
2491 pdata.target = target;
2492 pdata.absolute = absolute;
2495 mono_domain_lock (domain);
2496 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2499 /* this uses the first available slot */
2501 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2503 mono_domain_unlock (domain);
2505 if (pdata.found != 1)
2506 g_print ("thunk failed for %p from %p\n", target, code);
2507 g_assert (pdata.found == 1);
2511 ppc_patch (guchar *code, const guchar *target)
2513 guint32 ins = *(guint32*)code;
2514 guint32 prim = ins >> 26;
2517 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2519 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2520 gint diff = target - code;
2522 if (diff <= 33554431){
2523 ins = (18 << 26) | (diff) | (ins & 1);
2524 *(guint32*)code = ins;
2528 /* diff between 0 and -33554432 */
2529 if (diff >= -33554432){
2530 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2531 *(guint32*)code = ins;
2536 if ((glong)target >= 0){
2537 if ((glong)target <= 33554431){
2538 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2539 *(guint32*)code = ins;
2543 if ((glong)target >= -33554432){
2544 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2545 *(guint32*)code = ins;
2550 handle_thunk (TRUE, code, target);
2553 g_assert_not_reached ();
2560 guint32 li = (guint32)target;
2561 ins = (ins & 0xffff0000) | (ins & 3);
2562 ovf = li & 0xffff0000;
2563 if (ovf != 0 && ovf != 0xffff0000)
2564 g_assert_not_reached ();
2567 // FIXME: assert the top bits of li are 0
2569 gint diff = target - code;
2570 ins = (ins & 0xffff0000) | (ins & 3);
2571 ovf = diff & 0xffff0000;
2572 if (ovf != 0 && ovf != 0xffff0000)
2573 g_assert_not_reached ();
2577 *(guint32*)code = ins;
2581 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2583 /* the trampoline code will try to patch the blrl, blr, bcctr */
2584 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2587 /* this is the lis/ori/mtlr/blrl sequence */
2588 seq = (guint32*)code;
2589 g_assert ((seq [0] >> 26) == 15);
2590 g_assert ((seq [1] >> 26) == 24);
2591 g_assert ((seq [2] >> 26) == 31);
2592 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2593 /* FIXME: make this thread safe */
2594 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2595 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2596 mono_arch_flush_icache (code - 8, 8);
2598 g_assert_not_reached ();
2600 // g_print ("patched with 0x%08x\n", ins);
2604 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2606 switch (ins->opcode) {
2609 case OP_FCALL_MEMBASE:
2610 if (ins->dreg != ppc_f1)
2611 ppc_fmr (code, ins->dreg, ppc_f1);
2619 * emit_load_volatile_arguments:
2621 * Load volatile arguments from the stack to the original input registers.
2622 * Required before a tail call.
2625 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2627 MonoMethod *method = cfg->method;
2628 MonoMethodSignature *sig;
2632 int struct_index = 0;
2634 /* FIXME: Generate intermediate code instead */
2636 sig = mono_method_signature (method);
2638 /* This is the opposite of the code in emit_prolog */
2642 cinfo = calculate_sizes (sig, sig->pinvoke);
2644 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2645 ArgInfo *ainfo = &cinfo->ret;
2646 inst = cfg->vret_addr;
2647 g_assert (ppc_is_imm16 (inst->inst_offset));
2648 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2650 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2651 ArgInfo *ainfo = cinfo->args + i;
2652 inst = cfg->args [pos];
2654 g_assert (inst->opcode != OP_REGVAR);
2655 g_assert (ppc_is_imm16 (inst->inst_offset));
2657 switch (ainfo->regtype) {
2658 case RegTypeGeneral:
2659 switch (ainfo->size) {
2661 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2664 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2667 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2673 switch (ainfo->size) {
2675 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2678 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2681 g_assert_not_reached ();
2689 case RegTypeStructByVal: {
2697 * Darwin pinvokes needs some special handling
2698 * for 1 and 2 byte arguments
2700 if (method->signature->pinvoke)
2701 size = mono_class_native_size (inst->klass, NULL);
2702 if (size == 1 || size == 2) {
2707 for (i = 0; i < ainfo->size; ++i) {
2708 ppc_lwz (code, ainfo->reg + i,
2709 inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
2714 case RegTypeStructByAddr: {
2715 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2717 g_assert (ppc_is_imm16 (addr->inst_offset));
2718 g_assert (!ainfo->offset);
2719 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2726 g_assert_not_reached ();
2738 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2740 MonoInst *ins, *next;
2743 guint8 *code = cfg->native_code + cfg->code_len;
2744 MonoInst *last_ins = NULL;
2745 guint last_offset = 0;
2748 /* we don't align basic blocks of loops on ppc */
2750 if (cfg->verbose_level > 2)
2751 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2753 cpos = bb->max_offset;
2755 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2756 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2757 //g_assert (!mono_compile_aot);
2760 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2761 /* this is not thread save, but good enough */
2762 /* fixme: howto handle overflows? */
2763 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2766 MONO_BB_FOR_EACH_INS (bb, ins) {
2767 offset = code - cfg->native_code;
2769 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2771 if (offset > (cfg->code_size - max_len - 16)) {
2772 cfg->code_size *= 2;
2773 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2774 code = cfg->native_code + offset;
2776 // if (ins->cil_code)
2777 // g_print ("cil code\n");
2778 mono_debug_record_line_number (cfg, ins, offset);
2780 switch (ins->opcode) {
2781 case OP_RELAXED_NOP:
2784 case OP_DUMMY_STORE:
2785 case OP_NOT_REACHED:
2789 emit_tls_access (code, ins->dreg, ins->inst_offset);
2792 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2793 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2794 ppc_mr (code, ppc_r4, ppc_r0);
2797 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2798 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2799 ppc_mr (code, ppc_r4, ppc_r0);
2801 case OP_MEMORY_BARRIER:
2804 case OP_STOREI1_MEMBASE_REG:
2805 if (ppc_is_imm16 (ins->inst_offset)) {
2806 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2808 ppc_load (code, ppc_r0, ins->inst_offset);
2809 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2812 case OP_STOREI2_MEMBASE_REG:
2813 if (ppc_is_imm16 (ins->inst_offset)) {
2814 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2816 ppc_load (code, ppc_r0, ins->inst_offset);
2817 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2820 case OP_STORE_MEMBASE_REG:
2821 case OP_STOREI4_MEMBASE_REG:
2822 if (ppc_is_imm16 (ins->inst_offset)) {
2823 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2825 ppc_load (code, ppc_r0, ins->inst_offset);
2826 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2829 case OP_STOREI1_MEMINDEX:
2830 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2832 case OP_STOREI2_MEMINDEX:
2833 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2835 case OP_STORE_MEMINDEX:
2836 case OP_STOREI4_MEMINDEX:
2837 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2840 g_assert_not_reached ();
2842 case OP_LOAD_MEMBASE:
2843 case OP_LOADI4_MEMBASE:
2844 case OP_LOADU4_MEMBASE:
2845 if (ppc_is_imm16 (ins->inst_offset)) {
2846 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2848 ppc_load (code, ppc_r0, ins->inst_offset);
2849 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2852 case OP_LOADI1_MEMBASE:
2853 case OP_LOADU1_MEMBASE:
2854 if (ppc_is_imm16 (ins->inst_offset)) {
2855 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2857 ppc_load (code, ppc_r0, ins->inst_offset);
2858 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2860 if (ins->opcode == OP_LOADI1_MEMBASE)
2861 ppc_extsb (code, ins->dreg, ins->dreg);
2863 case OP_LOADU2_MEMBASE:
2864 if (ppc_is_imm16 (ins->inst_offset)) {
2865 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2867 ppc_load (code, ppc_r0, ins->inst_offset);
2868 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2871 case OP_LOADI2_MEMBASE:
2872 if (ppc_is_imm16 (ins->inst_offset)) {
2873 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2875 ppc_load (code, ppc_r0, ins->inst_offset);
2876 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2879 case OP_LOAD_MEMINDEX:
2880 case OP_LOADI4_MEMINDEX:
2881 case OP_LOADU4_MEMINDEX:
2882 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2884 case OP_LOADU2_MEMINDEX:
2885 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2887 case OP_LOADI2_MEMINDEX:
2888 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2890 case OP_LOADU1_MEMINDEX:
2891 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2893 case OP_LOADI1_MEMINDEX:
2894 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2895 ppc_extsb (code, ins->dreg, ins->dreg);
2897 case OP_ICONV_TO_I1:
2898 ppc_extsb (code, ins->dreg, ins->sreg1);
2900 case OP_ICONV_TO_I2:
2901 ppc_extsh (code, ins->dreg, ins->sreg1);
2903 case OP_ICONV_TO_U1:
2904 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2906 case OP_ICONV_TO_U2:
2907 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2912 if (next && compare_opcode_is_unsigned (next->opcode))
2913 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2915 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2917 case OP_COMPARE_IMM:
2918 case OP_ICOMPARE_IMM:
2920 if (next && compare_opcode_is_unsigned (next->opcode)) {
2921 if (ppc_is_uimm16 (ins->inst_imm)) {
2922 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2924 g_assert_not_reached ();
2927 if (ppc_is_imm16 (ins->inst_imm)) {
2928 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2930 g_assert_not_reached ();
2939 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2942 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2946 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2949 if (ppc_is_imm16 (ins->inst_imm)) {
2950 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2952 g_assert_not_reached ();
2957 if (ppc_is_imm16 (ins->inst_imm)) {
2958 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2960 g_assert_not_reached ();
2964 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2966 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2967 ppc_mfspr (code, ppc_r0, ppc_xer);
2968 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2969 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2971 case OP_IADD_OVF_UN:
2972 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2974 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2975 ppc_mfspr (code, ppc_r0, ppc_xer);
2976 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2977 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2980 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2982 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2983 ppc_mfspr (code, ppc_r0, ppc_xer);
2984 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2985 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2987 case OP_ISUB_OVF_UN:
2988 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2990 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2991 ppc_mfspr (code, ppc_r0, ppc_xer);
2992 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2993 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2995 case OP_ADD_OVF_CARRY:
2996 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2998 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2999 ppc_mfspr (code, ppc_r0, ppc_xer);
3000 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3001 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3003 case OP_ADD_OVF_UN_CARRY:
3004 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3006 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3007 ppc_mfspr (code, ppc_r0, ppc_xer);
3008 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3009 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3011 case OP_SUB_OVF_CARRY:
3012 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3014 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3015 ppc_mfspr (code, ppc_r0, ppc_xer);
3016 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3017 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3019 case OP_SUB_OVF_UN_CARRY:
3020 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3022 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3023 ppc_mfspr (code, ppc_r0, ppc_xer);
3024 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3025 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3029 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3032 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3036 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3040 // we add the negated value
3041 if (ppc_is_imm16 (-ins->inst_imm))
3042 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3044 g_assert_not_reached ();
3048 g_assert (ppc_is_imm16 (ins->inst_imm));
3049 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3052 ppc_subfze (code, ins->dreg, ins->sreg1);
3055 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3056 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3060 if (!(ins->inst_imm & 0xffff0000)) {
3061 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3062 } else if (!(ins->inst_imm & 0xffff)) {
3063 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3065 g_assert_not_reached ();
3069 guint8 *divisor_is_m1;
3070 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3072 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3073 divisor_is_m1 = code;
3074 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3075 ppc_lis (code, ppc_r0, 0x8000);
3076 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3077 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3078 ppc_patch (divisor_is_m1, code);
3079 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3081 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3082 ppc_mfspr (code, ppc_r0, ppc_xer);
3083 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3084 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3088 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3089 ppc_mfspr (code, ppc_r0, ppc_xer);
3090 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3091 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3097 g_assert_not_reached ();
3099 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3103 if (!(ins->inst_imm & 0xffff0000)) {
3104 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3105 } else if (!(ins->inst_imm & 0xffff)) {
3106 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3108 g_assert_not_reached ();
3112 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3116 if (!(ins->inst_imm & 0xffff0000)) {
3117 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3118 } else if (!(ins->inst_imm & 0xffff)) {
3119 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3121 g_assert_not_reached ();
3125 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3129 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3132 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3136 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3139 case OP_ISHR_UN_IMM:
3141 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3143 ppc_mr (code, ins->dreg, ins->sreg1);
3146 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3149 ppc_not (code, ins->dreg, ins->sreg1);
3152 ppc_neg (code, ins->dreg, ins->sreg1);
3155 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3159 if (ppc_is_imm16 (ins->inst_imm)) {
3160 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3162 g_assert_not_reached ();
3166 /* we annot use mcrxr, since it's not implemented on some processors
3167 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3169 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3170 ppc_mfspr (code, ppc_r0, ppc_xer);
3171 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3172 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3174 case OP_IMUL_OVF_UN:
3175 /* we first multiply to get the high word and compare to 0
3176 * to set the flags, then the result is discarded and then
3177 * we multiply to get the lower * bits result
3179 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3180 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3181 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3182 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3185 ppc_load (code, ins->dreg, ins->inst_c0);
3188 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3189 ppc_lis (code, ins->dreg, 0);
3190 ppc_ori (code, ins->dreg, ins->dreg, 0);
3192 case OP_ICONV_TO_I4:
3193 case OP_ICONV_TO_U4:
3195 ppc_mr (code, ins->dreg, ins->sreg1);
3198 int saved = ins->sreg1;
3199 if (ins->sreg1 == ppc_r3) {
3200 ppc_mr (code, ppc_r0, ins->sreg1);
3203 if (ins->sreg2 != ppc_r3)
3204 ppc_mr (code, ppc_r3, ins->sreg2);
3205 if (saved != ppc_r4)
3206 ppc_mr (code, ppc_r4, saved);
3210 ppc_fmr (code, ins->dreg, ins->sreg1);
3212 case OP_FCONV_TO_R4:
3213 ppc_frsp (code, ins->dreg, ins->sreg1);
3219 * Keep in sync with mono_arch_emit_epilog
3221 g_assert (!cfg->method->save_lmf);
3223 * Note: we can use ppc_r11 here because it is dead anyway:
3224 * we're leaving the method.
3226 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3227 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3228 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3230 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3231 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3233 ppc_mtlr (code, ppc_r0);
3236 code = emit_load_volatile_arguments (cfg, code);
3238 if (ppc_is_imm16 (cfg->stack_usage)) {
3239 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3241 ppc_load (code, ppc_r11, cfg->stack_usage);
3242 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3244 if (!cfg->method->save_lmf) {
3245 /*for (i = 31; i >= 14; --i) {
3246 if (cfg->used_float_regs & (1 << i)) {
3247 pos += sizeof (double);
3248 ppc_lfd (code, i, -pos, cfg->frame_reg);
3251 for (i = 31; i >= 13; --i) {
3252 if (cfg->used_int_regs & (1 << i)) {
3253 pos += sizeof (gulong);
3254 ppc_lwz (code, i, -pos, cfg->frame_reg);
3258 /* FIXME restore from MonoLMF: though this can't happen yet */
3260 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3265 /* ensure ins->sreg1 is not NULL */
3266 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3269 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3270 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3272 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3273 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3275 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3284 call = (MonoCallInst*)ins;
3285 if (ins->flags & MONO_INST_HAS_METHOD)
3286 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3288 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3289 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3290 ppc_lis (code, ppc_r0, 0);
3291 ppc_ori (code, ppc_r0, ppc_r0, 0);
3292 ppc_mtlr (code, ppc_r0);
3297 /* FIXME: this should be handled somewhere else in the new jit */
3298 code = emit_move_return_value (cfg, ins, code);
3304 case OP_VOIDCALL_REG:
3306 ppc_mtlr (code, ins->sreg1);
3308 /* FIXME: this should be handled somewhere else in the new jit */
3309 code = emit_move_return_value (cfg, ins, code);
3311 case OP_FCALL_MEMBASE:
3312 case OP_LCALL_MEMBASE:
3313 case OP_VCALL_MEMBASE:
3314 case OP_VCALL2_MEMBASE:
3315 case OP_VOIDCALL_MEMBASE:
3316 case OP_CALL_MEMBASE:
3317 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3318 ppc_mtlr (code, ppc_r0);
3320 /* FIXME: this should be handled somewhere else in the new jit */
3321 code = emit_move_return_value (cfg, ins, code);
3324 g_assert_not_reached ();
3327 guint8 * zero_loop_jump, * zero_loop_start;
3328 /* keep alignment */
3329 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3330 int area_offset = alloca_waste;
3332 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3333 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3334 /* use ctr to store the number of words to 0 if needed */
3335 if (ins->flags & MONO_INST_INIT) {
3336 /* we zero 4 bytes at a time:
3337 * we add 7 instead of 3 so that we set the counter to
3338 * at least 1, otherwise the bdnz instruction will make
3339 * it negative and iterate billions of times.
3341 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3342 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3343 ppc_mtctr (code, ppc_r0);
3345 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3346 ppc_neg (code, ppc_r11, ppc_r11);
3347 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3349 if (ins->flags & MONO_INST_INIT) {
3350 /* adjust the dest reg by -4 so we can use stwu */
3351 /* we actually adjust -8 because we let the loop
3354 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3355 ppc_li (code, ppc_r11, 0);
3356 zero_loop_start = code;
3357 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3358 zero_loop_jump = code;
3359 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3360 ppc_patch (zero_loop_jump, zero_loop_start);
3362 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3367 ppc_mr (code, ppc_r3, ins->sreg1);
3368 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3369 (gpointer)"mono_arch_throw_exception");
3370 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3371 ppc_lis (code, ppc_r0, 0);
3372 ppc_ori (code, ppc_r0, ppc_r0, 0);
3373 ppc_mtlr (code, ppc_r0);
3382 ppc_mr (code, ppc_r3, ins->sreg1);
3383 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3384 (gpointer)"mono_arch_rethrow_exception");
3385 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3386 ppc_lis (code, ppc_r0, 0);
3387 ppc_ori (code, ppc_r0, ppc_r0, 0);
3388 ppc_mtlr (code, ppc_r0);
3395 case OP_START_HANDLER: {
3396 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3397 ppc_mflr (code, ppc_r0);
3398 if (ppc_is_imm16 (spvar->inst_offset)) {
3399 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3401 ppc_load (code, ppc_r11, spvar->inst_offset);
3402 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3406 case OP_ENDFILTER: {
3407 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3408 if (ins->sreg1 != ppc_r3)
3409 ppc_mr (code, ppc_r3, ins->sreg1);
3410 if (ppc_is_imm16 (spvar->inst_offset)) {
3411 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3413 ppc_load (code, ppc_r11, spvar->inst_offset);
3414 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3416 ppc_mtlr (code, ppc_r0);
3420 case OP_ENDFINALLY: {
3421 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3422 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3423 ppc_mtlr (code, ppc_r0);
3427 case OP_CALL_HANDLER:
3428 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3432 ins->inst_c0 = code - cfg->native_code;
3435 if (ins->flags & MONO_INST_BRLABEL) {
3436 /*if (ins->inst_i0->inst_c0) {
3438 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3440 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3444 /*if (ins->inst_target_bb->native_offset) {
3446 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3448 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3454 ppc_mtctr (code, ins->sreg1);
3455 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3459 ppc_li (code, ins->dreg, 0);
3460 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3461 ppc_li (code, ins->dreg, 1);
3467 ppc_li (code, ins->dreg, 1);
3468 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3469 ppc_li (code, ins->dreg, 0);
3475 ppc_li (code, ins->dreg, 1);
3476 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3477 ppc_li (code, ins->dreg, 0);
3479 case OP_COND_EXC_EQ:
3480 case OP_COND_EXC_NE_UN:
3481 case OP_COND_EXC_LT:
3482 case OP_COND_EXC_LT_UN:
3483 case OP_COND_EXC_GT:
3484 case OP_COND_EXC_GT_UN:
3485 case OP_COND_EXC_GE:
3486 case OP_COND_EXC_GE_UN:
3487 case OP_COND_EXC_LE:
3488 case OP_COND_EXC_LE_UN:
3489 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3491 case OP_COND_EXC_IEQ:
3492 case OP_COND_EXC_INE_UN:
3493 case OP_COND_EXC_ILT:
3494 case OP_COND_EXC_ILT_UN:
3495 case OP_COND_EXC_IGT:
3496 case OP_COND_EXC_IGT_UN:
3497 case OP_COND_EXC_IGE:
3498 case OP_COND_EXC_IGE_UN:
3499 case OP_COND_EXC_ILE:
3500 case OP_COND_EXC_ILE_UN:
3501 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3504 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3506 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3507 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3508 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3510 case OP_COND_EXC_OV:
3511 /*ppc_mcrxr (code, 0);
3512 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3514 case OP_COND_EXC_NC:
3515 case OP_COND_EXC_NO:
3516 g_assert_not_reached ();
3528 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3531 /* floating point opcodes */
3534 g_assert_not_reached ();
3535 case OP_STORER8_MEMBASE_REG:
3536 if (ppc_is_imm16 (ins->inst_offset)) {
3537 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3539 ppc_load (code, ppc_r0, ins->inst_offset);
3540 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3543 case OP_LOADR8_MEMBASE:
3544 if (ppc_is_imm16 (ins->inst_offset)) {
3545 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3547 ppc_load (code, ppc_r0, ins->inst_offset);
3548 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3551 case OP_STORER4_MEMBASE_REG:
3552 ppc_frsp (code, ins->sreg1, ins->sreg1);
3553 if (ppc_is_imm16 (ins->inst_offset)) {
3554 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3556 ppc_load (code, ppc_r0, ins->inst_offset);
3557 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3560 case OP_LOADR4_MEMBASE:
3561 if (ppc_is_imm16 (ins->inst_offset)) {
3562 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3564 ppc_load (code, ppc_r0, ins->inst_offset);
3565 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3568 case OP_LOADR4_MEMINDEX:
3569 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3571 case OP_LOADR8_MEMINDEX:
3572 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3574 case OP_STORER4_MEMINDEX:
3575 ppc_frsp (code, ins->sreg1, ins->sreg1);
3576 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3578 case OP_STORER8_MEMINDEX:
3579 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3582 case CEE_CONV_R4: /* FIXME: change precision */
3584 g_assert_not_reached ();
3585 case OP_FCONV_TO_I1:
3586 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3588 case OP_FCONV_TO_U1:
3589 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3591 case OP_FCONV_TO_I2:
3592 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3594 case OP_FCONV_TO_U2:
3595 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3597 case OP_FCONV_TO_I4:
3599 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3601 case OP_FCONV_TO_U4:
3603 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3605 case OP_FCONV_TO_I8:
3606 case OP_FCONV_TO_U8:
3607 g_assert_not_reached ();
3608 /* Implemented as helper calls */
3610 case OP_LCONV_TO_R_UN:
3611 g_assert_not_reached ();
3612 /* Implemented as helper calls */
3614 case OP_LCONV_TO_OVF_I4_2:
3615 case OP_LCONV_TO_OVF_I: {
3616 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3617 // Check if its negative
3618 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3619 negative_branch = code;
3620 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3621 // Its positive msword == 0
3622 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3623 msword_positive_branch = code;
3624 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3626 ovf_ex_target = code;
3627 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3629 ppc_patch (negative_branch, code);
3630 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3631 msword_negative_branch = code;
3632 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3633 ppc_patch (msword_negative_branch, ovf_ex_target);
3635 ppc_patch (msword_positive_branch, code);
3636 if (ins->dreg != ins->sreg1)
3637 ppc_mr (code, ins->dreg, ins->sreg1);
3641 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3644 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3647 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3650 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3653 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3656 ppc_fneg (code, ins->dreg, ins->sreg1);
3660 g_assert_not_reached ();
3663 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3666 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3667 ppc_li (code, ins->dreg, 0);
3668 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3669 ppc_li (code, ins->dreg, 1);
3672 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3673 ppc_li (code, ins->dreg, 1);
3674 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3675 ppc_li (code, ins->dreg, 0);
3678 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3679 ppc_li (code, ins->dreg, 1);
3680 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3681 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3682 ppc_li (code, ins->dreg, 0);
3685 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3686 ppc_li (code, ins->dreg, 1);
3687 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3688 ppc_li (code, ins->dreg, 0);
3691 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3692 ppc_li (code, ins->dreg, 1);
3693 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3694 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3695 ppc_li (code, ins->dreg, 0);
3698 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3701 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3704 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3705 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3708 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3709 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3712 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3713 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3716 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3717 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3720 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3721 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3724 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3727 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3728 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3731 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3734 g_assert_not_reached ();
3735 case OP_CHECK_FINITE: {
3736 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3737 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3738 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3739 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3742 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3743 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3747 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3748 g_assert_not_reached ();
3751 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3752 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3753 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3754 g_assert_not_reached ();
3760 last_offset = offset;
3763 cfg->code_len = code - cfg->native_code;
3767 mono_arch_register_lowlevel_calls (void)
3771 #define patch_lis_ori(ip,val) do {\
3772 guint16 *__lis_ori = (guint16*)(ip); \
3773 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3774 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3778 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3780 MonoJumpInfo *patch_info;
3782 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3783 unsigned char *ip = patch_info->ip.i + code;
3784 unsigned char *target;
3786 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3788 switch (patch_info->type) {
3789 case MONO_PATCH_INFO_IP:
3790 patch_lis_ori (ip, ip);
3792 case MONO_PATCH_INFO_METHOD_REL:
3793 g_assert_not_reached ();
3794 *((gpointer *)(ip)) = code + patch_info->data.offset;
3796 case MONO_PATCH_INFO_SWITCH: {
3797 gpointer *table = (gpointer *)patch_info->data.table->table;
3800 patch_lis_ori (ip, table);
3802 for (i = 0; i < patch_info->data.table->table_size; i++) {
3803 table [i] = (int)patch_info->data.table->table [i] + code;
3805 /* we put into the table the absolute address, no need for ppc_patch in this case */
3808 case MONO_PATCH_INFO_METHODCONST:
3809 case MONO_PATCH_INFO_CLASS:
3810 case MONO_PATCH_INFO_IMAGE:
3811 case MONO_PATCH_INFO_FIELD:
3812 case MONO_PATCH_INFO_VTABLE:
3813 case MONO_PATCH_INFO_IID:
3814 case MONO_PATCH_INFO_SFLDA:
3815 case MONO_PATCH_INFO_LDSTR:
3816 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3817 case MONO_PATCH_INFO_LDTOKEN:
3818 /* from OP_AOTCONST : lis + ori */
3819 patch_lis_ori (ip, target);
3821 case MONO_PATCH_INFO_R4:
3822 case MONO_PATCH_INFO_R8:
3823 g_assert_not_reached ();
3824 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3826 case MONO_PATCH_INFO_EXC_NAME:
3827 g_assert_not_reached ();
3828 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3830 case MONO_PATCH_INFO_NONE:
3831 case MONO_PATCH_INFO_BB_OVF:
3832 case MONO_PATCH_INFO_EXC_OVF:
3833 /* everything is dealt with at epilog output time */
3838 ppc_patch (ip, target);
3843 * Stack frame layout:
3845 * ------------------- sp
3846 * MonoLMF structure or saved registers
3847 * -------------------
3849 * -------------------
3851 * -------------------
3852 * optional 8 bytes for tracing
3853 * -------------------
3854 * param area size is cfg->param_area
3855 * -------------------
3856 * linkage area size is PPC_STACK_PARAM_OFFSET
3857 * ------------------- sp
3861 mono_arch_emit_prolog (MonoCompile *cfg)
3863 MonoMethod *method = cfg->method;
3865 MonoMethodSignature *sig;
3867 int alloc_size, pos, max_offset, i;
3872 int tailcall_struct_index;
3874 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3877 sig = mono_method_signature (method);
3878 cfg->code_size = 256 + sig->param_count * 20;
3879 code = cfg->native_code = g_malloc (cfg->code_size);
3881 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3882 ppc_mflr (code, ppc_r0);
3883 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3886 alloc_size = cfg->stack_offset;
3889 if (!method->save_lmf) {
3890 /*for (i = 31; i >= 14; --i) {
3891 if (cfg->used_float_regs & (1 << i)) {
3892 pos += sizeof (gdouble);
3893 ppc_stfd (code, i, -pos, ppc_sp);
3896 for (i = 31; i >= 13; --i) {
3897 if (cfg->used_int_regs & (1 << i)) {
3898 pos += sizeof (gulong);
3899 ppc_stw (code, i, -pos, ppc_sp);
3904 pos += sizeof (MonoLMF);
3906 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3907 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3908 for (i = 14; i < 32; i++) {
3909 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3913 // align to PPC_STACK_ALIGNMENT bytes
3914 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3915 alloc_size += PPC_STACK_ALIGNMENT - 1;
3916 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3919 cfg->stack_usage = alloc_size;
3920 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3922 if (ppc_is_imm16 (-alloc_size)) {
3923 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3925 ppc_load (code, ppc_r11, -alloc_size);
3926 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3929 if (cfg->frame_reg != ppc_sp)
3930 ppc_mr (code, cfg->frame_reg, ppc_sp);
3932 /* store runtime generic context */
3933 if (cfg->rgctx_var) {
3934 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3935 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3937 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3940 /* compute max_offset in order to use short forward jumps
3941 * we always do it on ppc because the immediate displacement
3942 * for jumps is too small
3945 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3947 bb->max_offset = max_offset;
3949 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3952 MONO_BB_FOR_EACH_INS (bb, ins)
3953 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3956 /* load arguments allocated to register from the stack */
3959 cinfo = calculate_sizes (sig, sig->pinvoke);
3961 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3962 ArgInfo *ainfo = &cinfo->ret;
3965 inst = cfg->vret_addr;
3970 if (ppc_is_imm16 (inst->inst_offset)) {
3971 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3973 ppc_load (code, ppc_r11, inst->inst_offset);
3974 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3978 tailcall_struct_index = 0;
3979 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3980 ArgInfo *ainfo = cinfo->args + i;
3981 inst = cfg->args [pos];
3983 if (cfg->verbose_level > 2)
3984 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3985 if (inst->opcode == OP_REGVAR) {
3986 if (ainfo->regtype == RegTypeGeneral)
3987 ppc_mr (code, inst->dreg, ainfo->reg);
3988 else if (ainfo->regtype == RegTypeFP)
3989 ppc_fmr (code, inst->dreg, ainfo->reg);
3990 else if (ainfo->regtype == RegTypeBase) {
3991 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3992 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3994 g_assert_not_reached ();
3996 if (cfg->verbose_level > 2)
3997 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3999 /* the argument should be put on the stack: FIXME handle size != word */
4000 if (ainfo->regtype == RegTypeGeneral) {
4001 switch (ainfo->size) {
4003 if (ppc_is_imm16 (inst->inst_offset)) {
4004 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4006 ppc_load (code, ppc_r11, inst->inst_offset);
4007 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4011 if (ppc_is_imm16 (inst->inst_offset)) {
4012 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4014 ppc_load (code, ppc_r11, inst->inst_offset);
4015 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4019 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4020 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4021 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4023 ppc_load (code, ppc_r11, inst->inst_offset);
4024 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4025 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4026 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4030 if (ppc_is_imm16 (inst->inst_offset)) {
4031 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4033 ppc_load (code, ppc_r11, inst->inst_offset);
4034 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4038 } else if (ainfo->regtype == RegTypeBase) {
4039 /* load the previous stack pointer in r11 */
4040 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4041 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4042 switch (ainfo->size) {
4044 if (ppc_is_imm16 (inst->inst_offset)) {
4045 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4047 ppc_load (code, ppc_r11, inst->inst_offset);
4048 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4052 if (ppc_is_imm16 (inst->inst_offset)) {
4053 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4055 ppc_load (code, ppc_r11, inst->inst_offset);
4056 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4060 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4061 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4062 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4063 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4066 g_assert_not_reached ();
4070 if (ppc_is_imm16 (inst->inst_offset)) {
4071 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4073 ppc_load (code, ppc_r11, inst->inst_offset);
4074 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4078 } else if (ainfo->regtype == RegTypeFP) {
4079 g_assert (ppc_is_imm16 (inst->inst_offset));
4080 if (ainfo->size == 8)
4081 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4082 else if (ainfo->size == 4)
4083 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4085 g_assert_not_reached ();
4086 } else if (ainfo->regtype == RegTypeStructByVal) {
4087 int doffset = inst->inst_offset;
4091 g_assert (ppc_is_imm16 (inst->inst_offset));
4092 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4093 /* FIXME: what if there is no class? */
4094 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4095 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4096 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4099 * Darwin handles 1 and 2 byte
4100 * structs specially by
4101 * loading h/b into the arg
4102 * register. Only done for
4106 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4108 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4111 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4112 soffset += sizeof (gpointer);
4113 doffset += sizeof (gpointer);
4115 if (ainfo->vtsize) {
4116 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4117 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4118 if ((size & 3) != 0) {
4119 code = emit_memcpy (code, size - soffset,
4120 inst->inst_basereg, doffset,
4121 ppc_r11, ainfo->offset + soffset);
4123 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4124 inst->inst_basereg, doffset,
4125 ppc_r11, ainfo->offset + soffset);
4128 } else if (ainfo->regtype == RegTypeStructByAddr) {
4129 /* if it was originally a RegTypeBase */
4130 if (ainfo->offset) {
4131 /* load the previous stack pointer in r11 */
4132 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4133 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4135 ppc_mr (code, ppc_r11, ainfo->reg);
4138 if (cfg->tailcall_valuetype_addrs) {
4139 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4141 g_assert (ppc_is_imm16 (addr->inst_offset));
4142 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4144 tailcall_struct_index++;
4147 g_assert (ppc_is_imm16 (inst->inst_offset));
4148 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4149 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4151 g_assert_not_reached ();
4156 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4157 ppc_load (code, ppc_r3, cfg->domain);
4158 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4159 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4160 ppc_lis (code, ppc_r0, 0);
4161 ppc_ori (code, ppc_r0, ppc_r0, 0);
4162 ppc_mtlr (code, ppc_r0);
4169 if (method->save_lmf) {
4170 if (lmf_pthread_key != -1) {
4171 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4172 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4173 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4175 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4176 (gpointer)"mono_get_lmf_addr");
4177 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4178 ppc_lis (code, ppc_r0, 0);
4179 ppc_ori (code, ppc_r0, ppc_r0, 0);
4180 ppc_mtlr (code, ppc_r0);
4186 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4187 /* lmf_offset is the offset from the previous stack pointer,
4188 * alloc_size is the total stack space allocated, so the offset
4189 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4190 * The pointer to the struct is put in ppc_r11 (new_lmf).
4191 * The callee-saved registers are already in the MonoLMF structure
4193 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4194 /* ppc_r3 is the result from mono_get_lmf_addr () */
4195 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4196 /* new_lmf->previous_lmf = *lmf_addr */
4197 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4198 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4199 /* *(lmf_addr) = r11 */
4200 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4201 /* save method info */
4202 ppc_load (code, ppc_r0, method);
4203 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4204 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4205 /* save the current IP */
4206 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4207 ppc_load (code, ppc_r0, 0x01010101);
4208 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4212 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4214 cfg->code_len = code - cfg->native_code;
4215 g_assert (cfg->code_len < cfg->code_size);
4222 mono_arch_emit_epilog (MonoCompile *cfg)
4224 MonoMethod *method = cfg->method;
4226 int max_epilog_size = 16 + 20*4;
4229 if (cfg->method->save_lmf)
4230 max_epilog_size += 128;
4232 if (mono_jit_trace_calls != NULL)
4233 max_epilog_size += 50;
4235 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4236 max_epilog_size += 50;
4238 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4239 cfg->code_size *= 2;
4240 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4241 mono_jit_stats.code_reallocs++;
4245 * Keep in sync with OP_JMP
4247 code = cfg->native_code + cfg->code_len;
4249 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4250 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4254 if (method->save_lmf) {
4256 pos += sizeof (MonoLMF);
4258 /* save the frame reg in r8 */
4259 ppc_mr (code, ppc_r8, cfg->frame_reg);
4260 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4261 /* r5 = previous_lmf */
4262 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4264 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4265 /* *(lmf_addr) = previous_lmf */
4266 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4267 /* FIXME: speedup: there is no actual need to restore the registers if
4268 * we didn't actually change them (idea from Zoltan).
4271 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4273 /*for (i = 14; i < 32; i++) {
4274 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4276 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4277 /* use the saved copy of the frame reg in r8 */
4278 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4279 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4280 ppc_mtlr (code, ppc_r0);
4282 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4284 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4285 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4286 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4288 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4289 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4291 ppc_mtlr (code, ppc_r0);
4293 if (ppc_is_imm16 (cfg->stack_usage)) {
4294 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4296 ppc_load (code, ppc_r11, cfg->stack_usage);
4297 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4300 /*for (i = 31; i >= 14; --i) {
4301 if (cfg->used_float_regs & (1 << i)) {
4302 pos += sizeof (double);
4303 ppc_lfd (code, i, -pos, ppc_sp);
4306 for (i = 31; i >= 13; --i) {
4307 if (cfg->used_int_regs & (1 << i)) {
4308 pos += sizeof (gulong);
4309 ppc_lwz (code, i, -pos, ppc_sp);
4315 cfg->code_len = code - cfg->native_code;
4317 g_assert (cfg->code_len < cfg->code_size);
4321 /* remove once throw_exception_by_name is eliminated */
4323 exception_id_by_name (const char *name)
4325 if (strcmp (name, "IndexOutOfRangeException") == 0)
4326 return MONO_EXC_INDEX_OUT_OF_RANGE;
4327 if (strcmp (name, "OverflowException") == 0)
4328 return MONO_EXC_OVERFLOW;
4329 if (strcmp (name, "ArithmeticException") == 0)
4330 return MONO_EXC_ARITHMETIC;
4331 if (strcmp (name, "DivideByZeroException") == 0)
4332 return MONO_EXC_DIVIDE_BY_ZERO;
4333 if (strcmp (name, "InvalidCastException") == 0)
4334 return MONO_EXC_INVALID_CAST;
4335 if (strcmp (name, "NullReferenceException") == 0)
4336 return MONO_EXC_NULL_REF;
4337 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4338 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4339 g_error ("Unknown intrinsic exception %s\n", name);
4344 mono_arch_emit_exceptions (MonoCompile *cfg)
4346 MonoJumpInfo *patch_info;
4349 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4350 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4351 int max_epilog_size = 50;
4353 /* count the number of exception infos */
4356 * make sure we have enough space for exceptions
4357 * 24 is the simulated call to throw_exception_by_name
4359 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4360 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4361 i = exception_id_by_name (patch_info->data.target);
4362 if (!exc_throw_found [i]) {
4363 max_epilog_size += 24;
4364 exc_throw_found [i] = TRUE;
4366 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4367 max_epilog_size += 12;
4368 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4369 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4370 i = exception_id_by_name (ovfj->data.exception);
4371 if (!exc_throw_found [i]) {
4372 max_epilog_size += 24;
4373 exc_throw_found [i] = TRUE;
4375 max_epilog_size += 8;
4379 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4380 cfg->code_size *= 2;
4381 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4382 mono_jit_stats.code_reallocs++;
4385 code = cfg->native_code + cfg->code_len;
4387 /* add code to raise exceptions */
4388 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4389 switch (patch_info->type) {
4390 case MONO_PATCH_INFO_BB_OVF: {
4391 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4392 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4393 /* patch the initial jump */
4394 ppc_patch (ip, code);
4395 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4397 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4398 /* jump back to the true target */
4400 ip = ovfj->data.bb->native_offset + cfg->native_code;
4401 ppc_patch (code - 4, ip);
4404 case MONO_PATCH_INFO_EXC_OVF: {
4405 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4406 MonoJumpInfo *newji;
4407 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4408 unsigned char *bcl = code;
4409 /* patch the initial jump: we arrived here with a call */
4410 ppc_patch (ip, code);
4411 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4413 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4414 /* patch the conditional jump to the right handler */
4415 /* make it processed next */
4416 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4417 newji->type = MONO_PATCH_INFO_EXC;
4418 newji->ip.i = bcl - cfg->native_code;
4419 newji->data.target = ovfj->data.exception;
4420 newji->next = patch_info->next;
4421 patch_info->next = newji;
4424 case MONO_PATCH_INFO_EXC: {
4425 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4426 i = exception_id_by_name (patch_info->data.target);
4427 if (exc_throw_pos [i]) {
4428 ppc_patch (ip, exc_throw_pos [i]);
4429 patch_info->type = MONO_PATCH_INFO_NONE;
4432 exc_throw_pos [i] = code;
4434 ppc_patch (ip, code);
4435 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4436 ppc_load (code, ppc_r3, patch_info->data.target);
4437 /* we got here from a conditional call, so the calling ip is set in lr already */
4438 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4439 patch_info->data.name = "mono_arch_throw_exception_by_name";
4440 patch_info->ip.i = code - cfg->native_code;
4441 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4442 ppc_lis (code, ppc_r0, 0);
4443 ppc_ori (code, ppc_r0, ppc_r0, 0);
4444 ppc_mtctr (code, ppc_r0);
4445 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4457 cfg->code_len = code - cfg->native_code;
4459 g_assert (cfg->code_len < cfg->code_size);
4464 try_offset_access (void *value, guint32 idx)
4466 register void* me __asm__ ("r2");
4467 void ***p = (void***)((char*)me + 284);
4468 int idx1 = idx / 32;
4469 int idx2 = idx % 32;
4472 if (value != p[idx1][idx2])
4478 setup_tls_access (void)
4481 guint32 *ins, *code;
4482 guint32 cmplwi_1023, li_0x48, blr_ins;
4483 if (tls_mode == TLS_MODE_FAILED)
4486 if (g_getenv ("MONO_NO_TLS")) {
4487 tls_mode = TLS_MODE_FAILED;
4491 if (tls_mode == TLS_MODE_DETECT) {
4492 ins = (guint32*)pthread_getspecific;
4493 /* uncond branch to the real method */
4494 if ((*ins >> 26) == 18) {
4496 val = (*ins & ~3) << 6;
4500 ins = (guint32*)val;
4502 ins = (guint32*) ((char*)ins + val);
4505 code = &cmplwi_1023;
4506 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4508 ppc_li (code, ppc_r4, 0x48);
4511 if (*ins == cmplwi_1023) {
4512 int found_lwz_284 = 0;
4513 for (ptk = 0; ptk < 20; ++ptk) {
4515 if (!*ins || *ins == blr_ins)
4517 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4522 if (!found_lwz_284) {
4523 tls_mode = TLS_MODE_FAILED;
4526 tls_mode = TLS_MODE_LTHREADS;
4527 } else if (*ins == li_0x48) {
4529 /* uncond branch to the real method */
4530 if ((*ins >> 26) == 18) {
4532 val = (*ins & ~3) << 6;
4536 ins = (guint32*)val;
4538 ins = (guint32*) ((char*)ins + val);
4540 code = (guint32*)&val;
4541 ppc_li (code, ppc_r0, 0x7FF2);
4542 if (ins [1] == val) {
4543 /* Darwin on G4, implement */
4544 tls_mode = TLS_MODE_FAILED;
4547 code = (guint32*)&val;
4548 ppc_mfspr (code, ppc_r3, 104);
4549 if (ins [1] != val) {
4550 tls_mode = TLS_MODE_FAILED;
4553 tls_mode = TLS_MODE_DARWIN_G5;
4556 tls_mode = TLS_MODE_FAILED;
4560 tls_mode = TLS_MODE_FAILED;
4564 if (monodomain_key == -1) {
4565 ptk = mono_domain_get_tls_key ();
4567 ptk = mono_pthread_key_for_tls (ptk);
4569 monodomain_key = ptk;
4573 if (lmf_pthread_key == -1) {
4574 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4576 /*g_print ("MonoLMF at: %d\n", ptk);*/
4577 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4578 init_tls_failed = 1;
4581 lmf_pthread_key = ptk;
4584 if (monothread_key == -1) {
4585 ptk = mono_thread_get_tls_key ();
4587 ptk = mono_pthread_key_for_tls (ptk);
4589 monothread_key = ptk;
4590 /*g_print ("thread inited: %d\n", ptk);*/
4593 /*g_print ("thread not inited yet %d\n", ptk);*/
4599 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4601 setup_tls_access ();
4605 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4610 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4612 int this_dreg = ppc_r3;
4617 /* add the this argument */
4618 if (this_reg != -1) {
4620 MONO_INST_NEW (cfg, this, OP_MOVE);
4621 this->type = this_type;
4622 this->sreg1 = this_reg;
4623 this->dreg = mono_regstate_next_int (cfg->rs);
4624 mono_bblock_add_inst (cfg->cbb, this);
4625 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4630 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4631 vtarg->type = STACK_MP;
4632 vtarg->sreg1 = vt_reg;
4633 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4634 mono_bblock_add_inst (cfg->cbb, vtarg);
4635 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4639 #ifdef MONO_ARCH_HAVE_IMT
4643 #define JUMP_IMM_SIZE 12
4644 #define ENABLE_WRONG_METHOD_CHECK 0
4647 * LOCKING: called with the domain lock held
4650 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4654 guint8 *code, *start;
4656 for (i = 0; i < count; ++i) {
4657 MonoIMTCheckItem *item = imt_entries [i];
4658 if (item->is_equals) {
4659 if (item->check_target_idx) {
4660 if (!item->compare_done)
4661 item->chunk_size += CMP_SIZE;
4662 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4664 item->chunk_size += JUMP_IMM_SIZE;
4665 #if ENABLE_WRONG_METHOD_CHECK
4666 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4670 item->chunk_size += CMP_SIZE + BR_SIZE;
4671 imt_entries [item->check_target_idx]->compare_done = TRUE;
4673 size += item->chunk_size;
4675 /* the initial load of the vtable address */
4677 code = mono_code_manager_reserve (domain->code_mp, size);
4679 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4680 for (i = 0; i < count; ++i) {
4681 MonoIMTCheckItem *item = imt_entries [i];
4682 item->code_target = code;
4683 if (item->is_equals) {
4684 if (item->check_target_idx) {
4685 if (!item->compare_done) {
4686 ppc_load (code, ppc_r0, (guint32)item->method);
4687 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4689 item->jmp_code = code;
4690 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4691 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4692 ppc_mtctr (code, ppc_r0);
4693 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4695 /* enable the commented code to assert on wrong method */
4696 #if ENABLE_WRONG_METHOD_CHECK
4697 ppc_load (code, ppc_r0, (guint32)item->method);
4698 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4699 item->jmp_code = code;
4700 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4702 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4703 ppc_mtctr (code, ppc_r0);
4704 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4705 #if ENABLE_WRONG_METHOD_CHECK
4706 ppc_patch (item->jmp_code, code);
4708 item->jmp_code = NULL;
4712 ppc_load (code, ppc_r0, (guint32)item->method);
4713 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4714 item->jmp_code = code;
4715 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4718 /* patch the branches to get to the target items */
4719 for (i = 0; i < count; ++i) {
4720 MonoIMTCheckItem *item = imt_entries [i];
4721 if (item->jmp_code) {
4722 if (item->check_target_idx) {
4723 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4728 mono_stats.imt_thunks_size += code - start;
4729 g_assert (code - start <= size);
4730 mono_arch_flush_icache (start, size);
4735 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4737 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4741 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4743 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4748 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4750 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4754 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4756 MonoInst *ins = NULL;
4758 /*if (cmethod->klass == mono_defaults.math_class) {
4759 if (strcmp (cmethod->name, "Sqrt") == 0) {
4760 MONO_INST_NEW (cfg, ins, OP_SQRT);
4761 ins->inst_i0 = args [0];
4768 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4775 mono_arch_print_tree (MonoInst *tree, int arity)
4780 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4784 setup_tls_access ();
4785 if (monodomain_key == -1)
4788 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4789 ins->inst_offset = monodomain_key;
4794 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4798 setup_tls_access ();
4799 if (monothread_key == -1)
4802 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4803 ins->inst_offset = monothread_key;
4808 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4810 g_assert (reg >= ppc_r13);
4812 return (gpointer)ctx->regs [reg - ppc_r13];