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], &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 = mono_type_get_underlying_type (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) {
582 mib [1] = HW_CACHELINE;
583 len = sizeof (cachelinesize);
584 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
588 cachelineinc = cachelinesize;
589 /*g_print ("setting cl size to %d\n", cachelinesize);*/
591 #elif defined(__linux__)
592 /* sadly this will work only with 2.6 kernels... */
593 FILE* f = fopen ("/proc/self/auxv", "rb");
596 while (fread (&vec, sizeof (vec), 1, f) == 1) {
597 if (vec.type == 19) {
598 cachelinesize = vec.value;
607 #warning Need a way to get cache line size
613 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
614 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
616 for (p = start; p < endp; p += cachelineinc) {
617 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
620 for (p = start; p < endp; p += cachelineinc) {
621 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
626 for (p = start; p < endp; p += cachelineinc) {
627 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
634 mono_arch_flush_register_windows (void)
639 #define ALWAYS_ON_STACK(s) s
640 #define FP_ALSO_IN_REG(s) s
642 #define ALWAYS_ON_STACK(s)
643 #define FP_ALSO_IN_REG(s)
644 #define ALIGN_DOUBLES
657 guint32 vtsize; /* in param area */
659 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
660 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
675 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
678 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
679 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
680 ainfo->reg = ppc_sp; /* in the caller */
681 ainfo->regtype = RegTypeBase;
684 ALWAYS_ON_STACK (*stack_size += 4);
688 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
690 //*stack_size += (*stack_size % 8);
692 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
693 ainfo->reg = ppc_sp; /* in the caller */
694 ainfo->regtype = RegTypeBase;
701 ALWAYS_ON_STACK (*stack_size += 8);
711 has_only_a_r48_field (MonoClass *klass)
715 gboolean have_field = FALSE;
717 while ((f = mono_class_get_fields (klass, &iter))) {
718 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
721 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
732 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
735 int n = sig->hasthis + sig->param_count;
737 guint32 stack_size = 0;
738 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
740 fr = PPC_FIRST_FPARG_REG;
741 gr = PPC_FIRST_ARG_REG;
743 /* FIXME: handle returning a struct */
744 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
745 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
746 cinfo->struct_ret = PPC_FIRST_ARG_REG;
751 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
754 DEBUG(printf("params: %d\n", sig->param_count));
755 for (i = 0; i < sig->param_count; ++i) {
756 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
757 /* Prevent implicit arguments and sig_cookie from
758 being passed in registers */
759 gr = PPC_LAST_ARG_REG + 1;
760 /* FIXME: don't we have to set fr, too? */
761 /* Emit the signature cookie just before the implicit arguments */
762 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
764 DEBUG(printf("param %d: ", i));
765 if (sig->params [i]->byref) {
766 DEBUG(printf("byref\n"));
767 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
771 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
772 switch (simpletype) {
773 case MONO_TYPE_BOOLEAN:
776 cinfo->args [n].size = 1;
777 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
783 cinfo->args [n].size = 2;
784 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
789 cinfo->args [n].size = 4;
790 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
796 case MONO_TYPE_FNPTR:
797 case MONO_TYPE_CLASS:
798 case MONO_TYPE_OBJECT:
799 case MONO_TYPE_STRING:
800 case MONO_TYPE_SZARRAY:
801 case MONO_TYPE_ARRAY:
802 cinfo->args [n].size = sizeof (gpointer);
803 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
806 case MONO_TYPE_GENERICINST:
807 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
808 cinfo->args [n].size = sizeof (gpointer);
809 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
814 case MONO_TYPE_VALUETYPE: {
817 klass = mono_class_from_mono_type (sig->params [i]);
819 size = mono_class_native_size (klass, NULL);
821 size = mono_class_value_size (klass, NULL);
823 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
824 cinfo->args [n].size = size;
826 /* It was 7, now it is 8 in LinuxPPC */
827 if (fr <= PPC_LAST_FPARG_REG) {
828 cinfo->args [n].regtype = RegTypeFP;
829 cinfo->args [n].reg = fr;
831 FP_ALSO_IN_REG (gr ++);
833 FP_ALSO_IN_REG (gr ++);
834 ALWAYS_ON_STACK (stack_size += size);
836 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
837 cinfo->args [n].regtype = RegTypeBase;
838 cinfo->args [n].reg = ppc_sp; /* in the caller*/
845 DEBUG(printf ("load %d bytes struct\n",
846 mono_class_native_size (sig->params [i]->data.klass, NULL)));
847 #if PPC_PASS_STRUCTS_BY_VALUE
849 int align_size = size;
851 int rest = PPC_LAST_ARG_REG - gr + 1;
853 align_size += (sizeof (gpointer) - 1);
854 align_size &= ~(sizeof (gpointer) - 1);
855 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
856 n_in_regs = rest >= nwords? nwords: rest;
857 cinfo->args [n].regtype = RegTypeStructByVal;
858 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
859 cinfo->args [n].size = 0;
860 cinfo->args [n].vtsize = nwords;
862 cinfo->args [n].size = n_in_regs;
863 cinfo->args [n].vtsize = nwords - n_in_regs;
864 cinfo->args [n].reg = gr;
867 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
868 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
869 stack_size += nwords * sizeof (gpointer);
872 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
873 cinfo->args [n].regtype = RegTypeStructByAddr;
874 cinfo->args [n].vtsize = size;
879 case MONO_TYPE_TYPEDBYREF: {
880 int size = sizeof (MonoTypedRef);
881 /* keep in sync or merge with the valuetype case */
882 #if PPC_PASS_STRUCTS_BY_VALUE
884 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
885 cinfo->args [n].regtype = RegTypeStructByVal;
886 if (gr <= PPC_LAST_ARG_REG) {
887 int rest = PPC_LAST_ARG_REG - gr + 1;
888 int n_in_regs = rest >= nwords? nwords: rest;
889 cinfo->args [n].size = n_in_regs;
890 cinfo->args [n].vtsize = nwords - n_in_regs;
891 cinfo->args [n].reg = gr;
894 cinfo->args [n].size = 0;
895 cinfo->args [n].vtsize = nwords;
897 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
898 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
899 stack_size += nwords * sizeof (gpointer);
902 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
903 cinfo->args [n].regtype = RegTypeStructByAddr;
904 cinfo->args [n].vtsize = size;
911 cinfo->args [n].size = 8;
912 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
916 cinfo->args [n].size = 4;
918 /* It was 7, now it is 8 in LinuxPPC */
919 if (fr <= PPC_LAST_FPARG_REG) {
920 cinfo->args [n].regtype = RegTypeFP;
921 cinfo->args [n].reg = fr;
923 FP_ALSO_IN_REG (gr ++);
924 ALWAYS_ON_STACK (stack_size += 4);
926 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
927 cinfo->args [n].regtype = RegTypeBase;
928 cinfo->args [n].reg = ppc_sp; /* in the caller*/
934 cinfo->args [n].size = 8;
935 /* It was 7, now it is 8 in LinuxPPC */
936 if (fr <= PPC_LAST_FPARG_REG) {
937 cinfo->args [n].regtype = RegTypeFP;
938 cinfo->args [n].reg = fr;
940 FP_ALSO_IN_REG (gr += 2);
941 ALWAYS_ON_STACK (stack_size += 8);
943 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
944 cinfo->args [n].regtype = RegTypeBase;
945 cinfo->args [n].reg = ppc_sp; /* in the caller*/
951 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
955 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
956 /* Prevent implicit arguments and sig_cookie from
957 being passed in registers */
958 gr = PPC_LAST_ARG_REG + 1;
959 /* Emit the signature cookie just before the implicit arguments */
960 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
964 simpletype = mono_type_get_underlying_type (sig->ret)->type;
965 switch (simpletype) {
966 case MONO_TYPE_BOOLEAN:
977 case MONO_TYPE_FNPTR:
978 case MONO_TYPE_CLASS:
979 case MONO_TYPE_OBJECT:
980 case MONO_TYPE_SZARRAY:
981 case MONO_TYPE_ARRAY:
982 case MONO_TYPE_STRING:
983 cinfo->ret.reg = ppc_r3;
987 cinfo->ret.reg = ppc_r3;
991 cinfo->ret.reg = ppc_f1;
992 cinfo->ret.regtype = RegTypeFP;
994 case MONO_TYPE_GENERICINST:
995 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
996 cinfo->ret.reg = ppc_r3;
1000 case MONO_TYPE_VALUETYPE:
1002 case MONO_TYPE_TYPEDBYREF:
1003 case MONO_TYPE_VOID:
1006 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1010 /* align stack size to 16 */
1011 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1012 stack_size = (stack_size + 15) & ~15;
1014 cinfo->stack_usage = stack_size;
1019 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1021 #if !PPC_PASS_STRUCTS_BY_VALUE
1022 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1023 int num_structs = 0;
1026 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1029 for (i = 0; i < sig->param_count; ++i) {
1030 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1031 if (type->type == MONO_TYPE_VALUETYPE)
1036 cfg->tailcall_valuetype_addrs =
1037 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1038 for (i = 0; i < num_structs; ++i) {
1039 cfg->tailcall_valuetype_addrs [i] =
1040 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1041 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1048 * Set var information according to the calling convention. ppc version.
1049 * The locals var stuff should most likely be split in another method.
1052 mono_arch_allocate_vars (MonoCompile *m)
1054 MonoMethodSignature *sig;
1055 MonoMethodHeader *header;
1057 int i, offset, size, align, curinst;
1058 int frame_reg = ppc_sp;
1060 guint32 locals_stack_size, locals_stack_align;
1062 allocate_tailcall_valuetype_addrs (m);
1064 m->flags |= MONO_CFG_HAS_SPILLUP;
1066 /* allow room for the vararg method args: void* and long/double */
1067 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1068 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1069 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1070 * call convs needs to be handled this way.
1072 if (m->flags & MONO_CFG_HAS_VARARGS)
1073 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1074 /* gtk-sharp and other broken code will dllimport vararg functions even with
1075 * non-varargs signatures. Since there is little hope people will get this right
1076 * we assume they won't.
1078 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1079 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1081 header = mono_method_get_header (m->method);
1084 * We use the frame register also for any method that has
1085 * exception clauses. This way, when the handlers are called,
1086 * the code will reference local variables using the frame reg instead of
1087 * the stack pointer: if we had to restore the stack pointer, we'd
1088 * corrupt the method frames that are already on the stack (since
1089 * filters get called before stack unwinding happens) when the filter
1090 * code would call any method (this also applies to finally etc.).
1092 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1093 frame_reg = ppc_r31;
1094 m->frame_reg = frame_reg;
1095 if (frame_reg != ppc_sp) {
1096 m->used_int_regs |= 1 << frame_reg;
1099 sig = mono_method_signature (m->method);
1103 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1104 m->ret->opcode = OP_REGVAR;
1105 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1107 /* FIXME: handle long values? */
1108 switch (mono_type_get_underlying_type (sig->ret)->type) {
1109 case MONO_TYPE_VOID:
1113 m->ret->opcode = OP_REGVAR;
1114 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1117 m->ret->opcode = OP_REGVAR;
1118 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1122 /* local vars are at a positive offset from the stack pointer */
1124 * also note that if the function uses alloca, we use ppc_r31
1125 * to point at the local variables.
1127 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1128 /* align the offset to 16 bytes: not sure this is needed here */
1130 //offset &= ~(16 - 1);
1132 /* add parameter area size for called functions */
1133 offset += m->param_area;
1135 offset &= ~(16 - 1);
1137 /* allow room to save the return value */
1138 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1141 /* the MonoLMF structure is stored just below the stack pointer */
1144 /* this stuff should not be needed on ppc and the new jit,
1145 * because a call on ppc to the handlers doesn't change the
1146 * stack pointer and the jist doesn't manipulate the stack pointer
1147 * for operations involving valuetypes.
1149 /* reserve space to store the esp */
1150 offset += sizeof (gpointer);
1152 /* this is a global constant */
1153 mono_exc_esp_offset = offset;
1155 if (sig->call_convention == MONO_CALL_VARARG) {
1156 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1159 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1160 offset += sizeof(gpointer) - 1;
1161 offset &= ~(sizeof(gpointer) - 1);
1164 m->vret_addr->opcode = OP_REGOFFSET;
1165 m->vret_addr->inst_basereg = frame_reg;
1166 m->vret_addr->inst_offset = offset;
1168 if (G_UNLIKELY (m->verbose_level > 1)) {
1169 printf ("vret_addr =");
1170 mono_print_ins (m->vret_addr);
1174 inst->inst_offset = offset;
1175 inst->opcode = OP_REGOFFSET;
1176 inst->inst_basereg = frame_reg;
1179 offset += sizeof(gpointer);
1180 if (sig->call_convention == MONO_CALL_VARARG)
1181 m->sig_cookie += sizeof (gpointer);
1184 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1185 if (locals_stack_align) {
1186 offset += (locals_stack_align - 1);
1187 offset &= ~(locals_stack_align - 1);
1189 for (i = m->locals_start; i < m->num_varinfo; i++) {
1190 if (offsets [i] != -1) {
1191 MonoInst *inst = m->varinfo [i];
1192 inst->opcode = OP_REGOFFSET;
1193 inst->inst_basereg = frame_reg;
1194 inst->inst_offset = offset + offsets [i];
1196 g_print ("allocating local %d (%s) to %d\n",
1197 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1201 offset += locals_stack_size;
1205 inst = m->args [curinst];
1206 if (inst->opcode != OP_REGVAR) {
1207 inst->opcode = OP_REGOFFSET;
1208 inst->inst_basereg = frame_reg;
1209 offset += sizeof (gpointer) - 1;
1210 offset &= ~(sizeof (gpointer) - 1);
1211 inst->inst_offset = offset;
1212 offset += sizeof (gpointer);
1213 if (sig->call_convention == MONO_CALL_VARARG)
1214 m->sig_cookie += sizeof (gpointer);
1219 for (i = 0; i < sig->param_count; ++i) {
1220 inst = m->args [curinst];
1221 if (inst->opcode != OP_REGVAR) {
1222 inst->opcode = OP_REGOFFSET;
1223 inst->inst_basereg = frame_reg;
1225 size = mono_type_native_stack_size (sig->params [i], &align);
1226 inst->backend.is_pinvoke = 1;
1228 size = mono_type_size (sig->params [i], &align);
1230 offset += align - 1;
1231 offset &= ~(align - 1);
1232 inst->inst_offset = offset;
1234 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1235 m->sig_cookie += size;
1240 /* align the offset to 16 bytes */
1242 offset &= ~(16 - 1);
1245 m->stack_offset = offset;
1247 if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1248 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1250 m->sig_cookie = cinfo->sig_cookie.offset;
1257 mono_arch_create_vars (MonoCompile *cfg)
1259 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1261 if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1262 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1266 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1267 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1271 * take the arguments and generate the arch-specific
1272 * instructions to properly call the function in call.
1273 * This includes pushing, moving arguments to the right register
1275 * Issue: who does the spilling if needed, and when?
1278 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1280 MonoMethodSignature *sig;
1285 sig = call->signature;
1286 n = sig->param_count + sig->hasthis;
1288 cinfo = calculate_sizes (sig, sig->pinvoke);
1289 if (cinfo->struct_ret)
1290 call->used_iregs |= 1 << cinfo->struct_ret;
1292 for (i = 0; i < n; ++i) {
1293 ainfo = cinfo->args + i;
1294 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1296 cfg->disable_aot = TRUE;
1298 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1299 sig_arg->inst_p0 = call->signature;
1301 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1302 arg->inst_imm = cinfo->sig_cookie.offset;
1303 arg->inst_left = sig_arg;
1304 arg->inst_call = call;
1305 /* prepend, so they get reversed */
1306 arg->next = call->out_args;
1307 call->out_args = arg;
1309 if (is_virtual && i == 0) {
1310 /* the argument will be attached to the call instrucion */
1311 in = call->args [i];
1312 call->used_iregs |= 1 << ainfo->reg;
1314 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1315 in = call->args [i];
1316 arg->cil_code = in->cil_code;
1317 arg->inst_left = in;
1318 arg->inst_call = call;
1319 arg->type = in->type;
1320 /* prepend, so they get reversed */
1321 arg->next = call->out_args;
1322 call->out_args = arg;
1323 if (ainfo->regtype == RegTypeGeneral) {
1324 arg->backend.reg3 = ainfo->reg;
1325 call->used_iregs |= 1 << ainfo->reg;
1326 if (arg->type == STACK_I8)
1327 call->used_iregs |= 1 << (ainfo->reg + 1);
1328 } else if (ainfo->regtype == RegTypeStructByAddr) {
1329 if (ainfo->offset) {
1330 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1331 arg->opcode = OP_OUTARG_MEMBASE;
1332 ai->reg = ainfo->reg;
1333 ai->size = sizeof (gpointer);
1334 ai->offset = ainfo->offset;
1335 arg->backend.data = ai;
1337 arg->backend.reg3 = ainfo->reg;
1338 call->used_iregs |= 1 << ainfo->reg;
1340 } else if (ainfo->regtype == RegTypeStructByVal) {
1342 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1343 /* mark the used regs */
1344 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1345 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1347 arg->opcode = OP_OUTARG_VT;
1348 ai->reg = ainfo->reg;
1349 ai->size = ainfo->size;
1350 ai->vtsize = ainfo->vtsize;
1351 ai->offset = ainfo->offset;
1352 arg->backend.data = ai;
1353 } else if (ainfo->regtype == RegTypeBase) {
1354 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1355 arg->opcode = OP_OUTARG_MEMBASE;
1356 ai->reg = ainfo->reg;
1357 ai->size = ainfo->size;
1358 ai->offset = ainfo->offset;
1359 arg->backend.data = ai;
1360 } else if (ainfo->regtype == RegTypeFP) {
1361 arg->opcode = OP_OUTARG_R8;
1362 arg->backend.reg3 = ainfo->reg;
1363 call->used_fregs |= 1 << ainfo->reg;
1364 if (ainfo->size == 4) {
1365 arg->opcode = OP_OUTARG_R8;
1366 /* we reduce the precision */
1368 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1369 conv->inst_left = arg->inst_left;
1370 arg->inst_left = conv;*/
1373 g_assert_not_reached ();
1378 * Reverse the call->out_args list.
1381 MonoInst *prev = NULL, *list = call->out_args, *next;
1388 call->out_args = prev;
1391 call->stack_usage = cinfo->stack_usage;
1392 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1393 cfg->flags |= MONO_CFG_HAS_CALLS;
1395 * should set more info in call, such as the stack space
1396 * used by the args that needs to be added back to esp
1404 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1406 int sig_reg = mono_alloc_ireg (cfg);
1408 MONO_EMIT_NEW_ICONST (cfg, sig_reg, call->signature);
1409 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1410 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1414 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1417 MonoMethodSignature *sig;
1421 sig = call->signature;
1422 n = sig->param_count + sig->hasthis;
1424 cinfo = calculate_sizes (sig, sig->pinvoke);
1426 for (i = 0; i < n; ++i) {
1427 ArgInfo *ainfo = cinfo->args + i;
1430 if (i >= sig->hasthis)
1431 t = sig->params [i - sig->hasthis];
1433 t = &mono_defaults.int_class->byval_arg;
1434 t = mono_type_get_underlying_type (t);
1436 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1437 emit_sig_cookie (cfg, call, cinfo);
1439 in = call->args [i];
1441 if (ainfo->regtype == RegTypeGeneral) {
1442 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1443 MONO_INST_NEW (cfg, ins, OP_MOVE);
1444 ins->dreg = mono_alloc_ireg (cfg);
1445 ins->sreg1 = in->dreg + 1;
1446 MONO_ADD_INS (cfg->cbb, ins);
1447 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1449 MONO_INST_NEW (cfg, ins, OP_MOVE);
1450 ins->dreg = mono_alloc_ireg (cfg);
1451 ins->sreg1 = in->dreg + 2;
1452 MONO_ADD_INS (cfg->cbb, ins);
1453 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1455 MONO_INST_NEW (cfg, ins, OP_MOVE);
1456 ins->dreg = mono_alloc_ireg (cfg);
1457 ins->sreg1 = in->dreg;
1458 MONO_ADD_INS (cfg->cbb, ins);
1460 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1462 } else if (ainfo->regtype == RegTypeStructByAddr) {
1463 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1464 ins->opcode = OP_OUTARG_VT;
1465 ins->sreg1 = in->dreg;
1466 ins->klass = in->klass;
1467 ins->inst_p0 = call;
1468 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1469 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1470 MONO_ADD_INS (cfg->cbb, ins);
1471 } else if (ainfo->regtype == RegTypeStructByVal) {
1472 /* this is further handled in mono_arch_emit_outarg_vt () */
1473 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1474 ins->opcode = OP_OUTARG_VT;
1475 ins->sreg1 = in->dreg;
1476 ins->klass = in->klass;
1477 ins->inst_p0 = call;
1478 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1479 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1480 MONO_ADD_INS (cfg->cbb, ins);
1481 } else if (ainfo->regtype == RegTypeBase) {
1482 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1483 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1484 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1485 if (t->type == MONO_TYPE_R8)
1486 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1488 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1490 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1492 } else if (ainfo->regtype == RegTypeFP) {
1493 if (t->type == MONO_TYPE_VALUETYPE) {
1494 /* this is further handled in mono_arch_emit_outarg_vt () */
1495 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1496 ins->opcode = OP_OUTARG_VT;
1497 ins->sreg1 = in->dreg;
1498 ins->klass = in->klass;
1499 ins->inst_p0 = call;
1500 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1501 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1502 MONO_ADD_INS (cfg->cbb, ins);
1504 cfg->flags |= MONO_CFG_HAS_FPOUT;
1506 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1507 ins->dreg = mono_alloc_freg (cfg);
1508 ins->sreg1 = in->dreg;
1509 MONO_ADD_INS (cfg->cbb, ins);
1511 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
1512 cfg->flags |= MONO_CFG_HAS_FPOUT;
1515 g_assert_not_reached ();
1519 /* Emit the signature cookie in the case that there is no
1520 additional argument */
1521 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1522 emit_sig_cookie (cfg, call, cinfo);
1524 if (cinfo->struct_ret) {
1527 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1528 vtarg->sreg1 = call->vret_var->dreg;
1529 vtarg->dreg = mono_alloc_preg (cfg);
1530 MONO_ADD_INS (cfg->cbb, vtarg);
1532 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1535 call->stack_usage = cinfo->stack_usage;
1536 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1537 cfg->flags |= MONO_CFG_HAS_CALLS;
1543 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1545 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1546 ArgInfo *ainfo = ins->inst_p1;
1547 int ovf_size = ainfo->vtsize;
1548 int doffset = ainfo->offset;
1549 int i, soffset, dreg;
1551 if (ainfo->regtype == RegTypeStructByVal) {
1555 Darwin needs some special handling for 1 and 2 byte arguments
1558 g_assert (ins->klass);
1559 size = mono_class_native_size (ins->klass, NULL);
1560 if (size == 2 || size == 1) {
1561 int tmpr = mono_alloc_ireg (cfg);
1563 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1565 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1566 dreg = mono_alloc_ireg (cfg);
1567 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1568 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1571 for (i = 0; i < ainfo->size; ++i) {
1572 dreg = mono_alloc_ireg (cfg);
1573 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1574 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1575 soffset += sizeof (gpointer);
1578 mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1579 } else if (ainfo->regtype == RegTypeFP) {
1580 int tmpr = mono_alloc_freg (cfg);
1581 if (ainfo->size == 4)
1582 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1584 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1585 dreg = mono_alloc_freg (cfg);
1586 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1587 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1589 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1593 /* FIXME: alignment? */
1594 if (call->signature->pinvoke) {
1595 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1596 vtcopy->backend.is_pinvoke = 1;
1598 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1601 g_assert (ovf_size > 0);
1603 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1604 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1607 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1609 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1614 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1616 MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
1619 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1622 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1623 ins->sreg1 = val->dreg + 1;
1624 ins->sreg2 = val->dreg + 2;
1625 MONO_ADD_INS (cfg->cbb, ins);
1628 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1629 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1633 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1636 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1638 mono_arch_is_inst_imm (gint64 imm)
1644 * Allow tracing to work with this interface (with an optional argument)
1648 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1652 ppc_load (code, ppc_r3, cfg->method);
1653 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1654 ppc_load (code, ppc_r0, func);
1655 ppc_mtlr (code, ppc_r0);
1669 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1672 int save_mode = SAVE_NONE;
1674 MonoMethod *method = cfg->method;
1675 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1676 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1680 offset = code - cfg->native_code;
1681 /* we need about 16 instructions */
1682 if (offset > (cfg->code_size - 16 * 4)) {
1683 cfg->code_size *= 2;
1684 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1685 code = cfg->native_code + offset;
1689 case MONO_TYPE_VOID:
1690 /* special case string .ctor icall */
1691 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1692 save_mode = SAVE_ONE;
1694 save_mode = SAVE_NONE;
1698 save_mode = SAVE_TWO;
1702 save_mode = SAVE_FP;
1704 case MONO_TYPE_VALUETYPE:
1705 save_mode = SAVE_STRUCT;
1708 save_mode = SAVE_ONE;
1712 switch (save_mode) {
1714 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1715 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1716 if (enable_arguments) {
1717 ppc_mr (code, ppc_r5, ppc_r4);
1718 ppc_mr (code, ppc_r4, ppc_r3);
1722 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1723 if (enable_arguments) {
1724 ppc_mr (code, ppc_r4, ppc_r3);
1728 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1729 if (enable_arguments) {
1730 /* FIXME: what reg? */
1731 ppc_fmr (code, ppc_f3, ppc_f1);
1732 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1733 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1737 if (enable_arguments) {
1738 /* FIXME: get the actual address */
1739 ppc_mr (code, ppc_r4, ppc_r3);
1747 ppc_load (code, ppc_r3, cfg->method);
1748 ppc_load (code, ppc_r0, func);
1749 ppc_mtlr (code, ppc_r0);
1752 switch (save_mode) {
1754 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1755 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1758 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1761 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1771 * Conditional branches have a small offset, so if it is likely overflowed,
1772 * we do a branch to the end of the method (uncond branches have much larger
1773 * offsets) where we perform the conditional and jump back unconditionally.
1774 * It's slightly slower, since we add two uncond branches, but it's very simple
1775 * with the current patch implementation and such large methods are likely not
1776 * going to be perf critical anyway.
1781 const char *exception;
1788 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1789 if (ins->flags & MONO_INST_BRLABEL) { \
1790 if (0 && ins->inst_i0->inst_c0) { \
1791 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1793 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1794 ppc_bc (code, (b0), (b1), 0); \
1797 if (0 && ins->inst_true_bb->native_offset) { \
1798 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1800 int br_disp = ins->inst_true_bb->max_offset - offset; \
1801 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1802 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1803 ovfj->data.bb = ins->inst_true_bb; \
1804 ovfj->ip_offset = 0; \
1805 ovfj->b0_cond = (b0); \
1806 ovfj->b1_cond = (b1); \
1807 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1810 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1811 ppc_bc (code, (b0), (b1), 0); \
1816 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1818 /* emit an exception if condition is fail
1820 * We assign the extra code used to throw the implicit exceptions
1821 * to cfg->bb_exit as far as the big branch handling is concerned
1823 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1825 int br_disp = cfg->bb_exit->max_offset - offset; \
1826 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1827 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1828 ovfj->data.exception = (exc_name); \
1829 ovfj->ip_offset = code - cfg->native_code; \
1830 ovfj->b0_cond = (b0); \
1831 ovfj->b1_cond = (b1); \
1832 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1834 cfg->bb_exit->max_offset += 24; \
1836 mono_add_patch_info (cfg, code - cfg->native_code, \
1837 MONO_PATCH_INFO_EXC, exc_name); \
1838 ppc_bcl (code, (b0), (b1), 0); \
1842 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1845 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1850 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1852 MonoInst *ins, *n, *last_ins = NULL;
1854 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1855 switch (ins->opcode) {
1857 /* remove unnecessary multiplication with 1 */
1858 if (ins->inst_imm == 1) {
1859 if (ins->dreg != ins->sreg1) {
1860 ins->opcode = OP_MOVE;
1862 MONO_DELETE_INS (bb, ins);
1866 int power2 = mono_is_power_of_two (ins->inst_imm);
1868 ins->opcode = OP_SHL_IMM;
1869 ins->inst_imm = power2;
1873 case OP_LOAD_MEMBASE:
1874 case OP_LOADI4_MEMBASE:
1876 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1877 * OP_LOAD_MEMBASE offset(basereg), reg
1879 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1880 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1881 ins->inst_basereg == last_ins->inst_destbasereg &&
1882 ins->inst_offset == last_ins->inst_offset) {
1883 if (ins->dreg == last_ins->sreg1) {
1884 MONO_DELETE_INS (bb, ins);
1887 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1888 ins->opcode = OP_MOVE;
1889 ins->sreg1 = last_ins->sreg1;
1893 * Note: reg1 must be different from the basereg in the second load
1894 * OP_LOAD_MEMBASE offset(basereg), reg1
1895 * OP_LOAD_MEMBASE offset(basereg), reg2
1897 * OP_LOAD_MEMBASE offset(basereg), reg1
1898 * OP_MOVE reg1, reg2
1900 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1901 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1902 ins->inst_basereg != last_ins->dreg &&
1903 ins->inst_basereg == last_ins->inst_basereg &&
1904 ins->inst_offset == last_ins->inst_offset) {
1906 if (ins->dreg == last_ins->dreg) {
1907 MONO_DELETE_INS (bb, ins);
1910 ins->opcode = OP_MOVE;
1911 ins->sreg1 = last_ins->dreg;
1914 //g_assert_not_reached ();
1918 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1919 * OP_LOAD_MEMBASE offset(basereg), reg
1921 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1922 * OP_ICONST reg, imm
1924 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1925 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1926 ins->inst_basereg == last_ins->inst_destbasereg &&
1927 ins->inst_offset == last_ins->inst_offset) {
1928 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1929 ins->opcode = OP_ICONST;
1930 ins->inst_c0 = last_ins->inst_imm;
1931 g_assert_not_reached (); // check this rule
1935 case OP_LOADU1_MEMBASE:
1936 case OP_LOADI1_MEMBASE:
1937 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1938 ins->inst_basereg == last_ins->inst_destbasereg &&
1939 ins->inst_offset == last_ins->inst_offset) {
1940 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1941 ins->sreg1 = last_ins->sreg1;
1944 case OP_LOADU2_MEMBASE:
1945 case OP_LOADI2_MEMBASE:
1946 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1947 ins->inst_basereg == last_ins->inst_destbasereg &&
1948 ins->inst_offset == last_ins->inst_offset) {
1949 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1950 ins->sreg1 = last_ins->sreg1;
1954 ins->opcode = OP_MOVE;
1958 if (ins->dreg == ins->sreg1) {
1959 MONO_DELETE_INS (bb, ins);
1963 * OP_MOVE sreg, dreg
1964 * OP_MOVE dreg, sreg
1966 if (last_ins && last_ins->opcode == OP_MOVE &&
1967 ins->sreg1 == last_ins->dreg &&
1968 ins->dreg == last_ins->sreg1) {
1969 MONO_DELETE_INS (bb, ins);
1977 bb->last_ins = last_ins;
1981 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1983 g_assert (cfg->new_ir);
1985 switch (ins->opcode) {
1986 case OP_ICONV_TO_R_UN: {
1987 static const guint64 adjust_val = 0x4330000000000000ULL;
1988 int msw_reg = mono_alloc_ireg (cfg);
1989 int adj_reg = mono_alloc_freg (cfg);
1990 int tmp_reg = mono_alloc_freg (cfg);
1991 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1992 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
1993 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
1994 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1995 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
1996 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1997 ins->opcode = OP_NOP;
2000 case OP_ICONV_TO_R4:
2001 case OP_ICONV_TO_R8: {
2002 /* FIXME: change precision for CEE_CONV_R4 */
2003 static const guint64 adjust_val = 0x4330000080000000ULL;
2004 int msw_reg = mono_alloc_ireg (cfg);
2005 int xored = mono_alloc_ireg (cfg);
2006 int adj_reg = mono_alloc_freg (cfg);
2007 int tmp_reg = mono_alloc_freg (cfg);
2008 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2009 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2010 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2011 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2012 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2013 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2014 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2015 if (ins->opcode == OP_ICONV_TO_R4)
2016 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2017 ins->opcode = OP_NOP;
2021 int msw_reg = mono_alloc_ireg (cfg);
2022 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2023 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2024 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2025 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2026 ins->opcode = OP_NOP;
2033 * the branch_b0_table should maintain the order of these
2047 branch_b0_table [] = {
2062 branch_b1_table [] = {
2076 #define NEW_INS(cfg,dest,op) do { \
2077 MONO_INST_NEW((cfg), (dest), (op)); \
2078 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2082 map_to_reg_reg_op (int op)
2091 case OP_COMPARE_IMM:
2093 case OP_ICOMPARE_IMM:
2109 case OP_LOAD_MEMBASE:
2110 return OP_LOAD_MEMINDEX;
2111 case OP_LOADI4_MEMBASE:
2112 return OP_LOADI4_MEMINDEX;
2113 case OP_LOADU4_MEMBASE:
2114 return OP_LOADU4_MEMINDEX;
2115 case OP_LOADU1_MEMBASE:
2116 return OP_LOADU1_MEMINDEX;
2117 case OP_LOADI2_MEMBASE:
2118 return OP_LOADI2_MEMINDEX;
2119 case OP_LOADU2_MEMBASE:
2120 return OP_LOADU2_MEMINDEX;
2121 case OP_LOADI1_MEMBASE:
2122 return OP_LOADI1_MEMINDEX;
2123 case OP_LOADR4_MEMBASE:
2124 return OP_LOADR4_MEMINDEX;
2125 case OP_LOADR8_MEMBASE:
2126 return OP_LOADR8_MEMINDEX;
2127 case OP_STOREI1_MEMBASE_REG:
2128 return OP_STOREI1_MEMINDEX;
2129 case OP_STOREI2_MEMBASE_REG:
2130 return OP_STOREI2_MEMINDEX;
2131 case OP_STOREI4_MEMBASE_REG:
2132 return OP_STOREI4_MEMINDEX;
2133 case OP_STORE_MEMBASE_REG:
2134 return OP_STORE_MEMINDEX;
2135 case OP_STORER4_MEMBASE_REG:
2136 return OP_STORER4_MEMINDEX;
2137 case OP_STORER8_MEMBASE_REG:
2138 return OP_STORER8_MEMINDEX;
2139 case OP_STORE_MEMBASE_IMM:
2140 return OP_STORE_MEMBASE_REG;
2141 case OP_STOREI1_MEMBASE_IMM:
2142 return OP_STOREI1_MEMBASE_REG;
2143 case OP_STOREI2_MEMBASE_IMM:
2144 return OP_STOREI2_MEMBASE_REG;
2145 case OP_STOREI4_MEMBASE_IMM:
2146 return OP_STOREI4_MEMBASE_REG;
2148 return mono_op_imm_to_op (op);
2151 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2153 #define compare_opcode_is_unsigned(opcode) \
2154 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2155 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2156 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2157 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2158 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2160 * Remove from the instruction list the instructions that can't be
2161 * represented with very simple instructions with no register
2165 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2167 MonoInst *ins, *next, *temp, *last_ins = NULL;
2170 /* setup the virtual reg allocator */
2171 if (bb->max_vreg > cfg->rs->next_vreg)
2172 cfg->rs->next_vreg = bb->max_vreg;
2174 MONO_BB_FOR_EACH_INS (bb, ins) {
2176 switch (ins->opcode) {
2177 case OP_IDIV_UN_IMM:
2180 case OP_IREM_UN_IMM:
2181 NEW_INS (cfg, temp, OP_ICONST);
2182 temp->inst_c0 = ins->inst_imm;
2183 temp->dreg = mono_regstate_next_int (cfg->rs);
2184 ins->sreg2 = temp->dreg;
2185 if (ins->opcode == OP_IDIV_IMM)
2186 ins->opcode = OP_IDIV;
2187 else if (ins->opcode == OP_IREM_IMM)
2188 ins->opcode = OP_IREM;
2189 else if (ins->opcode == OP_IDIV_UN_IMM)
2190 ins->opcode = OP_IDIV_UN;
2191 else if (ins->opcode == OP_IREM_UN_IMM)
2192 ins->opcode = OP_IREM_UN;
2194 /* handle rem separately */
2199 /* we change a rem dest, src1, src2 to
2200 * div temp1, src1, src2
2201 * mul temp2, temp1, src2
2202 * sub dest, src1, temp2
2204 NEW_INS (cfg, mul, OP_IMUL);
2205 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2206 temp->sreg1 = ins->sreg1;
2207 temp->sreg2 = ins->sreg2;
2208 temp->dreg = mono_regstate_next_int (cfg->rs);
2209 mul->sreg1 = temp->dreg;
2210 mul->sreg2 = ins->sreg2;
2211 mul->dreg = mono_regstate_next_int (cfg->rs);
2212 ins->opcode = OP_ISUB;
2213 ins->sreg2 = mul->dreg;
2219 if (!ppc_is_imm16 (ins->inst_imm)) {
2220 NEW_INS (cfg, temp, OP_ICONST);
2221 temp->inst_c0 = ins->inst_imm;
2222 temp->dreg = mono_regstate_next_int (cfg->rs);
2223 ins->sreg2 = temp->dreg;
2224 ins->opcode = map_to_reg_reg_op (ins->opcode);
2229 if (!ppc_is_imm16 (-ins->inst_imm)) {
2230 NEW_INS (cfg, temp, OP_ICONST);
2231 temp->inst_c0 = ins->inst_imm;
2232 temp->dreg = mono_regstate_next_int (cfg->rs);
2233 ins->sreg2 = temp->dreg;
2234 ins->opcode = map_to_reg_reg_op (ins->opcode);
2243 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2244 NEW_INS (cfg, temp, OP_ICONST);
2245 temp->inst_c0 = ins->inst_imm;
2246 temp->dreg = mono_regstate_next_int (cfg->rs);
2247 ins->sreg2 = temp->dreg;
2248 ins->opcode = map_to_reg_reg_op (ins->opcode);
2256 NEW_INS (cfg, temp, OP_ICONST);
2257 temp->inst_c0 = ins->inst_imm;
2258 temp->dreg = mono_regstate_next_int (cfg->rs);
2259 ins->sreg2 = temp->dreg;
2260 ins->opcode = map_to_reg_reg_op (ins->opcode);
2262 case OP_COMPARE_IMM:
2263 case OP_ICOMPARE_IMM:
2265 /* Branch opts can eliminate the branch */
2266 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2267 ins->opcode = OP_NOP;
2271 if (compare_opcode_is_unsigned (next->opcode)) {
2272 if (!ppc_is_uimm16 (ins->inst_imm)) {
2273 NEW_INS (cfg, temp, OP_ICONST);
2274 temp->inst_c0 = ins->inst_imm;
2275 temp->dreg = mono_regstate_next_int (cfg->rs);
2276 ins->sreg2 = temp->dreg;
2277 ins->opcode = map_to_reg_reg_op (ins->opcode);
2280 if (!ppc_is_imm16 (ins->inst_imm)) {
2281 NEW_INS (cfg, temp, OP_ICONST);
2282 temp->inst_c0 = ins->inst_imm;
2283 temp->dreg = mono_regstate_next_int (cfg->rs);
2284 ins->sreg2 = temp->dreg;
2285 ins->opcode = map_to_reg_reg_op (ins->opcode);
2291 if (ins->inst_imm == 1) {
2292 ins->opcode = OP_MOVE;
2295 if (ins->inst_imm == 0) {
2296 ins->opcode = OP_ICONST;
2300 imm = mono_is_power_of_two (ins->inst_imm);
2302 ins->opcode = OP_SHL_IMM;
2303 ins->inst_imm = imm;
2306 if (!ppc_is_imm16 (ins->inst_imm)) {
2307 NEW_INS (cfg, temp, OP_ICONST);
2308 temp->inst_c0 = ins->inst_imm;
2309 temp->dreg = mono_regstate_next_int (cfg->rs);
2310 ins->sreg2 = temp->dreg;
2311 ins->opcode = map_to_reg_reg_op (ins->opcode);
2314 case OP_LOCALLOC_IMM:
2315 NEW_INS (cfg, temp, OP_ICONST);
2316 temp->inst_c0 = ins->inst_imm;
2317 temp->dreg = mono_regstate_next_int (cfg->rs);
2318 ins->sreg1 = temp->dreg;
2319 ins->opcode = OP_LOCALLOC;
2321 case OP_LOAD_MEMBASE:
2322 case OP_LOADI4_MEMBASE:
2323 case OP_LOADU4_MEMBASE:
2324 case OP_LOADI2_MEMBASE:
2325 case OP_LOADU2_MEMBASE:
2326 case OP_LOADI1_MEMBASE:
2327 case OP_LOADU1_MEMBASE:
2328 case OP_LOADR4_MEMBASE:
2329 case OP_LOADR8_MEMBASE:
2330 case OP_STORE_MEMBASE_REG:
2331 case OP_STOREI4_MEMBASE_REG:
2332 case OP_STOREI2_MEMBASE_REG:
2333 case OP_STOREI1_MEMBASE_REG:
2334 case OP_STORER4_MEMBASE_REG:
2335 case OP_STORER8_MEMBASE_REG:
2336 /* we can do two things: load the immed in a register
2337 * and use an indexed load, or see if the immed can be
2338 * represented as an ad_imm + a load with a smaller offset
2339 * that fits. We just do the first for now, optimize later.
2341 if (ppc_is_imm16 (ins->inst_offset))
2343 NEW_INS (cfg, temp, OP_ICONST);
2344 temp->inst_c0 = ins->inst_offset;
2345 temp->dreg = mono_regstate_next_int (cfg->rs);
2346 ins->sreg2 = temp->dreg;
2347 ins->opcode = map_to_reg_reg_op (ins->opcode);
2349 case OP_STORE_MEMBASE_IMM:
2350 case OP_STOREI1_MEMBASE_IMM:
2351 case OP_STOREI2_MEMBASE_IMM:
2352 case OP_STOREI4_MEMBASE_IMM:
2353 NEW_INS (cfg, temp, OP_ICONST);
2354 temp->inst_c0 = ins->inst_imm;
2355 temp->dreg = mono_regstate_next_int (cfg->rs);
2356 ins->sreg1 = temp->dreg;
2357 ins->opcode = map_to_reg_reg_op (ins->opcode);
2359 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2362 NEW_INS (cfg, temp, OP_ICONST);
2363 temp->inst_c0 = (guint32)ins->inst_p0;
2364 temp->dreg = mono_regstate_next_int (cfg->rs);
2365 ins->inst_basereg = temp->dreg;
2366 ins->inst_offset = 0;
2367 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2369 /* make it handle the possibly big ins->inst_offset
2370 * later optimize to use lis + load_membase
2376 bb->last_ins = last_ins;
2377 bb->max_vreg = cfg->rs->next_vreg;
2382 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2384 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2385 ppc_fctiwz (code, ppc_f0, sreg);
2386 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2387 ppc_lwz (code, dreg, -4, ppc_sp);
2390 ppc_andid (code, dreg, dreg, 0xff);
2392 ppc_andid (code, dreg, dreg, 0xffff);
2395 ppc_extsb (code, dreg, dreg);
2397 ppc_extsh (code, dreg, dreg);
2402 static unsigned char*
2403 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2406 int sreg = tree->sreg1;
2407 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2408 if (tree->flags & MONO_INST_INIT) {
2410 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2411 x86_push_reg (code, X86_EAX);
2414 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2415 x86_push_reg (code, X86_ECX);
2418 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2419 x86_push_reg (code, X86_EDI);
2423 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2424 if (sreg != X86_ECX)
2425 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2426 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2428 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2430 x86_prefix (code, X86_REP_PREFIX);
2433 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2434 x86_pop_reg (code, X86_EDI);
2435 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2436 x86_pop_reg (code, X86_ECX);
2437 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2438 x86_pop_reg (code, X86_EAX);
2446 const guchar *target;
2451 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2454 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2455 PatchData *pdata = (PatchData*)user_data;
2456 guchar *code = data;
2457 guint32 *thunks = data;
2458 guint32 *endthunks = (guint32*)(code + bsize);
2462 int difflow, diffhigh;
2464 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2465 difflow = (char*)pdata->code - (char*)thunks;
2466 diffhigh = (char*)pdata->code - (char*)endthunks;
2467 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2470 templ = (guchar*)load;
2471 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2472 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2474 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2475 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2476 while (thunks < endthunks) {
2477 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2478 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2479 ppc_patch (pdata->code, (guchar*)thunks);
2480 mono_arch_flush_icache (pdata->code, 4);
2483 static int num_thunks = 0;
2485 if ((num_thunks % 20) == 0)
2486 g_print ("num_thunks lookup: %d\n", num_thunks);
2489 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2490 /* found a free slot instead: emit thunk */
2491 code = (guchar*)thunks;
2492 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2493 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2494 ppc_mtctr (code, ppc_r0);
2495 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2496 mono_arch_flush_icache ((guchar*)thunks, 16);
2498 ppc_patch (pdata->code, (guchar*)thunks);
2499 mono_arch_flush_icache (pdata->code, 4);
2502 static int num_thunks = 0;
2504 if ((num_thunks % 20) == 0)
2505 g_print ("num_thunks: %d\n", num_thunks);
2509 /* skip 16 bytes, the size of the thunk */
2513 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2519 handle_thunk (int absolute, guchar *code, const guchar *target) {
2520 MonoDomain *domain = mono_domain_get ();
2524 pdata.target = target;
2525 pdata.absolute = absolute;
2528 mono_domain_lock (domain);
2529 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2532 /* this uses the first available slot */
2534 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2536 mono_domain_unlock (domain);
2538 if (pdata.found != 1)
2539 g_print ("thunk failed for %p from %p\n", target, code);
2540 g_assert (pdata.found == 1);
2544 ppc_patch (guchar *code, const guchar *target)
2546 guint32 ins = *(guint32*)code;
2547 guint32 prim = ins >> 26;
2550 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2552 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2553 gint diff = target - code;
2555 if (diff <= 33554431){
2556 ins = (18 << 26) | (diff) | (ins & 1);
2557 *(guint32*)code = ins;
2561 /* diff between 0 and -33554432 */
2562 if (diff >= -33554432){
2563 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2564 *(guint32*)code = ins;
2569 if ((glong)target >= 0){
2570 if ((glong)target <= 33554431){
2571 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2572 *(guint32*)code = ins;
2576 if ((glong)target >= -33554432){
2577 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2578 *(guint32*)code = ins;
2583 handle_thunk (TRUE, code, target);
2586 g_assert_not_reached ();
2593 guint32 li = (guint32)target;
2594 ins = (ins & 0xffff0000) | (ins & 3);
2595 ovf = li & 0xffff0000;
2596 if (ovf != 0 && ovf != 0xffff0000)
2597 g_assert_not_reached ();
2600 // FIXME: assert the top bits of li are 0
2602 gint diff = target - code;
2603 ins = (ins & 0xffff0000) | (ins & 3);
2604 ovf = diff & 0xffff0000;
2605 if (ovf != 0 && ovf != 0xffff0000)
2606 g_assert_not_reached ();
2610 *(guint32*)code = ins;
2614 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2616 /* the trampoline code will try to patch the blrl, blr, bcctr */
2617 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2620 /* this is the lis/ori/mtlr/blrl sequence */
2621 seq = (guint32*)code;
2622 g_assert ((seq [0] >> 26) == 15);
2623 g_assert ((seq [1] >> 26) == 24);
2624 g_assert ((seq [2] >> 26) == 31);
2625 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2626 /* FIXME: make this thread safe */
2627 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2628 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2629 mono_arch_flush_icache (code - 8, 8);
2631 g_assert_not_reached ();
2633 // g_print ("patched with 0x%08x\n", ins);
2637 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2639 switch (ins->opcode) {
2642 case OP_FCALL_MEMBASE:
2643 if (ins->dreg != ppc_f1)
2644 ppc_fmr (code, ins->dreg, ppc_f1);
2652 * emit_load_volatile_arguments:
2654 * Load volatile arguments from the stack to the original input registers.
2655 * Required before a tail call.
2658 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2660 MonoMethod *method = cfg->method;
2661 MonoMethodSignature *sig;
2665 int struct_index = 0;
2667 /* FIXME: Generate intermediate code instead */
2669 sig = mono_method_signature (method);
2671 /* This is the opposite of the code in emit_prolog */
2675 cinfo = calculate_sizes (sig, sig->pinvoke);
2677 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2678 ArgInfo *ainfo = &cinfo->ret;
2679 inst = cfg->vret_addr;
2680 g_assert (ppc_is_imm16 (inst->inst_offset));
2681 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2683 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2684 ArgInfo *ainfo = cinfo->args + i;
2685 inst = cfg->args [pos];
2687 g_assert (inst->opcode != OP_REGVAR);
2688 g_assert (ppc_is_imm16 (inst->inst_offset));
2690 switch (ainfo->regtype) {
2691 case RegTypeGeneral:
2692 switch (ainfo->size) {
2694 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2697 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2700 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2706 switch (ainfo->size) {
2708 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2711 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2714 g_assert_not_reached ();
2719 case RegTypeStructByVal:
2723 case RegTypeStructByAddr: {
2724 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2726 g_assert (ppc_is_imm16 (addr->inst_offset));
2727 g_assert (!ainfo->offset);
2728 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2735 g_assert_not_reached ();
2747 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2749 MonoInst *ins, *next;
2752 guint8 *code = cfg->native_code + cfg->code_len;
2753 MonoInst *last_ins = NULL;
2754 guint last_offset = 0;
2757 /* we don't align basic blocks of loops on ppc */
2759 if (cfg->verbose_level > 2)
2760 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2762 cpos = bb->max_offset;
2764 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2765 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2766 //g_assert (!mono_compile_aot);
2769 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2770 /* this is not thread save, but good enough */
2771 /* fixme: howto handle overflows? */
2772 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2775 MONO_BB_FOR_EACH_INS (bb, ins) {
2776 offset = code - cfg->native_code;
2778 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2780 if (offset > (cfg->code_size - max_len - 16)) {
2781 cfg->code_size *= 2;
2782 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2783 code = cfg->native_code + offset;
2785 // if (ins->cil_code)
2786 // g_print ("cil code\n");
2787 mono_debug_record_line_number (cfg, ins, offset);
2789 switch (ins->opcode) {
2792 case OP_DUMMY_STORE:
2793 case OP_NOT_REACHED:
2797 emit_tls_access (code, ins->dreg, ins->inst_offset);
2800 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2801 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2802 ppc_mr (code, ppc_r4, ppc_r0);
2805 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2806 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2807 ppc_mr (code, ppc_r4, ppc_r0);
2809 case OP_MEMORY_BARRIER:
2812 case OP_STOREI1_MEMBASE_REG:
2813 if (ppc_is_imm16 (ins->inst_offset)) {
2814 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2816 ppc_load (code, ppc_r0, ins->inst_offset);
2817 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2820 case OP_STOREI2_MEMBASE_REG:
2821 if (ppc_is_imm16 (ins->inst_offset)) {
2822 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2824 ppc_load (code, ppc_r0, ins->inst_offset);
2825 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2828 case OP_STORE_MEMBASE_REG:
2829 case OP_STOREI4_MEMBASE_REG:
2830 if (ppc_is_imm16 (ins->inst_offset)) {
2831 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2833 ppc_load (code, ppc_r0, ins->inst_offset);
2834 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2837 case OP_STOREI1_MEMINDEX:
2838 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2840 case OP_STOREI2_MEMINDEX:
2841 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2843 case OP_STORE_MEMINDEX:
2844 case OP_STOREI4_MEMINDEX:
2845 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2848 g_assert_not_reached ();
2850 case OP_LOAD_MEMBASE:
2851 case OP_LOADI4_MEMBASE:
2852 case OP_LOADU4_MEMBASE:
2853 if (ppc_is_imm16 (ins->inst_offset)) {
2854 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2856 ppc_load (code, ppc_r0, ins->inst_offset);
2857 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2860 case OP_LOADI1_MEMBASE:
2861 case OP_LOADU1_MEMBASE:
2862 if (ppc_is_imm16 (ins->inst_offset)) {
2863 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2865 ppc_load (code, ppc_r0, ins->inst_offset);
2866 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2868 if (ins->opcode == OP_LOADI1_MEMBASE)
2869 ppc_extsb (code, ins->dreg, ins->dreg);
2871 case OP_LOADU2_MEMBASE:
2872 if (ppc_is_imm16 (ins->inst_offset)) {
2873 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2875 ppc_load (code, ppc_r0, ins->inst_offset);
2876 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2879 case OP_LOADI2_MEMBASE:
2880 if (ppc_is_imm16 (ins->inst_offset)) {
2881 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2883 ppc_load (code, ppc_r0, ins->inst_offset);
2884 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2887 case OP_LOAD_MEMINDEX:
2888 case OP_LOADI4_MEMINDEX:
2889 case OP_LOADU4_MEMINDEX:
2890 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2892 case OP_LOADU2_MEMINDEX:
2893 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2895 case OP_LOADI2_MEMINDEX:
2896 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2898 case OP_LOADU1_MEMINDEX:
2899 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2901 case OP_LOADI1_MEMINDEX:
2902 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2903 ppc_extsb (code, ins->dreg, ins->dreg);
2905 case OP_ICONV_TO_I1:
2906 ppc_extsb (code, ins->dreg, ins->sreg1);
2908 case OP_ICONV_TO_I2:
2909 ppc_extsh (code, ins->dreg, ins->sreg1);
2911 case OP_ICONV_TO_U1:
2912 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2914 case OP_ICONV_TO_U2:
2915 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2920 if (next && compare_opcode_is_unsigned (next->opcode))
2921 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2923 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2925 case OP_COMPARE_IMM:
2926 case OP_ICOMPARE_IMM:
2928 if (next && compare_opcode_is_unsigned (next->opcode)) {
2929 if (ppc_is_uimm16 (ins->inst_imm)) {
2930 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2932 g_assert_not_reached ();
2935 if (ppc_is_imm16 (ins->inst_imm)) {
2936 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2938 g_assert_not_reached ();
2947 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2950 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2954 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2957 if (ppc_is_imm16 (ins->inst_imm)) {
2958 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2960 g_assert_not_reached ();
2965 if (ppc_is_imm16 (ins->inst_imm)) {
2966 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2968 g_assert_not_reached ();
2972 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2974 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2975 ppc_mfspr (code, ppc_r0, ppc_xer);
2976 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2977 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2979 case OP_IADD_OVF_UN:
2980 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2982 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2983 ppc_mfspr (code, ppc_r0, ppc_xer);
2984 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2985 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2988 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2990 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2991 ppc_mfspr (code, ppc_r0, ppc_xer);
2992 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2993 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2995 case OP_ISUB_OVF_UN:
2996 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2998 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2999 ppc_mfspr (code, ppc_r0, ppc_xer);
3000 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3001 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3003 case OP_ADD_OVF_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<<14));
3009 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3011 case OP_ADD_OVF_UN_CARRY:
3012 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3014 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3015 ppc_mfspr (code, ppc_r0, ppc_xer);
3016 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3017 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3019 case OP_SUB_OVF_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<<14));
3025 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3027 case OP_SUB_OVF_UN_CARRY:
3028 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3030 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3031 ppc_mfspr (code, ppc_r0, ppc_xer);
3032 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3033 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3037 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3040 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3044 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3048 // we add the negated value
3049 if (ppc_is_imm16 (-ins->inst_imm))
3050 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3052 g_assert_not_reached ();
3056 g_assert (ppc_is_imm16 (ins->inst_imm));
3057 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3060 ppc_subfze (code, ins->dreg, ins->sreg1);
3063 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3064 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3068 if (!(ins->inst_imm & 0xffff0000)) {
3069 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3070 } else if (!(ins->inst_imm & 0xffff)) {
3071 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3073 g_assert_not_reached ();
3077 guint8 *divisor_is_m1;
3078 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3080 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3081 divisor_is_m1 = code;
3082 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3083 ppc_lis (code, ppc_r0, 0x8000);
3084 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3085 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3086 ppc_patch (divisor_is_m1, code);
3087 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3089 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3090 ppc_mfspr (code, ppc_r0, ppc_xer);
3091 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3092 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3096 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3097 ppc_mfspr (code, ppc_r0, ppc_xer);
3098 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3099 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3105 g_assert_not_reached ();
3107 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3111 if (!(ins->inst_imm & 0xffff0000)) {
3112 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3113 } else if (!(ins->inst_imm & 0xffff)) {
3114 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3116 g_assert_not_reached ();
3120 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3124 if (!(ins->inst_imm & 0xffff0000)) {
3125 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3126 } else if (!(ins->inst_imm & 0xffff)) {
3127 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3129 g_assert_not_reached ();
3133 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3137 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3140 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3144 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3147 case OP_ISHR_UN_IMM:
3149 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3151 ppc_mr (code, ins->dreg, ins->sreg1);
3154 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3157 ppc_not (code, ins->dreg, ins->sreg1);
3160 ppc_neg (code, ins->dreg, ins->sreg1);
3163 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3167 if (ppc_is_imm16 (ins->inst_imm)) {
3168 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3170 g_assert_not_reached ();
3174 /* we annot use mcrxr, since it's not implemented on some processors
3175 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3177 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3178 ppc_mfspr (code, ppc_r0, ppc_xer);
3179 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3180 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3182 case OP_IMUL_OVF_UN:
3183 /* we first multiply to get the high word and compare to 0
3184 * to set the flags, then the result is discarded and then
3185 * we multiply to get the lower * bits result
3187 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3188 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3189 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3190 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3193 ppc_load (code, ins->dreg, ins->inst_c0);
3196 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3197 ppc_lis (code, ins->dreg, 0);
3198 ppc_ori (code, ins->dreg, ins->dreg, 0);
3200 case OP_ICONV_TO_I4:
3201 case OP_ICONV_TO_U4:
3203 ppc_mr (code, ins->dreg, ins->sreg1);
3206 int saved = ins->sreg1;
3207 if (ins->sreg1 == ppc_r3) {
3208 ppc_mr (code, ppc_r0, ins->sreg1);
3211 if (ins->sreg2 != ppc_r3)
3212 ppc_mr (code, ppc_r3, ins->sreg2);
3213 if (saved != ppc_r4)
3214 ppc_mr (code, ppc_r4, saved);
3218 ppc_fmr (code, ins->dreg, ins->sreg1);
3220 case OP_FCONV_TO_R4:
3221 ppc_frsp (code, ins->dreg, ins->sreg1);
3227 * Keep in sync with mono_arch_emit_epilog
3229 g_assert (!cfg->method->save_lmf);
3231 * Note: we can use ppc_r11 here because it is dead anyway:
3232 * we're leaving the method.
3234 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3235 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3236 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3238 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3239 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3241 ppc_mtlr (code, ppc_r0);
3244 code = emit_load_volatile_arguments (cfg, code);
3246 if (ppc_is_imm16 (cfg->stack_usage)) {
3247 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3249 ppc_load (code, ppc_r11, cfg->stack_usage);
3250 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3252 if (!cfg->method->save_lmf) {
3253 /*for (i = 31; i >= 14; --i) {
3254 if (cfg->used_float_regs & (1 << i)) {
3255 pos += sizeof (double);
3256 ppc_lfd (code, i, -pos, cfg->frame_reg);
3259 for (i = 31; i >= 13; --i) {
3260 if (cfg->used_int_regs & (1 << i)) {
3261 pos += sizeof (gulong);
3262 ppc_lwz (code, i, -pos, cfg->frame_reg);
3266 /* FIXME restore from MonoLMF: though this can't happen yet */
3268 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3273 /* ensure ins->sreg1 is not NULL */
3274 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3277 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3278 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3280 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3281 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3283 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3292 call = (MonoCallInst*)ins;
3293 if (ins->flags & MONO_INST_HAS_METHOD)
3294 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3296 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3297 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3298 ppc_lis (code, ppc_r0, 0);
3299 ppc_ori (code, ppc_r0, ppc_r0, 0);
3300 ppc_mtlr (code, ppc_r0);
3305 /* FIXME: this should be handled somewhere else in the new jit */
3306 code = emit_move_return_value (cfg, ins, code);
3312 case OP_VOIDCALL_REG:
3314 ppc_mtlr (code, ins->sreg1);
3316 /* FIXME: this should be handled somewhere else in the new jit */
3317 code = emit_move_return_value (cfg, ins, code);
3319 case OP_FCALL_MEMBASE:
3320 case OP_LCALL_MEMBASE:
3321 case OP_VCALL_MEMBASE:
3322 case OP_VCALL2_MEMBASE:
3323 case OP_VOIDCALL_MEMBASE:
3324 case OP_CALL_MEMBASE:
3325 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3326 ppc_mtlr (code, ppc_r0);
3328 /* FIXME: this should be handled somewhere else in the new jit */
3329 code = emit_move_return_value (cfg, ins, code);
3332 g_assert_not_reached ();
3335 guint8 * zero_loop_jump, * zero_loop_start;
3336 /* keep alignment */
3337 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3338 int area_offset = alloca_waste;
3340 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3341 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3342 /* use ctr to store the number of words to 0 if needed */
3343 if (ins->flags & MONO_INST_INIT) {
3344 /* we zero 4 bytes at a time:
3345 * we add 7 instead of 3 so that we set the counter to
3346 * at least 1, otherwise the bdnz instruction will make
3347 * it negative and iterate billions of times.
3349 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3350 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3351 ppc_mtctr (code, ppc_r0);
3353 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3354 ppc_neg (code, ppc_r11, ppc_r11);
3355 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3357 if (ins->flags & MONO_INST_INIT) {
3358 /* adjust the dest reg by -4 so we can use stwu */
3359 /* we actually adjust -8 because we let the loop
3362 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3363 ppc_li (code, ppc_r11, 0);
3364 zero_loop_start = code;
3365 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3366 zero_loop_jump = code;
3367 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3368 ppc_patch (zero_loop_jump, zero_loop_start);
3370 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3375 ppc_mr (code, ppc_r3, ins->sreg1);
3376 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3377 (gpointer)"mono_arch_throw_exception");
3378 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3379 ppc_lis (code, ppc_r0, 0);
3380 ppc_ori (code, ppc_r0, ppc_r0, 0);
3381 ppc_mtlr (code, ppc_r0);
3390 ppc_mr (code, ppc_r3, ins->sreg1);
3391 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3392 (gpointer)"mono_arch_rethrow_exception");
3393 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3394 ppc_lis (code, ppc_r0, 0);
3395 ppc_ori (code, ppc_r0, ppc_r0, 0);
3396 ppc_mtlr (code, ppc_r0);
3403 case OP_START_HANDLER: {
3404 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3405 ppc_mflr (code, ppc_r0);
3406 if (ppc_is_imm16 (spvar->inst_offset)) {
3407 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3409 ppc_load (code, ppc_r11, spvar->inst_offset);
3410 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3414 case OP_ENDFILTER: {
3415 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3416 if (ins->sreg1 != ppc_r3)
3417 ppc_mr (code, ppc_r3, ins->sreg1);
3418 if (ppc_is_imm16 (spvar->inst_offset)) {
3419 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3421 ppc_load (code, ppc_r11, spvar->inst_offset);
3422 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3424 ppc_mtlr (code, ppc_r0);
3428 case OP_ENDFINALLY: {
3429 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3430 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3431 ppc_mtlr (code, ppc_r0);
3435 case OP_CALL_HANDLER:
3436 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3440 ins->inst_c0 = code - cfg->native_code;
3443 if (ins->flags & MONO_INST_BRLABEL) {
3444 /*if (ins->inst_i0->inst_c0) {
3446 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3448 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3452 /*if (ins->inst_target_bb->native_offset) {
3454 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3456 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3462 ppc_mtctr (code, ins->sreg1);
3463 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3467 ppc_li (code, ins->dreg, 0);
3468 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3469 ppc_li (code, ins->dreg, 1);
3475 ppc_li (code, ins->dreg, 1);
3476 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3477 ppc_li (code, ins->dreg, 0);
3483 ppc_li (code, ins->dreg, 1);
3484 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3485 ppc_li (code, ins->dreg, 0);
3487 case OP_COND_EXC_EQ:
3488 case OP_COND_EXC_NE_UN:
3489 case OP_COND_EXC_LT:
3490 case OP_COND_EXC_LT_UN:
3491 case OP_COND_EXC_GT:
3492 case OP_COND_EXC_GT_UN:
3493 case OP_COND_EXC_GE:
3494 case OP_COND_EXC_GE_UN:
3495 case OP_COND_EXC_LE:
3496 case OP_COND_EXC_LE_UN:
3497 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3499 case OP_COND_EXC_IEQ:
3500 case OP_COND_EXC_INE_UN:
3501 case OP_COND_EXC_ILT:
3502 case OP_COND_EXC_ILT_UN:
3503 case OP_COND_EXC_IGT:
3504 case OP_COND_EXC_IGT_UN:
3505 case OP_COND_EXC_IGE:
3506 case OP_COND_EXC_IGE_UN:
3507 case OP_COND_EXC_ILE:
3508 case OP_COND_EXC_ILE_UN:
3509 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3512 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3514 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3515 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3516 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3518 case OP_COND_EXC_OV:
3519 /*ppc_mcrxr (code, 0);
3520 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3522 case OP_COND_EXC_NC:
3523 case OP_COND_EXC_NO:
3524 g_assert_not_reached ();
3536 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3539 /* floating point opcodes */
3542 g_assert_not_reached ();
3543 case OP_STORER8_MEMBASE_REG:
3544 if (ppc_is_imm16 (ins->inst_offset)) {
3545 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3547 ppc_load (code, ppc_r0, ins->inst_offset);
3548 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3551 case OP_LOADR8_MEMBASE:
3552 if (ppc_is_imm16 (ins->inst_offset)) {
3553 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3555 ppc_load (code, ppc_r0, ins->inst_offset);
3556 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3559 case OP_STORER4_MEMBASE_REG:
3560 ppc_frsp (code, ins->sreg1, ins->sreg1);
3561 if (ppc_is_imm16 (ins->inst_offset)) {
3562 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3564 ppc_load (code, ppc_r0, ins->inst_offset);
3565 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3568 case OP_LOADR4_MEMBASE:
3569 if (ppc_is_imm16 (ins->inst_offset)) {
3570 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3572 ppc_load (code, ppc_r0, ins->inst_offset);
3573 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3576 case OP_LOADR4_MEMINDEX:
3577 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3579 case OP_LOADR8_MEMINDEX:
3580 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3582 case OP_STORER4_MEMINDEX:
3583 ppc_frsp (code, ins->sreg1, ins->sreg1);
3584 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3586 case OP_STORER8_MEMINDEX:
3587 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3590 case CEE_CONV_R4: /* FIXME: change precision */
3592 g_assert_not_reached ();
3593 case OP_FCONV_TO_I1:
3594 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3596 case OP_FCONV_TO_U1:
3597 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3599 case OP_FCONV_TO_I2:
3600 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3602 case OP_FCONV_TO_U2:
3603 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3605 case OP_FCONV_TO_I4:
3607 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3609 case OP_FCONV_TO_U4:
3611 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3613 case OP_FCONV_TO_I8:
3614 case OP_FCONV_TO_U8:
3615 g_assert_not_reached ();
3616 /* Implemented as helper calls */
3618 case OP_LCONV_TO_R_UN:
3619 g_assert_not_reached ();
3620 /* Implemented as helper calls */
3622 case OP_LCONV_TO_OVF_I4_2:
3623 case OP_LCONV_TO_OVF_I: {
3624 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3625 // Check if its negative
3626 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3627 negative_branch = code;
3628 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3629 // Its positive msword == 0
3630 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3631 msword_positive_branch = code;
3632 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3634 ovf_ex_target = code;
3635 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3637 ppc_patch (negative_branch, code);
3638 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3639 msword_negative_branch = code;
3640 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3641 ppc_patch (msword_negative_branch, ovf_ex_target);
3643 ppc_patch (msword_positive_branch, code);
3644 if (ins->dreg != ins->sreg1)
3645 ppc_mr (code, ins->dreg, ins->sreg1);
3649 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3652 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3655 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3658 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3664 ppc_fneg (code, ins->dreg, ins->sreg1);
3668 g_assert_not_reached ();
3671 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3674 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3675 ppc_li (code, ins->dreg, 0);
3676 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3677 ppc_li (code, ins->dreg, 1);
3680 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3681 ppc_li (code, ins->dreg, 1);
3682 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3683 ppc_li (code, ins->dreg, 0);
3686 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3687 ppc_li (code, ins->dreg, 1);
3688 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3689 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3690 ppc_li (code, ins->dreg, 0);
3693 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3694 ppc_li (code, ins->dreg, 1);
3695 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3696 ppc_li (code, ins->dreg, 0);
3699 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3700 ppc_li (code, ins->dreg, 1);
3701 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3702 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3703 ppc_li (code, ins->dreg, 0);
3706 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3709 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3712 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3713 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3716 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3717 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3720 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3721 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3724 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3725 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3728 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3729 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3732 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3735 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3736 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3739 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3742 g_assert_not_reached ();
3743 case OP_CHECK_FINITE: {
3744 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3745 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3746 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3747 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3750 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3751 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3755 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3756 g_assert_not_reached ();
3759 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3760 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3761 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3762 g_assert_not_reached ();
3768 last_offset = offset;
3771 cfg->code_len = code - cfg->native_code;
3775 mono_arch_register_lowlevel_calls (void)
3779 #define patch_lis_ori(ip,val) do {\
3780 guint16 *__lis_ori = (guint16*)(ip); \
3781 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3782 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3786 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3788 MonoJumpInfo *patch_info;
3790 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3791 unsigned char *ip = patch_info->ip.i + code;
3792 unsigned char *target;
3794 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3796 switch (patch_info->type) {
3797 case MONO_PATCH_INFO_IP:
3798 patch_lis_ori (ip, ip);
3800 case MONO_PATCH_INFO_METHOD_REL:
3801 g_assert_not_reached ();
3802 *((gpointer *)(ip)) = code + patch_info->data.offset;
3804 case MONO_PATCH_INFO_SWITCH: {
3805 gpointer *table = (gpointer *)patch_info->data.table->table;
3808 patch_lis_ori (ip, table);
3810 for (i = 0; i < patch_info->data.table->table_size; i++) {
3811 table [i] = (int)patch_info->data.table->table [i] + code;
3813 /* we put into the table the absolute address, no need for ppc_patch in this case */
3816 case MONO_PATCH_INFO_METHODCONST:
3817 case MONO_PATCH_INFO_CLASS:
3818 case MONO_PATCH_INFO_IMAGE:
3819 case MONO_PATCH_INFO_FIELD:
3820 case MONO_PATCH_INFO_VTABLE:
3821 case MONO_PATCH_INFO_IID:
3822 case MONO_PATCH_INFO_SFLDA:
3823 case MONO_PATCH_INFO_LDSTR:
3824 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3825 case MONO_PATCH_INFO_LDTOKEN:
3826 /* from OP_AOTCONST : lis + ori */
3827 patch_lis_ori (ip, target);
3829 case MONO_PATCH_INFO_R4:
3830 case MONO_PATCH_INFO_R8:
3831 g_assert_not_reached ();
3832 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3834 case MONO_PATCH_INFO_EXC_NAME:
3835 g_assert_not_reached ();
3836 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3838 case MONO_PATCH_INFO_NONE:
3839 case MONO_PATCH_INFO_BB_OVF:
3840 case MONO_PATCH_INFO_EXC_OVF:
3841 /* everything is dealt with at epilog output time */
3846 ppc_patch (ip, target);
3851 * Stack frame layout:
3853 * ------------------- sp
3854 * MonoLMF structure or saved registers
3855 * -------------------
3857 * -------------------
3859 * -------------------
3860 * optional 8 bytes for tracing
3861 * -------------------
3862 * param area size is cfg->param_area
3863 * -------------------
3864 * linkage area size is PPC_STACK_PARAM_OFFSET
3865 * ------------------- sp
3869 mono_arch_emit_prolog (MonoCompile *cfg)
3871 MonoMethod *method = cfg->method;
3873 MonoMethodSignature *sig;
3875 int alloc_size, pos, max_offset, i;
3880 int tailcall_struct_index;
3882 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3885 sig = mono_method_signature (method);
3886 cfg->code_size = 256 + sig->param_count * 20;
3887 code = cfg->native_code = g_malloc (cfg->code_size);
3889 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3890 ppc_mflr (code, ppc_r0);
3891 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3894 alloc_size = cfg->stack_offset;
3897 if (!method->save_lmf) {
3898 /*for (i = 31; i >= 14; --i) {
3899 if (cfg->used_float_regs & (1 << i)) {
3900 pos += sizeof (gdouble);
3901 ppc_stfd (code, i, -pos, ppc_sp);
3904 for (i = 31; i >= 13; --i) {
3905 if (cfg->used_int_regs & (1 << i)) {
3906 pos += sizeof (gulong);
3907 ppc_stw (code, i, -pos, ppc_sp);
3912 pos += sizeof (MonoLMF);
3914 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3915 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3916 for (i = 14; i < 32; i++) {
3917 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3921 // align to PPC_STACK_ALIGNMENT bytes
3922 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3923 alloc_size += PPC_STACK_ALIGNMENT - 1;
3924 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3927 cfg->stack_usage = alloc_size;
3928 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3930 if (ppc_is_imm16 (-alloc_size)) {
3931 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3933 ppc_load (code, ppc_r11, -alloc_size);
3934 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3937 if (cfg->frame_reg != ppc_sp)
3938 ppc_mr (code, cfg->frame_reg, ppc_sp);
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 (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) {
4098 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
4099 register. Should this case include linux/ppc?
4103 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4105 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4108 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4109 soffset += sizeof (gpointer);
4110 doffset += sizeof (gpointer);
4112 if (ainfo->vtsize) {
4113 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4114 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4115 if ((size & 3) != 0) {
4116 code = emit_memcpy (code, size - soffset,
4117 inst->inst_basereg, doffset,
4118 ppc_r11, ainfo->offset + soffset);
4120 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4121 inst->inst_basereg, doffset,
4122 ppc_r11, ainfo->offset + soffset);
4125 } else if (ainfo->regtype == RegTypeStructByAddr) {
4126 /* if it was originally a RegTypeBase */
4127 if (ainfo->offset) {
4128 /* load the previous stack pointer in r11 */
4129 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4130 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4132 ppc_mr (code, ppc_r11, ainfo->reg);
4135 if (cfg->tailcall_valuetype_addrs) {
4136 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4138 g_assert (ppc_is_imm16 (addr->inst_offset));
4139 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4141 tailcall_struct_index++;
4144 g_assert (ppc_is_imm16 (inst->inst_offset));
4145 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4146 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4148 g_assert_not_reached ();
4153 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4154 ppc_load (code, ppc_r3, cfg->domain);
4155 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4156 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4157 ppc_lis (code, ppc_r0, 0);
4158 ppc_ori (code, ppc_r0, ppc_r0, 0);
4159 ppc_mtlr (code, ppc_r0);
4166 if (method->save_lmf) {
4167 if (lmf_pthread_key != -1) {
4168 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4169 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4170 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4172 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4173 (gpointer)"mono_get_lmf_addr");
4174 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4175 ppc_lis (code, ppc_r0, 0);
4176 ppc_ori (code, ppc_r0, ppc_r0, 0);
4177 ppc_mtlr (code, ppc_r0);
4183 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4184 /* lmf_offset is the offset from the previous stack pointer,
4185 * alloc_size is the total stack space allocated, so the offset
4186 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4187 * The pointer to the struct is put in ppc_r11 (new_lmf).
4188 * The callee-saved registers are already in the MonoLMF structure
4190 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4191 /* ppc_r3 is the result from mono_get_lmf_addr () */
4192 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4193 /* new_lmf->previous_lmf = *lmf_addr */
4194 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4195 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4196 /* *(lmf_addr) = r11 */
4197 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4198 /* save method info */
4199 ppc_load (code, ppc_r0, method);
4200 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4201 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4202 /* save the current IP */
4203 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4204 ppc_load (code, ppc_r0, 0x01010101);
4205 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4209 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4211 cfg->code_len = code - cfg->native_code;
4212 g_assert (cfg->code_len < cfg->code_size);
4219 mono_arch_emit_epilog (MonoCompile *cfg)
4221 MonoJumpInfo *patch_info;
4222 MonoMethod *method = cfg->method;
4224 int max_epilog_size = 16 + 20*4;
4227 if (cfg->method->save_lmf)
4228 max_epilog_size += 128;
4230 if (mono_jit_trace_calls != NULL)
4231 max_epilog_size += 50;
4233 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4234 max_epilog_size += 50;
4236 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4237 cfg->code_size *= 2;
4238 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4239 mono_jit_stats.code_reallocs++;
4243 * Keep in sync with OP_JMP
4245 code = cfg->native_code + cfg->code_len;
4247 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4248 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4252 if (method->save_lmf) {
4254 pos += sizeof (MonoLMF);
4256 /* save the frame reg in r8 */
4257 ppc_mr (code, ppc_r8, cfg->frame_reg);
4258 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4259 /* r5 = previous_lmf */
4260 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4262 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4263 /* *(lmf_addr) = previous_lmf */
4264 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4265 /* FIXME: speedup: there is no actual need to restore the registers if
4266 * we didn't actually change them (idea from Zoltan).
4269 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4271 /*for (i = 14; i < 32; i++) {
4272 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4274 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4275 /* use the saved copy of the frame reg in r8 */
4276 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4277 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4278 ppc_mtlr (code, ppc_r0);
4280 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4282 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4283 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4284 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4286 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4287 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4289 ppc_mtlr (code, ppc_r0);
4291 if (ppc_is_imm16 (cfg->stack_usage)) {
4292 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4294 ppc_load (code, ppc_r11, cfg->stack_usage);
4295 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4298 /*for (i = 31; i >= 14; --i) {
4299 if (cfg->used_float_regs & (1 << i)) {
4300 pos += sizeof (double);
4301 ppc_lfd (code, i, -pos, ppc_sp);
4304 for (i = 31; i >= 13; --i) {
4305 if (cfg->used_int_regs & (1 << i)) {
4306 pos += sizeof (gulong);
4307 ppc_lwz (code, i, -pos, ppc_sp);
4313 cfg->code_len = code - cfg->native_code;
4315 g_assert (cfg->code_len < cfg->code_size);
4319 /* remove once throw_exception_by_name is eliminated */
4321 exception_id_by_name (const char *name)
4323 if (strcmp (name, "IndexOutOfRangeException") == 0)
4324 return MONO_EXC_INDEX_OUT_OF_RANGE;
4325 if (strcmp (name, "OverflowException") == 0)
4326 return MONO_EXC_OVERFLOW;
4327 if (strcmp (name, "ArithmeticException") == 0)
4328 return MONO_EXC_ARITHMETIC;
4329 if (strcmp (name, "DivideByZeroException") == 0)
4330 return MONO_EXC_DIVIDE_BY_ZERO;
4331 if (strcmp (name, "InvalidCastException") == 0)
4332 return MONO_EXC_INVALID_CAST;
4333 if (strcmp (name, "NullReferenceException") == 0)
4334 return MONO_EXC_NULL_REF;
4335 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4336 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4337 g_error ("Unknown intrinsic exception %s\n", name);
4342 mono_arch_emit_exceptions (MonoCompile *cfg)
4344 MonoJumpInfo *patch_info;
4347 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4348 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4349 int max_epilog_size = 50;
4351 /* count the number of exception infos */
4354 * make sure we have enough space for exceptions
4355 * 24 is the simulated call to throw_exception_by_name
4357 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4358 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4359 i = exception_id_by_name (patch_info->data.target);
4360 if (!exc_throw_found [i]) {
4361 max_epilog_size += 24;
4362 exc_throw_found [i] = TRUE;
4364 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4365 max_epilog_size += 12;
4366 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4367 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4368 i = exception_id_by_name (ovfj->data.exception);
4369 if (!exc_throw_found [i]) {
4370 max_epilog_size += 24;
4371 exc_throw_found [i] = TRUE;
4373 max_epilog_size += 8;
4377 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4378 cfg->code_size *= 2;
4379 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4380 mono_jit_stats.code_reallocs++;
4383 code = cfg->native_code + cfg->code_len;
4385 /* add code to raise exceptions */
4386 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4387 switch (patch_info->type) {
4388 case MONO_PATCH_INFO_BB_OVF: {
4389 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4390 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4391 /* patch the initial jump */
4392 ppc_patch (ip, code);
4393 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4395 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4396 /* jump back to the true target */
4398 ip = ovfj->data.bb->native_offset + cfg->native_code;
4399 ppc_patch (code - 4, ip);
4402 case MONO_PATCH_INFO_EXC_OVF: {
4403 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4404 MonoJumpInfo *newji;
4405 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4406 unsigned char *bcl = code;
4407 /* patch the initial jump: we arrived here with a call */
4408 ppc_patch (ip, code);
4409 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4411 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4412 /* patch the conditional jump to the right handler */
4413 /* make it processed next */
4414 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4415 newji->type = MONO_PATCH_INFO_EXC;
4416 newji->ip.i = bcl - cfg->native_code;
4417 newji->data.target = ovfj->data.exception;
4418 newji->next = patch_info->next;
4419 patch_info->next = newji;
4422 case MONO_PATCH_INFO_EXC: {
4423 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4424 i = exception_id_by_name (patch_info->data.target);
4425 if (exc_throw_pos [i]) {
4426 ppc_patch (ip, exc_throw_pos [i]);
4427 patch_info->type = MONO_PATCH_INFO_NONE;
4430 exc_throw_pos [i] = code;
4432 ppc_patch (ip, code);
4433 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4434 ppc_load (code, ppc_r3, patch_info->data.target);
4435 /* we got here from a conditional call, so the calling ip is set in lr already */
4436 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4437 patch_info->data.name = "mono_arch_throw_exception_by_name";
4438 patch_info->ip.i = code - cfg->native_code;
4439 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4440 ppc_lis (code, ppc_r0, 0);
4441 ppc_ori (code, ppc_r0, ppc_r0, 0);
4442 ppc_mtctr (code, ppc_r0);
4443 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4455 cfg->code_len = code - cfg->native_code;
4457 g_assert (cfg->code_len < cfg->code_size);
4462 try_offset_access (void *value, guint32 idx)
4464 register void* me __asm__ ("r2");
4465 void ***p = (void***)((char*)me + 284);
4466 int idx1 = idx / 32;
4467 int idx2 = idx % 32;
4470 if (value != p[idx1][idx2])
4476 setup_tls_access (void)
4479 guint32 *ins, *code;
4480 guint32 cmplwi_1023, li_0x48, blr_ins;
4481 if (tls_mode == TLS_MODE_FAILED)
4484 if (g_getenv ("MONO_NO_TLS")) {
4485 tls_mode = TLS_MODE_FAILED;
4489 if (tls_mode == TLS_MODE_DETECT) {
4490 ins = (guint32*)pthread_getspecific;
4491 /* uncond branch to the real method */
4492 if ((*ins >> 26) == 18) {
4494 val = (*ins & ~3) << 6;
4498 ins = (guint32*)val;
4500 ins = (guint32*) ((char*)ins + val);
4503 code = &cmplwi_1023;
4504 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4506 ppc_li (code, ppc_r4, 0x48);
4509 if (*ins == cmplwi_1023) {
4510 int found_lwz_284 = 0;
4511 for (ptk = 0; ptk < 20; ++ptk) {
4513 if (!*ins || *ins == blr_ins)
4515 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4520 if (!found_lwz_284) {
4521 tls_mode = TLS_MODE_FAILED;
4524 tls_mode = TLS_MODE_LTHREADS;
4525 } else if (*ins == li_0x48) {
4527 /* uncond branch to the real method */
4528 if ((*ins >> 26) == 18) {
4530 val = (*ins & ~3) << 6;
4534 ins = (guint32*)val;
4536 ins = (guint32*) ((char*)ins + val);
4538 code = (guint32*)&val;
4539 ppc_li (code, ppc_r0, 0x7FF2);
4540 if (ins [1] == val) {
4541 /* Darwin on G4, implement */
4542 tls_mode = TLS_MODE_FAILED;
4545 code = (guint32*)&val;
4546 ppc_mfspr (code, ppc_r3, 104);
4547 if (ins [1] != val) {
4548 tls_mode = TLS_MODE_FAILED;
4551 tls_mode = TLS_MODE_DARWIN_G5;
4554 tls_mode = TLS_MODE_FAILED;
4558 tls_mode = TLS_MODE_FAILED;
4562 if (monodomain_key == -1) {
4563 ptk = mono_domain_get_tls_key ();
4565 ptk = mono_pthread_key_for_tls (ptk);
4567 monodomain_key = ptk;
4571 if (lmf_pthread_key == -1) {
4572 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4574 /*g_print ("MonoLMF at: %d\n", ptk);*/
4575 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4576 init_tls_failed = 1;
4579 lmf_pthread_key = ptk;
4582 if (monothread_key == -1) {
4583 ptk = mono_thread_get_tls_key ();
4585 ptk = mono_pthread_key_for_tls (ptk);
4587 monothread_key = ptk;
4588 /*g_print ("thread inited: %d\n", ptk);*/
4591 /*g_print ("thread not inited yet %d\n", ptk);*/
4597 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4599 setup_tls_access ();
4603 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4608 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4610 int this_dreg = ppc_r3;
4615 /* add the this argument */
4616 if (this_reg != -1) {
4618 MONO_INST_NEW (cfg, this, OP_MOVE);
4619 this->type = this_type;
4620 this->sreg1 = this_reg;
4621 this->dreg = mono_regstate_next_int (cfg->rs);
4622 mono_bblock_add_inst (cfg->cbb, this);
4623 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4628 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4629 vtarg->type = STACK_MP;
4630 vtarg->sreg1 = vt_reg;
4631 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4632 mono_bblock_add_inst (cfg->cbb, vtarg);
4633 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4637 #ifdef MONO_ARCH_HAVE_IMT
4641 #define JUMP_IMM_SIZE 12
4642 #define ENABLE_WRONG_METHOD_CHECK 0
4645 * LOCKING: called with the domain lock held
4648 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4652 guint8 *code, *start;
4654 for (i = 0; i < count; ++i) {
4655 MonoIMTCheckItem *item = imt_entries [i];
4656 if (item->is_equals) {
4657 if (item->check_target_idx) {
4658 if (!item->compare_done)
4659 item->chunk_size += CMP_SIZE;
4660 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4662 item->chunk_size += JUMP_IMM_SIZE;
4663 #if ENABLE_WRONG_METHOD_CHECK
4664 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4668 item->chunk_size += CMP_SIZE + BR_SIZE;
4669 imt_entries [item->check_target_idx]->compare_done = TRUE;
4671 size += item->chunk_size;
4673 /* the initial load of the vtable address */
4675 code = mono_code_manager_reserve (domain->code_mp, size);
4677 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4678 for (i = 0; i < count; ++i) {
4679 MonoIMTCheckItem *item = imt_entries [i];
4680 item->code_target = code;
4681 if (item->is_equals) {
4682 if (item->check_target_idx) {
4683 if (!item->compare_done) {
4684 ppc_load (code, ppc_r0, (guint32)item->method);
4685 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4687 item->jmp_code = code;
4688 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4689 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4690 ppc_mtctr (code, ppc_r0);
4691 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4693 /* enable the commented code to assert on wrong method */
4694 #if ENABLE_WRONG_METHOD_CHECK
4695 ppc_load (code, ppc_r0, (guint32)item->method);
4696 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4697 item->jmp_code = code;
4698 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4700 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4701 ppc_mtctr (code, ppc_r0);
4702 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4703 #if ENABLE_WRONG_METHOD_CHECK
4704 ppc_patch (item->jmp_code, code);
4706 item->jmp_code = NULL;
4710 ppc_load (code, ppc_r0, (guint32)item->method);
4711 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4712 item->jmp_code = code;
4713 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4716 /* patch the branches to get to the target items */
4717 for (i = 0; i < count; ++i) {
4718 MonoIMTCheckItem *item = imt_entries [i];
4719 if (item->jmp_code) {
4720 if (item->check_target_idx) {
4721 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4726 mono_stats.imt_thunks_size += code - start;
4727 g_assert (code - start <= size);
4728 mono_arch_flush_icache (start, size);
4733 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4735 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4739 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4741 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4746 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4748 MonoInst *ins = NULL;
4750 /*if (cmethod->klass == mono_defaults.math_class) {
4751 if (strcmp (cmethod->name, "Sqrt") == 0) {
4752 MONO_INST_NEW (cfg, ins, OP_SQRT);
4753 ins->inst_i0 = args [0];
4760 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4767 mono_arch_print_tree (MonoInst *tree, int arity)
4772 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4776 setup_tls_access ();
4777 if (monodomain_key == -1)
4780 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4781 ins->inst_offset = monodomain_key;
4786 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4790 setup_tls_access ();
4791 if (monothread_key == -1)
4794 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4795 ins->inst_offset = monothread_key;
4800 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4802 /* FIXME: implement */
4803 g_assert_not_reached ();