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 allocate_tailcall_valuetype_addrs (m);
1062 m->flags |= MONO_CFG_HAS_SPILLUP;
1064 /* allow room for the vararg method args: void* and long/double */
1065 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1066 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1067 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1068 * call convs needs to be handled this way.
1070 if (m->flags & MONO_CFG_HAS_VARARGS)
1071 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1072 /* gtk-sharp and other broken code will dllimport vararg functions even with
1073 * non-varargs signatures. Since there is little hope people will get this right
1074 * we assume they won't.
1076 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1077 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1079 header = mono_method_get_header (m->method);
1082 * We use the frame register also for any method that has
1083 * exception clauses. This way, when the handlers are called,
1084 * the code will reference local variables using the frame reg instead of
1085 * the stack pointer: if we had to restore the stack pointer, we'd
1086 * corrupt the method frames that are already on the stack (since
1087 * filters get called before stack unwinding happens) when the filter
1088 * code would call any method (this also applies to finally etc.).
1090 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1091 frame_reg = ppc_r31;
1092 m->frame_reg = frame_reg;
1093 if (frame_reg != ppc_sp) {
1094 m->used_int_regs |= 1 << frame_reg;
1097 sig = mono_method_signature (m->method);
1101 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1102 m->ret->opcode = OP_REGVAR;
1103 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1105 /* FIXME: handle long values? */
1106 switch (mono_type_get_underlying_type (sig->ret)->type) {
1107 case MONO_TYPE_VOID:
1111 m->ret->opcode = OP_REGVAR;
1112 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1115 m->ret->opcode = OP_REGVAR;
1116 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1120 /* local vars are at a positive offset from the stack pointer */
1122 * also note that if the function uses alloca, we use ppc_r31
1123 * to point at the local variables.
1125 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1126 /* align the offset to 16 bytes: not sure this is needed here */
1128 //offset &= ~(16 - 1);
1130 /* add parameter area size for called functions */
1131 offset += m->param_area;
1133 offset &= ~(16 - 1);
1135 /* allow room to save the return value */
1136 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1139 /* the MonoLMF structure is stored just below the stack pointer */
1142 /* this stuff should not be needed on ppc and the new jit,
1143 * because a call on ppc to the handlers doesn't change the
1144 * stack pointer and the jist doesn't manipulate the stack pointer
1145 * for operations involving valuetypes.
1147 /* reserve space to store the esp */
1148 offset += sizeof (gpointer);
1150 /* this is a global constant */
1151 mono_exc_esp_offset = offset;
1153 if (sig->call_convention == MONO_CALL_VARARG) {
1154 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1157 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1158 offset += sizeof(gpointer) - 1;
1159 offset &= ~(sizeof(gpointer) - 1);
1162 m->vret_addr->opcode = OP_REGOFFSET;
1163 m->vret_addr->inst_basereg = frame_reg;
1164 m->vret_addr->inst_offset = offset;
1166 if (G_UNLIKELY (m->verbose_level > 1)) {
1167 printf ("vret_addr =");
1168 mono_print_ins (m->vret_addr);
1172 inst->inst_offset = offset;
1173 inst->opcode = OP_REGOFFSET;
1174 inst->inst_basereg = frame_reg;
1177 offset += sizeof(gpointer);
1178 if (sig->call_convention == MONO_CALL_VARARG)
1179 m->sig_cookie += sizeof (gpointer);
1182 curinst = m->locals_start;
1183 for (i = curinst; i < m->num_varinfo; ++i) {
1184 inst = m->varinfo [i];
1185 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1188 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1189 * pinvoke wrappers when they call functions returning structure */
1190 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1191 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1193 size = mono_type_size (inst->inst_vtype, &align);
1195 offset += align - 1;
1196 offset &= ~(align - 1);
1197 inst->inst_offset = offset;
1198 inst->opcode = OP_REGOFFSET;
1199 inst->inst_basereg = frame_reg;
1201 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1206 inst = m->args [curinst];
1207 if (inst->opcode != OP_REGVAR) {
1208 inst->opcode = OP_REGOFFSET;
1209 inst->inst_basereg = frame_reg;
1210 offset += sizeof (gpointer) - 1;
1211 offset &= ~(sizeof (gpointer) - 1);
1212 inst->inst_offset = offset;
1213 offset += sizeof (gpointer);
1214 if (sig->call_convention == MONO_CALL_VARARG)
1215 m->sig_cookie += sizeof (gpointer);
1220 for (i = 0; i < sig->param_count; ++i) {
1221 inst = m->args [curinst];
1222 if (inst->opcode != OP_REGVAR) {
1223 inst->opcode = OP_REGOFFSET;
1224 inst->inst_basereg = frame_reg;
1226 size = mono_type_native_stack_size (sig->params [i], &align);
1227 inst->backend.is_pinvoke = 1;
1229 size = mono_type_size (sig->params [i], &align);
1231 offset += align - 1;
1232 offset &= ~(align - 1);
1233 inst->inst_offset = offset;
1235 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1236 m->sig_cookie += size;
1241 /* align the offset to 16 bytes */
1243 offset &= ~(16 - 1);
1246 m->stack_offset = offset;
1248 if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1249 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1251 m->sig_cookie = cinfo->sig_cookie.offset;
1258 mono_arch_create_vars (MonoCompile *cfg)
1260 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1262 if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1263 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1267 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1268 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1272 * take the arguments and generate the arch-specific
1273 * instructions to properly call the function in call.
1274 * This includes pushing, moving arguments to the right register
1276 * Issue: who does the spilling if needed, and when?
1279 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1281 MonoMethodSignature *sig;
1286 sig = call->signature;
1287 n = sig->param_count + sig->hasthis;
1289 cinfo = calculate_sizes (sig, sig->pinvoke);
1290 if (cinfo->struct_ret)
1291 call->used_iregs |= 1 << cinfo->struct_ret;
1293 for (i = 0; i < n; ++i) {
1294 ainfo = cinfo->args + i;
1295 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1297 cfg->disable_aot = TRUE;
1299 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1300 sig_arg->inst_p0 = call->signature;
1302 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1303 arg->inst_imm = cinfo->sig_cookie.offset;
1304 arg->inst_left = sig_arg;
1305 arg->inst_call = call;
1306 /* prepend, so they get reversed */
1307 arg->next = call->out_args;
1308 call->out_args = arg;
1310 if (is_virtual && i == 0) {
1311 /* the argument will be attached to the call instrucion */
1312 in = call->args [i];
1313 call->used_iregs |= 1 << ainfo->reg;
1315 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1316 in = call->args [i];
1317 arg->cil_code = in->cil_code;
1318 arg->inst_left = in;
1319 arg->inst_call = call;
1320 arg->type = in->type;
1321 /* prepend, so they get reversed */
1322 arg->next = call->out_args;
1323 call->out_args = arg;
1324 if (ainfo->regtype == RegTypeGeneral) {
1325 arg->backend.reg3 = ainfo->reg;
1326 call->used_iregs |= 1 << ainfo->reg;
1327 if (arg->type == STACK_I8)
1328 call->used_iregs |= 1 << (ainfo->reg + 1);
1329 } else if (ainfo->regtype == RegTypeStructByAddr) {
1330 if (ainfo->offset) {
1331 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1332 arg->opcode = OP_OUTARG_MEMBASE;
1333 ai->reg = ainfo->reg;
1334 ai->size = sizeof (gpointer);
1335 ai->offset = ainfo->offset;
1336 arg->backend.data = ai;
1338 arg->backend.reg3 = ainfo->reg;
1339 call->used_iregs |= 1 << ainfo->reg;
1341 } else if (ainfo->regtype == RegTypeStructByVal) {
1343 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1344 /* mark the used regs */
1345 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1346 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1348 arg->opcode = OP_OUTARG_VT;
1349 ai->reg = ainfo->reg;
1350 ai->size = ainfo->size;
1351 ai->vtsize = ainfo->vtsize;
1352 ai->offset = ainfo->offset;
1353 arg->backend.data = ai;
1354 } else if (ainfo->regtype == RegTypeBase) {
1355 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1356 arg->opcode = OP_OUTARG_MEMBASE;
1357 ai->reg = ainfo->reg;
1358 ai->size = ainfo->size;
1359 ai->offset = ainfo->offset;
1360 arg->backend.data = ai;
1361 } else if (ainfo->regtype == RegTypeFP) {
1362 arg->opcode = OP_OUTARG_R8;
1363 arg->backend.reg3 = ainfo->reg;
1364 call->used_fregs |= 1 << ainfo->reg;
1365 if (ainfo->size == 4) {
1366 arg->opcode = OP_OUTARG_R8;
1367 /* we reduce the precision */
1369 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1370 conv->inst_left = arg->inst_left;
1371 arg->inst_left = conv;*/
1374 g_assert_not_reached ();
1379 * Reverse the call->out_args list.
1382 MonoInst *prev = NULL, *list = call->out_args, *next;
1389 call->out_args = prev;
1392 call->stack_usage = cinfo->stack_usage;
1393 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1394 cfg->flags |= MONO_CFG_HAS_CALLS;
1396 * should set more info in call, such as the stack space
1397 * used by the args that needs to be added back to esp
1405 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1407 int sig_reg = mono_alloc_ireg (cfg);
1409 MONO_EMIT_NEW_ICONST (cfg, sig_reg, call->signature);
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1411 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1415 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1418 MonoMethodSignature *sig;
1422 sig = call->signature;
1423 n = sig->param_count + sig->hasthis;
1425 cinfo = calculate_sizes (sig, sig->pinvoke);
1427 for (i = 0; i < n; ++i) {
1428 ArgInfo *ainfo = cinfo->args + i;
1431 if (i >= sig->hasthis)
1432 t = sig->params [i - sig->hasthis];
1434 t = &mono_defaults.int_class->byval_arg;
1435 t = mono_type_get_underlying_type (t);
1437 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1438 emit_sig_cookie (cfg, call, cinfo);
1440 in = call->args [i];
1442 if (ainfo->regtype == RegTypeGeneral) {
1443 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1444 MONO_INST_NEW (cfg, ins, OP_MOVE);
1445 ins->dreg = mono_alloc_ireg (cfg);
1446 ins->sreg1 = in->dreg + 1;
1447 MONO_ADD_INS (cfg->cbb, ins);
1448 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1450 MONO_INST_NEW (cfg, ins, OP_MOVE);
1451 ins->dreg = mono_alloc_ireg (cfg);
1452 ins->sreg1 = in->dreg + 2;
1453 MONO_ADD_INS (cfg->cbb, ins);
1454 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1456 MONO_INST_NEW (cfg, ins, OP_MOVE);
1457 ins->dreg = mono_alloc_ireg (cfg);
1458 ins->sreg1 = in->dreg;
1459 MONO_ADD_INS (cfg->cbb, ins);
1461 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1463 } else if (ainfo->regtype == RegTypeStructByAddr) {
1464 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1465 ins->opcode = OP_OUTARG_VT;
1466 ins->sreg1 = in->dreg;
1467 ins->klass = in->klass;
1468 ins->inst_p0 = call;
1469 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1470 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1471 MONO_ADD_INS (cfg->cbb, ins);
1472 } else if (ainfo->regtype == RegTypeStructByVal) {
1473 /* this is further handled in mono_arch_emit_outarg_vt () */
1474 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1475 ins->opcode = OP_OUTARG_VT;
1476 ins->sreg1 = in->dreg;
1477 ins->klass = in->klass;
1478 ins->inst_p0 = call;
1479 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1480 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1481 MONO_ADD_INS (cfg->cbb, ins);
1482 } else if (ainfo->regtype == RegTypeBase) {
1483 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1484 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1485 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1486 if (t->type == MONO_TYPE_R8)
1487 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1489 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1491 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1493 } else if (ainfo->regtype == RegTypeFP) {
1494 if (t->type == MONO_TYPE_VALUETYPE) {
1495 /* this is further handled in mono_arch_emit_outarg_vt () */
1496 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1497 ins->opcode = OP_OUTARG_VT;
1498 ins->sreg1 = in->dreg;
1499 ins->klass = in->klass;
1500 ins->inst_p0 = call;
1501 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1502 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1503 MONO_ADD_INS (cfg->cbb, ins);
1505 cfg->flags |= MONO_CFG_HAS_FPOUT;
1507 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1508 ins->dreg = mono_alloc_freg (cfg);
1509 ins->sreg1 = in->dreg;
1510 MONO_ADD_INS (cfg->cbb, ins);
1512 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
1513 cfg->flags |= MONO_CFG_HAS_FPOUT;
1516 g_assert_not_reached ();
1520 /* Emit the signature cookie in the case that there is no
1521 additional argument */
1522 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1523 emit_sig_cookie (cfg, call, cinfo);
1525 if (cinfo->struct_ret) {
1528 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1529 vtarg->sreg1 = call->vret_var->dreg;
1530 vtarg->dreg = mono_alloc_preg (cfg);
1531 MONO_ADD_INS (cfg->cbb, vtarg);
1533 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1536 call->stack_usage = cinfo->stack_usage;
1537 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1538 cfg->flags |= MONO_CFG_HAS_CALLS;
1544 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1546 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1547 ArgInfo *ainfo = ins->inst_p1;
1548 int ovf_size = ainfo->vtsize;
1549 int doffset = ainfo->offset;
1550 int i, soffset, dreg;
1553 if (ainfo->regtype == RegTypeStructByVal) {
1556 Darwin needs some special handling for 1 and 2 byte arguments
1559 g_assert (ins->klass);
1560 size = mono_class_native_size (ins->klass, NULL);
1561 if (size == 2 || size == 1) {
1562 int tmpr = mono_alloc_ireg (cfg);
1564 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1566 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1567 dreg = mono_alloc_ireg (cfg);
1568 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1569 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1572 for (i = 0; i < ainfo->size; ++i) {
1573 dreg = mono_alloc_ireg (cfg);
1574 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1575 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1576 soffset += sizeof (gpointer);
1579 mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1580 } else if (ainfo->regtype == RegTypeFP) {
1581 int tmpr = mono_alloc_freg (cfg);
1582 if (ainfo->size == 4)
1583 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1585 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1586 dreg = mono_alloc_freg (cfg);
1587 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1588 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1590 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1594 /* FIXME: alignment? */
1595 if (call->signature->pinvoke) {
1596 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1597 vtcopy->backend.is_pinvoke = 1;
1599 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1602 g_assert (ovf_size > 0);
1604 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1605 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1608 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1610 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1615 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1617 MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
1620 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1623 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1624 ins->sreg1 = val->dreg + 1;
1625 ins->sreg2 = val->dreg + 2;
1626 MONO_ADD_INS (cfg->cbb, ins);
1629 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1630 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1634 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1637 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1639 mono_arch_is_inst_imm (gint64 imm)
1645 * Allow tracing to work with this interface (with an optional argument)
1649 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1653 ppc_load (code, ppc_r3, cfg->method);
1654 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1655 ppc_load (code, ppc_r0, func);
1656 ppc_mtlr (code, ppc_r0);
1670 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1673 int save_mode = SAVE_NONE;
1675 MonoMethod *method = cfg->method;
1676 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1677 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1681 offset = code - cfg->native_code;
1682 /* we need about 16 instructions */
1683 if (offset > (cfg->code_size - 16 * 4)) {
1684 cfg->code_size *= 2;
1685 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1686 code = cfg->native_code + offset;
1690 case MONO_TYPE_VOID:
1691 /* special case string .ctor icall */
1692 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1693 save_mode = SAVE_ONE;
1695 save_mode = SAVE_NONE;
1699 save_mode = SAVE_TWO;
1703 save_mode = SAVE_FP;
1705 case MONO_TYPE_VALUETYPE:
1706 save_mode = SAVE_STRUCT;
1709 save_mode = SAVE_ONE;
1713 switch (save_mode) {
1715 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1716 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1717 if (enable_arguments) {
1718 ppc_mr (code, ppc_r5, ppc_r4);
1719 ppc_mr (code, ppc_r4, ppc_r3);
1723 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1724 if (enable_arguments) {
1725 ppc_mr (code, ppc_r4, ppc_r3);
1729 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1730 if (enable_arguments) {
1731 /* FIXME: what reg? */
1732 ppc_fmr (code, ppc_f3, ppc_f1);
1733 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1734 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1738 if (enable_arguments) {
1739 /* FIXME: get the actual address */
1740 ppc_mr (code, ppc_r4, ppc_r3);
1748 ppc_load (code, ppc_r3, cfg->method);
1749 ppc_load (code, ppc_r0, func);
1750 ppc_mtlr (code, ppc_r0);
1753 switch (save_mode) {
1755 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1756 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1759 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1762 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1772 * Conditional branches have a small offset, so if it is likely overflowed,
1773 * we do a branch to the end of the method (uncond branches have much larger
1774 * offsets) where we perform the conditional and jump back unconditionally.
1775 * It's slightly slower, since we add two uncond branches, but it's very simple
1776 * with the current patch implementation and such large methods are likely not
1777 * going to be perf critical anyway.
1782 const char *exception;
1789 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1790 if (ins->flags & MONO_INST_BRLABEL) { \
1791 if (0 && ins->inst_i0->inst_c0) { \
1792 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1794 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1795 ppc_bc (code, (b0), (b1), 0); \
1798 if (0 && ins->inst_true_bb->native_offset) { \
1799 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1801 int br_disp = ins->inst_true_bb->max_offset - offset; \
1802 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1803 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1804 ovfj->data.bb = ins->inst_true_bb; \
1805 ovfj->ip_offset = 0; \
1806 ovfj->b0_cond = (b0); \
1807 ovfj->b1_cond = (b1); \
1808 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1811 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1812 ppc_bc (code, (b0), (b1), 0); \
1817 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1819 /* emit an exception if condition is fail
1821 * We assign the extra code used to throw the implicit exceptions
1822 * to cfg->bb_exit as far as the big branch handling is concerned
1824 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1826 int br_disp = cfg->bb_exit->max_offset - offset; \
1827 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1828 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1829 ovfj->data.exception = (exc_name); \
1830 ovfj->ip_offset = code - cfg->native_code; \
1831 ovfj->b0_cond = (b0); \
1832 ovfj->b1_cond = (b1); \
1833 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1835 cfg->bb_exit->max_offset += 24; \
1837 mono_add_patch_info (cfg, code - cfg->native_code, \
1838 MONO_PATCH_INFO_EXC, exc_name); \
1839 ppc_bcl (code, (b0), (b1), 0); \
1843 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1846 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1851 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1853 MonoInst *ins, *n, *last_ins = NULL;
1855 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1856 switch (ins->opcode) {
1858 /* remove unnecessary multiplication with 1 */
1859 if (ins->inst_imm == 1) {
1860 if (ins->dreg != ins->sreg1) {
1861 ins->opcode = OP_MOVE;
1863 MONO_DELETE_INS (bb, ins);
1867 int power2 = mono_is_power_of_two (ins->inst_imm);
1869 ins->opcode = OP_SHL_IMM;
1870 ins->inst_imm = power2;
1874 case OP_LOAD_MEMBASE:
1875 case OP_LOADI4_MEMBASE:
1877 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1878 * OP_LOAD_MEMBASE offset(basereg), reg
1880 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1881 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1882 ins->inst_basereg == last_ins->inst_destbasereg &&
1883 ins->inst_offset == last_ins->inst_offset) {
1884 if (ins->dreg == last_ins->sreg1) {
1885 MONO_DELETE_INS (bb, ins);
1888 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1889 ins->opcode = OP_MOVE;
1890 ins->sreg1 = last_ins->sreg1;
1894 * Note: reg1 must be different from the basereg in the second load
1895 * OP_LOAD_MEMBASE offset(basereg), reg1
1896 * OP_LOAD_MEMBASE offset(basereg), reg2
1898 * OP_LOAD_MEMBASE offset(basereg), reg1
1899 * OP_MOVE reg1, reg2
1901 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1902 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1903 ins->inst_basereg != last_ins->dreg &&
1904 ins->inst_basereg == last_ins->inst_basereg &&
1905 ins->inst_offset == last_ins->inst_offset) {
1907 if (ins->dreg == last_ins->dreg) {
1908 MONO_DELETE_INS (bb, ins);
1911 ins->opcode = OP_MOVE;
1912 ins->sreg1 = last_ins->dreg;
1915 //g_assert_not_reached ();
1919 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1920 * OP_LOAD_MEMBASE offset(basereg), reg
1922 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1923 * OP_ICONST reg, imm
1925 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1926 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1927 ins->inst_basereg == last_ins->inst_destbasereg &&
1928 ins->inst_offset == last_ins->inst_offset) {
1929 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1930 ins->opcode = OP_ICONST;
1931 ins->inst_c0 = last_ins->inst_imm;
1932 g_assert_not_reached (); // check this rule
1936 case OP_LOADU1_MEMBASE:
1937 case OP_LOADI1_MEMBASE:
1938 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1939 ins->inst_basereg == last_ins->inst_destbasereg &&
1940 ins->inst_offset == last_ins->inst_offset) {
1941 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1942 ins->sreg1 = last_ins->sreg1;
1945 case OP_LOADU2_MEMBASE:
1946 case OP_LOADI2_MEMBASE:
1947 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1948 ins->inst_basereg == last_ins->inst_destbasereg &&
1949 ins->inst_offset == last_ins->inst_offset) {
1950 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1951 ins->sreg1 = last_ins->sreg1;
1955 ins->opcode = OP_MOVE;
1959 if (ins->dreg == ins->sreg1) {
1960 MONO_DELETE_INS (bb, ins);
1964 * OP_MOVE sreg, dreg
1965 * OP_MOVE dreg, sreg
1967 if (last_ins && last_ins->opcode == OP_MOVE &&
1968 ins->sreg1 == last_ins->dreg &&
1969 ins->dreg == last_ins->sreg1) {
1970 MONO_DELETE_INS (bb, ins);
1978 bb->last_ins = last_ins;
1982 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1984 g_assert (cfg->new_ir);
1986 switch (ins->opcode) {
1987 case OP_ICONV_TO_R_UN: {
1988 static const guint64 adjust_val = 0x4330000000000000ULL;
1989 int msw_reg = mono_alloc_ireg (cfg);
1990 int adj_reg = mono_alloc_freg (cfg);
1991 int tmp_reg = mono_alloc_freg (cfg);
1992 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1993 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
1994 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
1995 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1996 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
1997 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1998 ins->opcode = OP_NOP;
2001 case OP_ICONV_TO_R4:
2002 case OP_ICONV_TO_R8: {
2003 /* FIXME: change precision for CEE_CONV_R4 */
2004 static const guint64 adjust_val = 0x4330000080000000ULL;
2005 int msw_reg = mono_alloc_ireg (cfg);
2006 int xored = mono_alloc_ireg (cfg);
2007 int adj_reg = mono_alloc_freg (cfg);
2008 int tmp_reg = mono_alloc_freg (cfg);
2009 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2010 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2011 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2012 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2013 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2014 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2015 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2016 ins->opcode = OP_NOP;
2020 int msw_reg = mono_alloc_ireg (cfg);
2021 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2022 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2023 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2024 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2025 ins->opcode = OP_NOP;
2032 * the branch_b0_table should maintain the order of these
2046 branch_b0_table [] = {
2061 branch_b1_table [] = {
2075 #define NEW_INS(cfg,dest,op) do { \
2076 MONO_INST_NEW((cfg), (dest), (op)); \
2077 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2081 map_to_reg_reg_op (int op)
2090 case OP_COMPARE_IMM:
2092 case OP_ICOMPARE_IMM:
2108 case OP_LOAD_MEMBASE:
2109 return OP_LOAD_MEMINDEX;
2110 case OP_LOADI4_MEMBASE:
2111 return OP_LOADI4_MEMINDEX;
2112 case OP_LOADU4_MEMBASE:
2113 return OP_LOADU4_MEMINDEX;
2114 case OP_LOADU1_MEMBASE:
2115 return OP_LOADU1_MEMINDEX;
2116 case OP_LOADI2_MEMBASE:
2117 return OP_LOADI2_MEMINDEX;
2118 case OP_LOADU2_MEMBASE:
2119 return OP_LOADU2_MEMINDEX;
2120 case OP_LOADI1_MEMBASE:
2121 return OP_LOADI1_MEMINDEX;
2122 case OP_LOADR4_MEMBASE:
2123 return OP_LOADR4_MEMINDEX;
2124 case OP_LOADR8_MEMBASE:
2125 return OP_LOADR8_MEMINDEX;
2126 case OP_STOREI1_MEMBASE_REG:
2127 return OP_STOREI1_MEMINDEX;
2128 case OP_STOREI2_MEMBASE_REG:
2129 return OP_STOREI2_MEMINDEX;
2130 case OP_STOREI4_MEMBASE_REG:
2131 return OP_STOREI4_MEMINDEX;
2132 case OP_STORE_MEMBASE_REG:
2133 return OP_STORE_MEMINDEX;
2134 case OP_STORER4_MEMBASE_REG:
2135 return OP_STORER4_MEMINDEX;
2136 case OP_STORER8_MEMBASE_REG:
2137 return OP_STORER8_MEMINDEX;
2138 case OP_STORE_MEMBASE_IMM:
2139 return OP_STORE_MEMBASE_REG;
2140 case OP_STOREI1_MEMBASE_IMM:
2141 return OP_STOREI1_MEMBASE_REG;
2142 case OP_STOREI2_MEMBASE_IMM:
2143 return OP_STOREI2_MEMBASE_REG;
2144 case OP_STOREI4_MEMBASE_IMM:
2145 return OP_STOREI4_MEMBASE_REG;
2147 return mono_op_imm_to_op (op);
2150 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2152 #define compare_opcode_is_unsigned(opcode) \
2153 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2154 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2155 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2156 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2157 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2159 * Remove from the instruction list the instructions that can't be
2160 * represented with very simple instructions with no register
2164 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2166 MonoInst *ins, *next, *temp, *last_ins = NULL;
2169 /* setup the virtual reg allocator */
2170 if (bb->max_vreg > cfg->rs->next_vreg)
2171 cfg->rs->next_vreg = bb->max_vreg;
2173 MONO_BB_FOR_EACH_INS (bb, ins) {
2175 switch (ins->opcode) {
2176 case OP_IDIV_UN_IMM:
2179 case OP_IREM_UN_IMM:
2180 NEW_INS (cfg, temp, OP_ICONST);
2181 temp->inst_c0 = ins->inst_imm;
2182 temp->dreg = mono_regstate_next_int (cfg->rs);
2183 ins->sreg2 = temp->dreg;
2184 if (ins->opcode == OP_IDIV_IMM)
2185 ins->opcode = OP_IDIV;
2186 else if (ins->opcode == OP_IREM_IMM)
2187 ins->opcode = OP_IREM;
2188 else if (ins->opcode == OP_IDIV_UN_IMM)
2189 ins->opcode = OP_IDIV_UN;
2190 else if (ins->opcode == OP_IREM_UN_IMM)
2191 ins->opcode = OP_IREM_UN;
2193 /* handle rem separately */
2198 /* we change a rem dest, src1, src2 to
2199 * div temp1, src1, src2
2200 * mul temp2, temp1, src2
2201 * sub dest, src1, temp2
2203 NEW_INS (cfg, mul, OP_IMUL);
2204 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2205 temp->sreg1 = ins->sreg1;
2206 temp->sreg2 = ins->sreg2;
2207 temp->dreg = mono_regstate_next_int (cfg->rs);
2208 mul->sreg1 = temp->dreg;
2209 mul->sreg2 = ins->sreg2;
2210 mul->dreg = mono_regstate_next_int (cfg->rs);
2211 ins->opcode = OP_ISUB;
2212 ins->sreg2 = mul->dreg;
2218 if (!ppc_is_imm16 (ins->inst_imm)) {
2219 NEW_INS (cfg, temp, OP_ICONST);
2220 temp->inst_c0 = ins->inst_imm;
2221 temp->dreg = mono_regstate_next_int (cfg->rs);
2222 ins->sreg2 = temp->dreg;
2223 ins->opcode = map_to_reg_reg_op (ins->opcode);
2228 if (!ppc_is_imm16 (-ins->inst_imm)) {
2229 NEW_INS (cfg, temp, OP_ICONST);
2230 temp->inst_c0 = ins->inst_imm;
2231 temp->dreg = mono_regstate_next_int (cfg->rs);
2232 ins->sreg2 = temp->dreg;
2233 ins->opcode = map_to_reg_reg_op (ins->opcode);
2242 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2243 NEW_INS (cfg, temp, OP_ICONST);
2244 temp->inst_c0 = ins->inst_imm;
2245 temp->dreg = mono_regstate_next_int (cfg->rs);
2246 ins->sreg2 = temp->dreg;
2247 ins->opcode = map_to_reg_reg_op (ins->opcode);
2255 NEW_INS (cfg, temp, OP_ICONST);
2256 temp->inst_c0 = ins->inst_imm;
2257 temp->dreg = mono_regstate_next_int (cfg->rs);
2258 ins->sreg2 = temp->dreg;
2259 ins->opcode = map_to_reg_reg_op (ins->opcode);
2261 case OP_COMPARE_IMM:
2262 case OP_ICOMPARE_IMM:
2264 /* Branch opts can eliminate the branch */
2265 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2266 ins->opcode = OP_NOP;
2270 if (compare_opcode_is_unsigned (next->opcode)) {
2271 if (!ppc_is_uimm16 (ins->inst_imm)) {
2272 NEW_INS (cfg, temp, OP_ICONST);
2273 temp->inst_c0 = ins->inst_imm;
2274 temp->dreg = mono_regstate_next_int (cfg->rs);
2275 ins->sreg2 = temp->dreg;
2276 ins->opcode = map_to_reg_reg_op (ins->opcode);
2279 if (!ppc_is_imm16 (ins->inst_imm)) {
2280 NEW_INS (cfg, temp, OP_ICONST);
2281 temp->inst_c0 = ins->inst_imm;
2282 temp->dreg = mono_regstate_next_int (cfg->rs);
2283 ins->sreg2 = temp->dreg;
2284 ins->opcode = map_to_reg_reg_op (ins->opcode);
2290 if (ins->inst_imm == 1) {
2291 ins->opcode = OP_MOVE;
2294 if (ins->inst_imm == 0) {
2295 ins->opcode = OP_ICONST;
2299 imm = mono_is_power_of_two (ins->inst_imm);
2301 ins->opcode = OP_SHL_IMM;
2302 ins->inst_imm = imm;
2305 if (!ppc_is_imm16 (ins->inst_imm)) {
2306 NEW_INS (cfg, temp, OP_ICONST);
2307 temp->inst_c0 = ins->inst_imm;
2308 temp->dreg = mono_regstate_next_int (cfg->rs);
2309 ins->sreg2 = temp->dreg;
2310 ins->opcode = map_to_reg_reg_op (ins->opcode);
2313 case OP_LOCALLOC_IMM:
2314 NEW_INS (cfg, temp, OP_ICONST);
2315 temp->inst_c0 = ins->inst_imm;
2316 temp->dreg = mono_regstate_next_int (cfg->rs);
2317 ins->sreg1 = temp->dreg;
2318 ins->opcode = OP_LOCALLOC;
2320 case OP_LOAD_MEMBASE:
2321 case OP_LOADI4_MEMBASE:
2322 case OP_LOADU4_MEMBASE:
2323 case OP_LOADI2_MEMBASE:
2324 case OP_LOADU2_MEMBASE:
2325 case OP_LOADI1_MEMBASE:
2326 case OP_LOADU1_MEMBASE:
2327 case OP_LOADR4_MEMBASE:
2328 case OP_LOADR8_MEMBASE:
2329 case OP_STORE_MEMBASE_REG:
2330 case OP_STOREI4_MEMBASE_REG:
2331 case OP_STOREI2_MEMBASE_REG:
2332 case OP_STOREI1_MEMBASE_REG:
2333 case OP_STORER4_MEMBASE_REG:
2334 case OP_STORER8_MEMBASE_REG:
2335 /* we can do two things: load the immed in a register
2336 * and use an indexed load, or see if the immed can be
2337 * represented as an ad_imm + a load with a smaller offset
2338 * that fits. We just do the first for now, optimize later.
2340 if (ppc_is_imm16 (ins->inst_offset))
2342 NEW_INS (cfg, temp, OP_ICONST);
2343 temp->inst_c0 = ins->inst_offset;
2344 temp->dreg = mono_regstate_next_int (cfg->rs);
2345 ins->sreg2 = temp->dreg;
2346 ins->opcode = map_to_reg_reg_op (ins->opcode);
2348 case OP_STORE_MEMBASE_IMM:
2349 case OP_STOREI1_MEMBASE_IMM:
2350 case OP_STOREI2_MEMBASE_IMM:
2351 case OP_STOREI4_MEMBASE_IMM:
2352 NEW_INS (cfg, temp, OP_ICONST);
2353 temp->inst_c0 = ins->inst_imm;
2354 temp->dreg = mono_regstate_next_int (cfg->rs);
2355 ins->sreg1 = temp->dreg;
2356 ins->opcode = map_to_reg_reg_op (ins->opcode);
2358 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2361 NEW_INS (cfg, temp, OP_ICONST);
2362 temp->inst_c0 = (guint32)ins->inst_p0;
2363 temp->dreg = mono_regstate_next_int (cfg->rs);
2364 ins->inst_basereg = temp->dreg;
2365 ins->inst_offset = 0;
2366 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2368 /* make it handle the possibly big ins->inst_offset
2369 * later optimize to use lis + load_membase
2375 bb->last_ins = last_ins;
2376 bb->max_vreg = cfg->rs->next_vreg;
2381 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2383 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2384 ppc_fctiwz (code, ppc_f0, sreg);
2385 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2386 ppc_lwz (code, dreg, -4, ppc_sp);
2389 ppc_andid (code, dreg, dreg, 0xff);
2391 ppc_andid (code, dreg, dreg, 0xffff);
2394 ppc_extsb (code, dreg, dreg);
2396 ppc_extsh (code, dreg, dreg);
2401 static unsigned char*
2402 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2405 int sreg = tree->sreg1;
2406 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2407 if (tree->flags & MONO_INST_INIT) {
2409 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2410 x86_push_reg (code, X86_EAX);
2413 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2414 x86_push_reg (code, X86_ECX);
2417 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2418 x86_push_reg (code, X86_EDI);
2422 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2423 if (sreg != X86_ECX)
2424 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2425 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2427 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2429 x86_prefix (code, X86_REP_PREFIX);
2432 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2433 x86_pop_reg (code, X86_EDI);
2434 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2435 x86_pop_reg (code, X86_ECX);
2436 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2437 x86_pop_reg (code, X86_EAX);
2445 const guchar *target;
2450 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2453 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2454 PatchData *pdata = (PatchData*)user_data;
2455 guchar *code = data;
2456 guint32 *thunks = data;
2457 guint32 *endthunks = (guint32*)(code + bsize);
2461 int difflow, diffhigh;
2463 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2464 difflow = (char*)pdata->code - (char*)thunks;
2465 diffhigh = (char*)pdata->code - (char*)endthunks;
2466 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2469 templ = (guchar*)load;
2470 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2471 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2473 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2474 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2475 while (thunks < endthunks) {
2476 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2477 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2478 ppc_patch (pdata->code, (guchar*)thunks);
2479 mono_arch_flush_icache (pdata->code, 4);
2482 static int num_thunks = 0;
2484 if ((num_thunks % 20) == 0)
2485 g_print ("num_thunks lookup: %d\n", num_thunks);
2488 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2489 /* found a free slot instead: emit thunk */
2490 code = (guchar*)thunks;
2491 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2492 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2493 ppc_mtctr (code, ppc_r0);
2494 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2495 mono_arch_flush_icache ((guchar*)thunks, 16);
2497 ppc_patch (pdata->code, (guchar*)thunks);
2498 mono_arch_flush_icache (pdata->code, 4);
2501 static int num_thunks = 0;
2503 if ((num_thunks % 20) == 0)
2504 g_print ("num_thunks: %d\n", num_thunks);
2508 /* skip 16 bytes, the size of the thunk */
2512 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2518 handle_thunk (int absolute, guchar *code, const guchar *target) {
2519 MonoDomain *domain = mono_domain_get ();
2523 pdata.target = target;
2524 pdata.absolute = absolute;
2527 mono_domain_lock (domain);
2528 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2531 /* this uses the first available slot */
2533 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2535 mono_domain_unlock (domain);
2537 if (pdata.found != 1)
2538 g_print ("thunk failed for %p from %p\n", target, code);
2539 g_assert (pdata.found == 1);
2543 ppc_patch (guchar *code, const guchar *target)
2545 guint32 ins = *(guint32*)code;
2546 guint32 prim = ins >> 26;
2549 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2551 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2552 gint diff = target - code;
2554 if (diff <= 33554431){
2555 ins = (18 << 26) | (diff) | (ins & 1);
2556 *(guint32*)code = ins;
2560 /* diff between 0 and -33554432 */
2561 if (diff >= -33554432){
2562 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2563 *(guint32*)code = ins;
2568 if ((glong)target >= 0){
2569 if ((glong)target <= 33554431){
2570 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2571 *(guint32*)code = ins;
2575 if ((glong)target >= -33554432){
2576 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2577 *(guint32*)code = ins;
2582 handle_thunk (TRUE, code, target);
2585 g_assert_not_reached ();
2592 guint32 li = (guint32)target;
2593 ins = (ins & 0xffff0000) | (ins & 3);
2594 ovf = li & 0xffff0000;
2595 if (ovf != 0 && ovf != 0xffff0000)
2596 g_assert_not_reached ();
2599 // FIXME: assert the top bits of li are 0
2601 gint diff = target - code;
2602 ins = (ins & 0xffff0000) | (ins & 3);
2603 ovf = diff & 0xffff0000;
2604 if (ovf != 0 && ovf != 0xffff0000)
2605 g_assert_not_reached ();
2609 *(guint32*)code = ins;
2613 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2615 /* the trampoline code will try to patch the blrl, blr, bcctr */
2616 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2619 /* this is the lis/ori/mtlr/blrl sequence */
2620 seq = (guint32*)code;
2621 g_assert ((seq [0] >> 26) == 15);
2622 g_assert ((seq [1] >> 26) == 24);
2623 g_assert ((seq [2] >> 26) == 31);
2624 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2625 /* FIXME: make this thread safe */
2626 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2627 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2628 mono_arch_flush_icache (code - 8, 8);
2630 g_assert_not_reached ();
2632 // g_print ("patched with 0x%08x\n", ins);
2636 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2638 switch (ins->opcode) {
2641 case OP_FCALL_MEMBASE:
2642 if (ins->dreg != ppc_f1)
2643 ppc_fmr (code, ins->dreg, ppc_f1);
2651 * emit_load_volatile_arguments:
2653 * Load volatile arguments from the stack to the original input registers.
2654 * Required before a tail call.
2657 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2659 MonoMethod *method = cfg->method;
2660 MonoMethodSignature *sig;
2664 int struct_index = 0;
2666 /* FIXME: Generate intermediate code instead */
2668 sig = mono_method_signature (method);
2670 /* This is the opposite of the code in emit_prolog */
2674 cinfo = calculate_sizes (sig, sig->pinvoke);
2676 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2677 ArgInfo *ainfo = &cinfo->ret;
2678 inst = cfg->vret_addr;
2679 g_assert (ppc_is_imm16 (inst->inst_offset));
2680 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2682 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2683 ArgInfo *ainfo = cinfo->args + i;
2684 inst = cfg->args [pos];
2686 g_assert (inst->opcode != OP_REGVAR);
2687 g_assert (ppc_is_imm16 (inst->inst_offset));
2689 switch (ainfo->regtype) {
2690 case RegTypeGeneral:
2691 switch (ainfo->size) {
2693 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2696 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2699 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2705 switch (ainfo->size) {
2707 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2710 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2713 g_assert_not_reached ();
2718 case RegTypeStructByVal:
2722 case RegTypeStructByAddr: {
2723 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2725 g_assert (ppc_is_imm16 (addr->inst_offset));
2726 g_assert (!ainfo->offset);
2727 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2734 g_assert_not_reached ();
2746 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2748 MonoInst *ins, *next;
2751 guint8 *code = cfg->native_code + cfg->code_len;
2752 MonoInst *last_ins = NULL;
2753 guint last_offset = 0;
2756 /* we don't align basic blocks of loops on ppc */
2758 if (cfg->verbose_level > 2)
2759 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2761 cpos = bb->max_offset;
2763 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2764 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2765 //g_assert (!mono_compile_aot);
2768 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2769 /* this is not thread save, but good enough */
2770 /* fixme: howto handle overflows? */
2771 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2774 MONO_BB_FOR_EACH_INS (bb, ins) {
2775 offset = code - cfg->native_code;
2777 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2779 if (offset > (cfg->code_size - max_len - 16)) {
2780 cfg->code_size *= 2;
2781 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2782 code = cfg->native_code + offset;
2784 // if (ins->cil_code)
2785 // g_print ("cil code\n");
2786 mono_debug_record_line_number (cfg, ins, offset);
2788 switch (ins->opcode) {
2791 case OP_DUMMY_STORE:
2792 case OP_NOT_REACHED:
2796 emit_tls_access (code, ins->dreg, ins->inst_offset);
2799 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2800 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2801 ppc_mr (code, ppc_r4, ppc_r0);
2804 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2805 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2806 ppc_mr (code, ppc_r4, ppc_r0);
2808 case OP_MEMORY_BARRIER:
2811 case OP_STOREI1_MEMBASE_REG:
2812 if (ppc_is_imm16 (ins->inst_offset)) {
2813 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2815 ppc_load (code, ppc_r0, ins->inst_offset);
2816 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2819 case OP_STOREI2_MEMBASE_REG:
2820 if (ppc_is_imm16 (ins->inst_offset)) {
2821 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2823 ppc_load (code, ppc_r0, ins->inst_offset);
2824 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2827 case OP_STORE_MEMBASE_REG:
2828 case OP_STOREI4_MEMBASE_REG:
2829 if (ppc_is_imm16 (ins->inst_offset)) {
2830 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2832 ppc_load (code, ppc_r0, ins->inst_offset);
2833 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2836 case OP_STOREI1_MEMINDEX:
2837 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2839 case OP_STOREI2_MEMINDEX:
2840 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2842 case OP_STORE_MEMINDEX:
2843 case OP_STOREI4_MEMINDEX:
2844 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2847 g_assert_not_reached ();
2849 case OP_LOAD_MEMBASE:
2850 case OP_LOADI4_MEMBASE:
2851 case OP_LOADU4_MEMBASE:
2852 if (ppc_is_imm16 (ins->inst_offset)) {
2853 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2855 ppc_load (code, ppc_r0, ins->inst_offset);
2856 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2859 case OP_LOADI1_MEMBASE:
2860 case OP_LOADU1_MEMBASE:
2861 if (ppc_is_imm16 (ins->inst_offset)) {
2862 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2864 ppc_load (code, ppc_r0, ins->inst_offset);
2865 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2867 if (ins->opcode == OP_LOADI1_MEMBASE)
2868 ppc_extsb (code, ins->dreg, ins->dreg);
2870 case OP_LOADU2_MEMBASE:
2871 if (ppc_is_imm16 (ins->inst_offset)) {
2872 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2874 ppc_load (code, ppc_r0, ins->inst_offset);
2875 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2878 case OP_LOADI2_MEMBASE:
2879 if (ppc_is_imm16 (ins->inst_offset)) {
2880 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2882 ppc_load (code, ppc_r0, ins->inst_offset);
2883 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2886 case OP_LOAD_MEMINDEX:
2887 case OP_LOADI4_MEMINDEX:
2888 case OP_LOADU4_MEMINDEX:
2889 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2891 case OP_LOADU2_MEMINDEX:
2892 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2894 case OP_LOADI2_MEMINDEX:
2895 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2897 case OP_LOADU1_MEMINDEX:
2898 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2900 case OP_LOADI1_MEMINDEX:
2901 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2902 ppc_extsb (code, ins->dreg, ins->dreg);
2904 case OP_ICONV_TO_I1:
2905 ppc_extsb (code, ins->dreg, ins->sreg1);
2907 case OP_ICONV_TO_I2:
2908 ppc_extsh (code, ins->dreg, ins->sreg1);
2910 case OP_ICONV_TO_U1:
2911 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2913 case OP_ICONV_TO_U2:
2914 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2919 if (next && compare_opcode_is_unsigned (next->opcode))
2920 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2922 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2924 case OP_COMPARE_IMM:
2925 case OP_ICOMPARE_IMM:
2927 if (next && compare_opcode_is_unsigned (next->opcode)) {
2928 if (ppc_is_uimm16 (ins->inst_imm)) {
2929 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2931 g_assert_not_reached ();
2934 if (ppc_is_imm16 (ins->inst_imm)) {
2935 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2937 g_assert_not_reached ();
2946 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2949 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2953 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2956 if (ppc_is_imm16 (ins->inst_imm)) {
2957 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2959 g_assert_not_reached ();
2964 if (ppc_is_imm16 (ins->inst_imm)) {
2965 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2967 g_assert_not_reached ();
2971 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2973 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2974 ppc_mfspr (code, ppc_r0, ppc_xer);
2975 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2976 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2978 case OP_IADD_OVF_UN:
2979 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2981 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2982 ppc_mfspr (code, ppc_r0, ppc_xer);
2983 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2984 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2987 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2989 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2990 ppc_mfspr (code, ppc_r0, ppc_xer);
2991 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2992 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2994 case OP_ISUB_OVF_UN:
2995 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2997 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2998 ppc_mfspr (code, ppc_r0, ppc_xer);
2999 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3000 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3002 case OP_ADD_OVF_CARRY:
3003 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3005 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3006 ppc_mfspr (code, ppc_r0, ppc_xer);
3007 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3008 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3010 case OP_ADD_OVF_UN_CARRY:
3011 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3013 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3014 ppc_mfspr (code, ppc_r0, ppc_xer);
3015 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3016 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3018 case OP_SUB_OVF_CARRY:
3019 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3021 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3022 ppc_mfspr (code, ppc_r0, ppc_xer);
3023 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3024 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3026 case OP_SUB_OVF_UN_CARRY:
3027 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3029 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3030 ppc_mfspr (code, ppc_r0, ppc_xer);
3031 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3032 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3036 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3039 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3043 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3047 // we add the negated value
3048 if (ppc_is_imm16 (-ins->inst_imm))
3049 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3051 g_assert_not_reached ();
3055 g_assert (ppc_is_imm16 (ins->inst_imm));
3056 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3059 ppc_subfze (code, ins->dreg, ins->sreg1);
3062 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3063 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3067 if (!(ins->inst_imm & 0xffff0000)) {
3068 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3069 } else if (!(ins->inst_imm & 0xffff)) {
3070 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3072 g_assert_not_reached ();
3076 guint8 *divisor_is_m1;
3077 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3079 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3080 divisor_is_m1 = code;
3081 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3082 ppc_lis (code, ppc_r0, 0x8000);
3083 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3084 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3085 ppc_patch (divisor_is_m1, code);
3086 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3088 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3089 ppc_mfspr (code, ppc_r0, ppc_xer);
3090 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3091 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3095 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3096 ppc_mfspr (code, ppc_r0, ppc_xer);
3097 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3098 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3104 g_assert_not_reached ();
3106 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3110 if (!(ins->inst_imm & 0xffff0000)) {
3111 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3112 } else if (!(ins->inst_imm & 0xffff)) {
3113 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3115 g_assert_not_reached ();
3119 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3123 if (!(ins->inst_imm & 0xffff0000)) {
3124 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3125 } else if (!(ins->inst_imm & 0xffff)) {
3126 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3128 g_assert_not_reached ();
3132 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3136 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3139 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3143 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3146 case OP_ISHR_UN_IMM:
3148 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3150 ppc_mr (code, ins->dreg, ins->sreg1);
3153 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3156 ppc_not (code, ins->dreg, ins->sreg1);
3159 ppc_neg (code, ins->dreg, ins->sreg1);
3162 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3166 if (ppc_is_imm16 (ins->inst_imm)) {
3167 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3169 g_assert_not_reached ();
3173 /* we annot use mcrxr, since it's not implemented on some processors
3174 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3176 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3177 ppc_mfspr (code, ppc_r0, ppc_xer);
3178 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3179 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3181 case OP_IMUL_OVF_UN:
3182 /* we first multiply to get the high word and compare to 0
3183 * to set the flags, then the result is discarded and then
3184 * we multiply to get the lower * bits result
3186 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3187 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3188 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3189 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3192 ppc_load (code, ins->dreg, ins->inst_c0);
3195 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3196 ppc_lis (code, ins->dreg, 0);
3197 ppc_ori (code, ins->dreg, ins->dreg, 0);
3199 case OP_ICONV_TO_I4:
3200 case OP_ICONV_TO_U4:
3202 ppc_mr (code, ins->dreg, ins->sreg1);
3205 int saved = ins->sreg1;
3206 if (ins->sreg1 == ppc_r3) {
3207 ppc_mr (code, ppc_r0, ins->sreg1);
3210 if (ins->sreg2 != ppc_r3)
3211 ppc_mr (code, ppc_r3, ins->sreg2);
3212 if (saved != ppc_r4)
3213 ppc_mr (code, ppc_r4, saved);
3217 ppc_fmr (code, ins->dreg, ins->sreg1);
3219 case OP_FCONV_TO_R4:
3220 ppc_frsp (code, ins->dreg, ins->sreg1);
3226 * Keep in sync with mono_arch_emit_epilog
3228 g_assert (!cfg->method->save_lmf);
3230 * Note: we can use ppc_r11 here because it is dead anyway:
3231 * we're leaving the method.
3233 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3234 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3235 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3237 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3238 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3240 ppc_mtlr (code, ppc_r0);
3243 code = emit_load_volatile_arguments (cfg, code);
3245 if (ppc_is_imm16 (cfg->stack_usage)) {
3246 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3248 ppc_load (code, ppc_r11, cfg->stack_usage);
3249 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3251 if (!cfg->method->save_lmf) {
3252 /*for (i = 31; i >= 14; --i) {
3253 if (cfg->used_float_regs & (1 << i)) {
3254 pos += sizeof (double);
3255 ppc_lfd (code, i, -pos, cfg->frame_reg);
3258 for (i = 31; i >= 13; --i) {
3259 if (cfg->used_int_regs & (1 << i)) {
3260 pos += sizeof (gulong);
3261 ppc_lwz (code, i, -pos, cfg->frame_reg);
3265 /* FIXME restore from MonoLMF: though this can't happen yet */
3267 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3272 /* ensure ins->sreg1 is not NULL */
3273 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3276 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3277 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3279 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3280 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3282 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3291 call = (MonoCallInst*)ins;
3292 if (ins->flags & MONO_INST_HAS_METHOD)
3293 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3295 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3296 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3297 ppc_lis (code, ppc_r0, 0);
3298 ppc_ori (code, ppc_r0, ppc_r0, 0);
3299 ppc_mtlr (code, ppc_r0);
3304 /* FIXME: this should be handled somewhere else in the new jit */
3305 code = emit_move_return_value (cfg, ins, code);
3311 case OP_VOIDCALL_REG:
3313 ppc_mtlr (code, ins->sreg1);
3315 /* FIXME: this should be handled somewhere else in the new jit */
3316 code = emit_move_return_value (cfg, ins, code);
3318 case OP_FCALL_MEMBASE:
3319 case OP_LCALL_MEMBASE:
3320 case OP_VCALL_MEMBASE:
3321 case OP_VCALL2_MEMBASE:
3322 case OP_VOIDCALL_MEMBASE:
3323 case OP_CALL_MEMBASE:
3324 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3325 ppc_mtlr (code, ppc_r0);
3327 /* FIXME: this should be handled somewhere else in the new jit */
3328 code = emit_move_return_value (cfg, ins, code);
3331 g_assert_not_reached ();
3334 guint8 * zero_loop_jump, * zero_loop_start;
3335 /* keep alignment */
3336 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3337 int area_offset = alloca_waste;
3339 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3340 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3341 /* use ctr to store the number of words to 0 if needed */
3342 if (ins->flags & MONO_INST_INIT) {
3343 /* we zero 4 bytes at a time:
3344 * we add 7 instead of 3 so that we set the counter to
3345 * at least 1, otherwise the bdnz instruction will make
3346 * it negative and iterate billions of times.
3348 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3349 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3350 ppc_mtctr (code, ppc_r0);
3352 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3353 ppc_neg (code, ppc_r11, ppc_r11);
3354 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3356 if (ins->flags & MONO_INST_INIT) {
3357 /* adjust the dest reg by -4 so we can use stwu */
3358 /* we actually adjust -8 because we let the loop
3361 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3362 ppc_li (code, ppc_r11, 0);
3363 zero_loop_start = code;
3364 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3365 zero_loop_jump = code;
3366 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3367 ppc_patch (zero_loop_jump, zero_loop_start);
3369 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3374 ppc_mr (code, ppc_r3, ins->sreg1);
3375 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3376 (gpointer)"mono_arch_throw_exception");
3377 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3378 ppc_lis (code, ppc_r0, 0);
3379 ppc_ori (code, ppc_r0, ppc_r0, 0);
3380 ppc_mtlr (code, ppc_r0);
3389 ppc_mr (code, ppc_r3, ins->sreg1);
3390 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3391 (gpointer)"mono_arch_rethrow_exception");
3392 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3393 ppc_lis (code, ppc_r0, 0);
3394 ppc_ori (code, ppc_r0, ppc_r0, 0);
3395 ppc_mtlr (code, ppc_r0);
3402 case OP_START_HANDLER: {
3403 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3404 ppc_mflr (code, ppc_r0);
3405 if (ppc_is_imm16 (spvar->inst_offset)) {
3406 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3408 ppc_load (code, ppc_r11, spvar->inst_offset);
3409 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3413 case OP_ENDFILTER: {
3414 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3415 if (ins->sreg1 != ppc_r3)
3416 ppc_mr (code, ppc_r3, ins->sreg1);
3417 if (ppc_is_imm16 (spvar->inst_offset)) {
3418 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3420 ppc_load (code, ppc_r11, spvar->inst_offset);
3421 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3423 ppc_mtlr (code, ppc_r0);
3427 case OP_ENDFINALLY: {
3428 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3429 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3430 ppc_mtlr (code, ppc_r0);
3434 case OP_CALL_HANDLER:
3435 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3439 ins->inst_c0 = code - cfg->native_code;
3442 if (ins->flags & MONO_INST_BRLABEL) {
3443 /*if (ins->inst_i0->inst_c0) {
3445 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3447 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3451 /*if (ins->inst_target_bb->native_offset) {
3453 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3455 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3461 ppc_mtctr (code, ins->sreg1);
3462 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3466 ppc_li (code, ins->dreg, 0);
3467 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3468 ppc_li (code, ins->dreg, 1);
3474 ppc_li (code, ins->dreg, 1);
3475 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3476 ppc_li (code, ins->dreg, 0);
3482 ppc_li (code, ins->dreg, 1);
3483 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3484 ppc_li (code, ins->dreg, 0);
3486 case OP_COND_EXC_EQ:
3487 case OP_COND_EXC_NE_UN:
3488 case OP_COND_EXC_LT:
3489 case OP_COND_EXC_LT_UN:
3490 case OP_COND_EXC_GT:
3491 case OP_COND_EXC_GT_UN:
3492 case OP_COND_EXC_GE:
3493 case OP_COND_EXC_GE_UN:
3494 case OP_COND_EXC_LE:
3495 case OP_COND_EXC_LE_UN:
3496 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3498 case OP_COND_EXC_IEQ:
3499 case OP_COND_EXC_INE_UN:
3500 case OP_COND_EXC_ILT:
3501 case OP_COND_EXC_ILT_UN:
3502 case OP_COND_EXC_IGT:
3503 case OP_COND_EXC_IGT_UN:
3504 case OP_COND_EXC_IGE:
3505 case OP_COND_EXC_IGE_UN:
3506 case OP_COND_EXC_ILE:
3507 case OP_COND_EXC_ILE_UN:
3508 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3511 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3513 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3514 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3515 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3517 case OP_COND_EXC_OV:
3518 /*ppc_mcrxr (code, 0);
3519 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3521 case OP_COND_EXC_NC:
3522 case OP_COND_EXC_NO:
3523 g_assert_not_reached ();
3535 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3538 /* floating point opcodes */
3541 g_assert_not_reached ();
3542 case OP_STORER8_MEMBASE_REG:
3543 if (ppc_is_imm16 (ins->inst_offset)) {
3544 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3546 ppc_load (code, ppc_r0, ins->inst_offset);
3547 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3550 case OP_LOADR8_MEMBASE:
3551 if (ppc_is_imm16 (ins->inst_offset)) {
3552 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3554 ppc_load (code, ppc_r0, ins->inst_offset);
3555 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3558 case OP_STORER4_MEMBASE_REG:
3559 ppc_frsp (code, ins->sreg1, ins->sreg1);
3560 if (ppc_is_imm16 (ins->inst_offset)) {
3561 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3563 ppc_load (code, ppc_r0, ins->inst_offset);
3564 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3567 case OP_LOADR4_MEMBASE:
3568 if (ppc_is_imm16 (ins->inst_offset)) {
3569 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3571 ppc_load (code, ppc_r0, ins->inst_offset);
3572 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3575 case OP_LOADR4_MEMINDEX:
3576 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3578 case OP_LOADR8_MEMINDEX:
3579 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3581 case OP_STORER4_MEMINDEX:
3582 ppc_frsp (code, ins->sreg1, ins->sreg1);
3583 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3585 case OP_STORER8_MEMINDEX:
3586 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3589 case CEE_CONV_R4: /* FIXME: change precision */
3591 g_assert_not_reached ();
3592 case OP_FCONV_TO_I1:
3593 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3595 case OP_FCONV_TO_U1:
3596 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3598 case OP_FCONV_TO_I2:
3599 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3601 case OP_FCONV_TO_U2:
3602 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3604 case OP_FCONV_TO_I4:
3606 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3608 case OP_FCONV_TO_U4:
3610 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3612 case OP_FCONV_TO_I8:
3613 case OP_FCONV_TO_U8:
3614 g_assert_not_reached ();
3615 /* Implemented as helper calls */
3617 case OP_LCONV_TO_R_UN:
3618 g_assert_not_reached ();
3619 /* Implemented as helper calls */
3621 case OP_LCONV_TO_OVF_I4_2:
3622 case OP_LCONV_TO_OVF_I: {
3623 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3624 // Check if its negative
3625 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3626 negative_branch = code;
3627 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3628 // Its positive msword == 0
3629 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3630 msword_positive_branch = code;
3631 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3633 ovf_ex_target = code;
3634 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3636 ppc_patch (negative_branch, code);
3637 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3638 msword_negative_branch = code;
3639 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3640 ppc_patch (msword_negative_branch, ovf_ex_target);
3642 ppc_patch (msword_positive_branch, code);
3643 if (ins->dreg != ins->sreg1)
3644 ppc_mr (code, ins->dreg, ins->sreg1);
3648 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3651 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3654 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3657 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3660 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3663 ppc_fneg (code, ins->dreg, ins->sreg1);
3667 g_assert_not_reached ();
3670 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3673 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3674 ppc_li (code, ins->dreg, 0);
3675 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3676 ppc_li (code, ins->dreg, 1);
3679 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3680 ppc_li (code, ins->dreg, 1);
3681 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3682 ppc_li (code, ins->dreg, 0);
3685 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3686 ppc_li (code, ins->dreg, 1);
3687 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3688 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3689 ppc_li (code, ins->dreg, 0);
3692 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3693 ppc_li (code, ins->dreg, 1);
3694 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3695 ppc_li (code, ins->dreg, 0);
3698 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3699 ppc_li (code, ins->dreg, 1);
3700 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3701 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3702 ppc_li (code, ins->dreg, 0);
3705 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3708 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3711 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3712 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3715 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3716 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3719 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3720 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3723 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3724 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3727 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3728 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3731 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3734 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3735 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3738 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3741 g_assert_not_reached ();
3742 case OP_CHECK_FINITE: {
3743 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3744 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3745 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3746 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3749 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3750 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3754 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3755 g_assert_not_reached ();
3758 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3759 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3760 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3761 g_assert_not_reached ();
3767 last_offset = offset;
3770 cfg->code_len = code - cfg->native_code;
3774 mono_arch_register_lowlevel_calls (void)
3778 #define patch_lis_ori(ip,val) do {\
3779 guint16 *__lis_ori = (guint16*)(ip); \
3780 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3781 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3785 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3787 MonoJumpInfo *patch_info;
3789 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3790 unsigned char *ip = patch_info->ip.i + code;
3791 unsigned char *target;
3793 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3795 switch (patch_info->type) {
3796 case MONO_PATCH_INFO_IP:
3797 patch_lis_ori (ip, ip);
3799 case MONO_PATCH_INFO_METHOD_REL:
3800 g_assert_not_reached ();
3801 *((gpointer *)(ip)) = code + patch_info->data.offset;
3803 case MONO_PATCH_INFO_SWITCH: {
3804 gpointer *table = (gpointer *)patch_info->data.table->table;
3807 patch_lis_ori (ip, table);
3809 for (i = 0; i < patch_info->data.table->table_size; i++) {
3810 table [i] = (int)patch_info->data.table->table [i] + code;
3812 /* we put into the table the absolute address, no need for ppc_patch in this case */
3815 case MONO_PATCH_INFO_METHODCONST:
3816 case MONO_PATCH_INFO_CLASS:
3817 case MONO_PATCH_INFO_IMAGE:
3818 case MONO_PATCH_INFO_FIELD:
3819 case MONO_PATCH_INFO_VTABLE:
3820 case MONO_PATCH_INFO_IID:
3821 case MONO_PATCH_INFO_SFLDA:
3822 case MONO_PATCH_INFO_LDSTR:
3823 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3824 case MONO_PATCH_INFO_LDTOKEN:
3825 /* from OP_AOTCONST : lis + ori */
3826 patch_lis_ori (ip, target);
3828 case MONO_PATCH_INFO_R4:
3829 case MONO_PATCH_INFO_R8:
3830 g_assert_not_reached ();
3831 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3833 case MONO_PATCH_INFO_EXC_NAME:
3834 g_assert_not_reached ();
3835 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3837 case MONO_PATCH_INFO_NONE:
3838 case MONO_PATCH_INFO_BB_OVF:
3839 case MONO_PATCH_INFO_EXC_OVF:
3840 /* everything is dealt with at epilog output time */
3845 ppc_patch (ip, target);
3850 * Stack frame layout:
3852 * ------------------- sp
3853 * MonoLMF structure or saved registers
3854 * -------------------
3856 * -------------------
3858 * -------------------
3859 * optional 8 bytes for tracing
3860 * -------------------
3861 * param area size is cfg->param_area
3862 * -------------------
3863 * linkage area size is PPC_STACK_PARAM_OFFSET
3864 * ------------------- sp
3868 mono_arch_emit_prolog (MonoCompile *cfg)
3870 MonoMethod *method = cfg->method;
3872 MonoMethodSignature *sig;
3874 int alloc_size, pos, max_offset, i;
3879 int tailcall_struct_index;
3881 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3884 sig = mono_method_signature (method);
3885 cfg->code_size = 256 + sig->param_count * 20;
3886 code = cfg->native_code = g_malloc (cfg->code_size);
3888 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3889 ppc_mflr (code, ppc_r0);
3890 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3893 alloc_size = cfg->stack_offset;
3896 if (!method->save_lmf) {
3897 /*for (i = 31; i >= 14; --i) {
3898 if (cfg->used_float_regs & (1 << i)) {
3899 pos += sizeof (gdouble);
3900 ppc_stfd (code, i, -pos, ppc_sp);
3903 for (i = 31; i >= 13; --i) {
3904 if (cfg->used_int_regs & (1 << i)) {
3905 pos += sizeof (gulong);
3906 ppc_stw (code, i, -pos, ppc_sp);
3911 pos += sizeof (MonoLMF);
3913 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3914 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3915 for (i = 14; i < 32; i++) {
3916 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3920 // align to PPC_STACK_ALIGNMENT bytes
3921 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3922 alloc_size += PPC_STACK_ALIGNMENT - 1;
3923 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3926 cfg->stack_usage = alloc_size;
3927 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3929 if (ppc_is_imm16 (-alloc_size)) {
3930 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3932 ppc_load (code, ppc_r11, -alloc_size);
3933 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3936 if (cfg->frame_reg != ppc_sp)
3937 ppc_mr (code, cfg->frame_reg, ppc_sp);
3939 /* compute max_offset in order to use short forward jumps
3940 * we always do it on ppc because the immediate displacement
3941 * for jumps is too small
3944 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3946 bb->max_offset = max_offset;
3948 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3951 MONO_BB_FOR_EACH_INS (bb, ins)
3952 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3955 /* load arguments allocated to register from the stack */
3958 cinfo = calculate_sizes (sig, sig->pinvoke);
3960 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3961 ArgInfo *ainfo = &cinfo->ret;
3964 inst = cfg->vret_addr;
3969 if (ppc_is_imm16 (inst->inst_offset)) {
3970 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3972 ppc_load (code, ppc_r11, inst->inst_offset);
3973 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3977 tailcall_struct_index = 0;
3978 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3979 ArgInfo *ainfo = cinfo->args + i;
3980 inst = cfg->args [pos];
3982 if (cfg->verbose_level > 2)
3983 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3984 if (inst->opcode == OP_REGVAR) {
3985 if (ainfo->regtype == RegTypeGeneral)
3986 ppc_mr (code, inst->dreg, ainfo->reg);
3987 else if (ainfo->regtype == RegTypeFP)
3988 ppc_fmr (code, inst->dreg, ainfo->reg);
3989 else if (ainfo->regtype == RegTypeBase) {
3990 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3991 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3993 g_assert_not_reached ();
3995 if (cfg->verbose_level > 2)
3996 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3998 /* the argument should be put on the stack: FIXME handle size != word */
3999 if (ainfo->regtype == RegTypeGeneral) {
4000 switch (ainfo->size) {
4002 if (ppc_is_imm16 (inst->inst_offset)) {
4003 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4005 ppc_load (code, ppc_r11, inst->inst_offset);
4006 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4010 if (ppc_is_imm16 (inst->inst_offset)) {
4011 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4013 ppc_load (code, ppc_r11, inst->inst_offset);
4014 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4018 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4019 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4020 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4022 ppc_load (code, ppc_r11, inst->inst_offset);
4023 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4024 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4025 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4029 if (ppc_is_imm16 (inst->inst_offset)) {
4030 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4032 ppc_load (code, ppc_r11, inst->inst_offset);
4033 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4037 } else if (ainfo->regtype == RegTypeBase) {
4038 /* load the previous stack pointer in r11 */
4039 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4040 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4041 switch (ainfo->size) {
4043 if (ppc_is_imm16 (inst->inst_offset)) {
4044 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4046 ppc_load (code, ppc_r11, inst->inst_offset);
4047 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4051 if (ppc_is_imm16 (inst->inst_offset)) {
4052 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4054 ppc_load (code, ppc_r11, inst->inst_offset);
4055 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4059 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4060 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4061 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4062 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4065 g_assert_not_reached ();
4069 if (ppc_is_imm16 (inst->inst_offset)) {
4070 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4072 ppc_load (code, ppc_r11, inst->inst_offset);
4073 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4077 } else if (ainfo->regtype == RegTypeFP) {
4078 g_assert (ppc_is_imm16 (inst->inst_offset));
4079 if (ainfo->size == 8)
4080 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4081 else if (ainfo->size == 4)
4082 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4084 g_assert_not_reached ();
4085 } else if (ainfo->regtype == RegTypeStructByVal) {
4086 int doffset = inst->inst_offset;
4090 g_assert (ppc_is_imm16 (inst->inst_offset));
4091 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4092 /* FIXME: what if there is no class? */
4093 if (mono_class_from_mono_type (inst->inst_vtype))
4094 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4095 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4097 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
4098 register. Should this case include linux/ppc?
4102 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4104 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4107 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4108 soffset += sizeof (gpointer);
4109 doffset += sizeof (gpointer);
4111 if (ainfo->vtsize) {
4112 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4113 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4114 if ((size & 3) != 0) {
4115 code = emit_memcpy (code, size - soffset,
4116 inst->inst_basereg, doffset,
4117 ppc_r11, ainfo->offset + soffset);
4119 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4120 inst->inst_basereg, doffset,
4121 ppc_r11, ainfo->offset + soffset);
4124 } else if (ainfo->regtype == RegTypeStructByAddr) {
4125 /* if it was originally a RegTypeBase */
4126 if (ainfo->offset) {
4127 /* load the previous stack pointer in r11 */
4128 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4129 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4131 ppc_mr (code, ppc_r11, ainfo->reg);
4134 if (cfg->tailcall_valuetype_addrs) {
4135 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4137 g_assert (ppc_is_imm16 (addr->inst_offset));
4138 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4140 tailcall_struct_index++;
4143 g_assert (ppc_is_imm16 (inst->inst_offset));
4144 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4145 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4147 g_assert_not_reached ();
4152 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4153 ppc_load (code, ppc_r3, cfg->domain);
4154 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4155 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4156 ppc_lis (code, ppc_r0, 0);
4157 ppc_ori (code, ppc_r0, ppc_r0, 0);
4158 ppc_mtlr (code, ppc_r0);
4165 if (method->save_lmf) {
4166 if (lmf_pthread_key != -1) {
4167 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4168 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4169 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4171 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4172 (gpointer)"mono_get_lmf_addr");
4173 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4174 ppc_lis (code, ppc_r0, 0);
4175 ppc_ori (code, ppc_r0, ppc_r0, 0);
4176 ppc_mtlr (code, ppc_r0);
4182 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4183 /* lmf_offset is the offset from the previous stack pointer,
4184 * alloc_size is the total stack space allocated, so the offset
4185 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4186 * The pointer to the struct is put in ppc_r11 (new_lmf).
4187 * The callee-saved registers are already in the MonoLMF structure
4189 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4190 /* ppc_r3 is the result from mono_get_lmf_addr () */
4191 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4192 /* new_lmf->previous_lmf = *lmf_addr */
4193 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4194 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4195 /* *(lmf_addr) = r11 */
4196 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4197 /* save method info */
4198 ppc_load (code, ppc_r0, method);
4199 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4200 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4201 /* save the current IP */
4202 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4203 ppc_load (code, ppc_r0, 0x01010101);
4204 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4208 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4210 cfg->code_len = code - cfg->native_code;
4211 g_assert (cfg->code_len < cfg->code_size);
4218 mono_arch_emit_epilog (MonoCompile *cfg)
4220 MonoJumpInfo *patch_info;
4221 MonoMethod *method = cfg->method;
4223 int max_epilog_size = 16 + 20*4;
4226 if (cfg->method->save_lmf)
4227 max_epilog_size += 128;
4229 if (mono_jit_trace_calls != NULL)
4230 max_epilog_size += 50;
4232 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4233 max_epilog_size += 50;
4235 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4236 cfg->code_size *= 2;
4237 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4238 mono_jit_stats.code_reallocs++;
4242 * Keep in sync with OP_JMP
4244 code = cfg->native_code + cfg->code_len;
4246 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4247 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4251 if (method->save_lmf) {
4253 pos += sizeof (MonoLMF);
4255 /* save the frame reg in r8 */
4256 ppc_mr (code, ppc_r8, cfg->frame_reg);
4257 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4258 /* r5 = previous_lmf */
4259 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4261 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4262 /* *(lmf_addr) = previous_lmf */
4263 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4264 /* FIXME: speedup: there is no actual need to restore the registers if
4265 * we didn't actually change them (idea from Zoltan).
4268 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4270 /*for (i = 14; i < 32; i++) {
4271 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4273 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4274 /* use the saved copy of the frame reg in r8 */
4275 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4276 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4277 ppc_mtlr (code, ppc_r0);
4279 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4281 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4282 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4283 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4285 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4286 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4288 ppc_mtlr (code, ppc_r0);
4290 if (ppc_is_imm16 (cfg->stack_usage)) {
4291 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4293 ppc_load (code, ppc_r11, cfg->stack_usage);
4294 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4297 /*for (i = 31; i >= 14; --i) {
4298 if (cfg->used_float_regs & (1 << i)) {
4299 pos += sizeof (double);
4300 ppc_lfd (code, i, -pos, ppc_sp);
4303 for (i = 31; i >= 13; --i) {
4304 if (cfg->used_int_regs & (1 << i)) {
4305 pos += sizeof (gulong);
4306 ppc_lwz (code, i, -pos, ppc_sp);
4312 cfg->code_len = code - cfg->native_code;
4314 g_assert (cfg->code_len < cfg->code_size);
4318 /* remove once throw_exception_by_name is eliminated */
4320 exception_id_by_name (const char *name)
4322 if (strcmp (name, "IndexOutOfRangeException") == 0)
4323 return MONO_EXC_INDEX_OUT_OF_RANGE;
4324 if (strcmp (name, "OverflowException") == 0)
4325 return MONO_EXC_OVERFLOW;
4326 if (strcmp (name, "ArithmeticException") == 0)
4327 return MONO_EXC_ARITHMETIC;
4328 if (strcmp (name, "DivideByZeroException") == 0)
4329 return MONO_EXC_DIVIDE_BY_ZERO;
4330 if (strcmp (name, "InvalidCastException") == 0)
4331 return MONO_EXC_INVALID_CAST;
4332 if (strcmp (name, "NullReferenceException") == 0)
4333 return MONO_EXC_NULL_REF;
4334 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4335 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4336 g_error ("Unknown intrinsic exception %s\n", name);
4341 mono_arch_emit_exceptions (MonoCompile *cfg)
4343 MonoJumpInfo *patch_info;
4346 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4347 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4348 int max_epilog_size = 50;
4350 /* count the number of exception infos */
4353 * make sure we have enough space for exceptions
4354 * 24 is the simulated call to throw_exception_by_name
4356 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4357 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4358 i = exception_id_by_name (patch_info->data.target);
4359 if (!exc_throw_found [i]) {
4360 max_epilog_size += 24;
4361 exc_throw_found [i] = TRUE;
4363 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4364 max_epilog_size += 12;
4365 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4366 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4367 i = exception_id_by_name (ovfj->data.exception);
4368 if (!exc_throw_found [i]) {
4369 max_epilog_size += 24;
4370 exc_throw_found [i] = TRUE;
4372 max_epilog_size += 8;
4376 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4377 cfg->code_size *= 2;
4378 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4379 mono_jit_stats.code_reallocs++;
4382 code = cfg->native_code + cfg->code_len;
4384 /* add code to raise exceptions */
4385 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4386 switch (patch_info->type) {
4387 case MONO_PATCH_INFO_BB_OVF: {
4388 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4389 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4390 /* patch the initial jump */
4391 ppc_patch (ip, code);
4392 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4394 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4395 /* jump back to the true target */
4397 ip = ovfj->data.bb->native_offset + cfg->native_code;
4398 ppc_patch (code - 4, ip);
4401 case MONO_PATCH_INFO_EXC_OVF: {
4402 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4403 MonoJumpInfo *newji;
4404 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4405 unsigned char *bcl = code;
4406 /* patch the initial jump: we arrived here with a call */
4407 ppc_patch (ip, code);
4408 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4410 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4411 /* patch the conditional jump to the right handler */
4412 /* make it processed next */
4413 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4414 newji->type = MONO_PATCH_INFO_EXC;
4415 newji->ip.i = bcl - cfg->native_code;
4416 newji->data.target = ovfj->data.exception;
4417 newji->next = patch_info->next;
4418 patch_info->next = newji;
4421 case MONO_PATCH_INFO_EXC: {
4422 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4423 i = exception_id_by_name (patch_info->data.target);
4424 if (exc_throw_pos [i]) {
4425 ppc_patch (ip, exc_throw_pos [i]);
4426 patch_info->type = MONO_PATCH_INFO_NONE;
4429 exc_throw_pos [i] = code;
4431 ppc_patch (ip, code);
4432 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4433 ppc_load (code, ppc_r3, patch_info->data.target);
4434 /* we got here from a conditional call, so the calling ip is set in lr already */
4435 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4436 patch_info->data.name = "mono_arch_throw_exception_by_name";
4437 patch_info->ip.i = code - cfg->native_code;
4438 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4439 ppc_lis (code, ppc_r0, 0);
4440 ppc_ori (code, ppc_r0, ppc_r0, 0);
4441 ppc_mtctr (code, ppc_r0);
4442 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4454 cfg->code_len = code - cfg->native_code;
4456 g_assert (cfg->code_len < cfg->code_size);
4461 try_offset_access (void *value, guint32 idx)
4463 register void* me __asm__ ("r2");
4464 void ***p = (void***)((char*)me + 284);
4465 int idx1 = idx / 32;
4466 int idx2 = idx % 32;
4469 if (value != p[idx1][idx2])
4475 setup_tls_access (void)
4478 guint32 *ins, *code;
4479 guint32 cmplwi_1023, li_0x48, blr_ins;
4480 if (tls_mode == TLS_MODE_FAILED)
4483 if (g_getenv ("MONO_NO_TLS")) {
4484 tls_mode = TLS_MODE_FAILED;
4488 if (tls_mode == TLS_MODE_DETECT) {
4489 ins = (guint32*)pthread_getspecific;
4490 /* uncond branch to the real method */
4491 if ((*ins >> 26) == 18) {
4493 val = (*ins & ~3) << 6;
4497 ins = (guint32*)val;
4499 ins = (guint32*) ((char*)ins + val);
4502 code = &cmplwi_1023;
4503 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4505 ppc_li (code, ppc_r4, 0x48);
4508 if (*ins == cmplwi_1023) {
4509 int found_lwz_284 = 0;
4510 for (ptk = 0; ptk < 20; ++ptk) {
4512 if (!*ins || *ins == blr_ins)
4514 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4519 if (!found_lwz_284) {
4520 tls_mode = TLS_MODE_FAILED;
4523 tls_mode = TLS_MODE_LTHREADS;
4524 } else if (*ins == li_0x48) {
4526 /* uncond branch to the real method */
4527 if ((*ins >> 26) == 18) {
4529 val = (*ins & ~3) << 6;
4533 ins = (guint32*)val;
4535 ins = (guint32*) ((char*)ins + val);
4537 code = (guint32*)&val;
4538 ppc_li (code, ppc_r0, 0x7FF2);
4539 if (ins [1] == val) {
4540 /* Darwin on G4, implement */
4541 tls_mode = TLS_MODE_FAILED;
4544 code = (guint32*)&val;
4545 ppc_mfspr (code, ppc_r3, 104);
4546 if (ins [1] != val) {
4547 tls_mode = TLS_MODE_FAILED;
4550 tls_mode = TLS_MODE_DARWIN_G5;
4553 tls_mode = TLS_MODE_FAILED;
4557 tls_mode = TLS_MODE_FAILED;
4561 if (monodomain_key == -1) {
4562 ptk = mono_domain_get_tls_key ();
4564 ptk = mono_pthread_key_for_tls (ptk);
4566 monodomain_key = ptk;
4570 if (lmf_pthread_key == -1) {
4571 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4573 /*g_print ("MonoLMF at: %d\n", ptk);*/
4574 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4575 init_tls_failed = 1;
4578 lmf_pthread_key = ptk;
4581 if (monothread_key == -1) {
4582 ptk = mono_thread_get_tls_key ();
4584 ptk = mono_pthread_key_for_tls (ptk);
4586 monothread_key = ptk;
4587 /*g_print ("thread inited: %d\n", ptk);*/
4590 /*g_print ("thread not inited yet %d\n", ptk);*/
4596 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4598 setup_tls_access ();
4602 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4607 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4609 int this_dreg = ppc_r3;
4614 /* add the this argument */
4615 if (this_reg != -1) {
4617 MONO_INST_NEW (cfg, this, OP_MOVE);
4618 this->type = this_type;
4619 this->sreg1 = this_reg;
4620 this->dreg = mono_regstate_next_int (cfg->rs);
4621 mono_bblock_add_inst (cfg->cbb, this);
4622 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4627 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4628 vtarg->type = STACK_MP;
4629 vtarg->sreg1 = vt_reg;
4630 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4631 mono_bblock_add_inst (cfg->cbb, vtarg);
4632 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4636 #ifdef MONO_ARCH_HAVE_IMT
4640 #define JUMP_IMM_SIZE 12
4641 #define ENABLE_WRONG_METHOD_CHECK 0
4644 * LOCKING: called with the domain lock held
4647 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4651 guint8 *code, *start;
4653 for (i = 0; i < count; ++i) {
4654 MonoIMTCheckItem *item = imt_entries [i];
4655 if (item->is_equals) {
4656 if (item->check_target_idx) {
4657 if (!item->compare_done)
4658 item->chunk_size += CMP_SIZE;
4659 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4661 item->chunk_size += JUMP_IMM_SIZE;
4662 #if ENABLE_WRONG_METHOD_CHECK
4663 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4667 item->chunk_size += CMP_SIZE + BR_SIZE;
4668 imt_entries [item->check_target_idx]->compare_done = TRUE;
4670 size += item->chunk_size;
4672 /* the initial load of the vtable address */
4674 code = mono_code_manager_reserve (domain->code_mp, size);
4676 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4677 for (i = 0; i < count; ++i) {
4678 MonoIMTCheckItem *item = imt_entries [i];
4679 item->code_target = code;
4680 if (item->is_equals) {
4681 if (item->check_target_idx) {
4682 if (!item->compare_done) {
4683 ppc_load (code, ppc_r0, (guint32)item->method);
4684 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4686 item->jmp_code = code;
4687 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4688 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4689 ppc_mtctr (code, ppc_r0);
4690 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4692 /* enable the commented code to assert on wrong method */
4693 #if ENABLE_WRONG_METHOD_CHECK
4694 ppc_load (code, ppc_r0, (guint32)item->method);
4695 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4696 item->jmp_code = code;
4697 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4699 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4700 ppc_mtctr (code, ppc_r0);
4701 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4702 #if ENABLE_WRONG_METHOD_CHECK
4703 ppc_patch (item->jmp_code, code);
4705 item->jmp_code = NULL;
4709 ppc_load (code, ppc_r0, (guint32)item->method);
4710 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4711 item->jmp_code = code;
4712 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4715 /* patch the branches to get to the target items */
4716 for (i = 0; i < count; ++i) {
4717 MonoIMTCheckItem *item = imt_entries [i];
4718 if (item->jmp_code) {
4719 if (item->check_target_idx) {
4720 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4725 mono_stats.imt_thunks_size += code - start;
4726 g_assert (code - start <= size);
4727 mono_arch_flush_icache (start, size);
4732 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4734 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4738 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4740 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4745 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4747 MonoInst *ins = NULL;
4749 /*if (cmethod->klass == mono_defaults.math_class) {
4750 if (strcmp (cmethod->name, "Sqrt") == 0) {
4751 MONO_INST_NEW (cfg, ins, OP_SQRT);
4752 ins->inst_i0 = args [0];
4759 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4766 mono_arch_print_tree (MonoInst *tree, int arity)
4771 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4775 setup_tls_access ();
4776 if (monodomain_key == -1)
4779 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4780 ins->inst_offset = monodomain_key;
4785 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4789 setup_tls_access ();
4790 if (monothread_key == -1)
4793 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4794 ins->inst_offset = monothread_key;
4799 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4801 /* FIXME: implement */
4802 g_assert_not_reached ();