2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 #include <sys/sysctl.h>
26 alloc_ireg (MonoCompile *cfg)
28 return cfg->next_vreg ++;
32 alloc_lreg (MonoCompile *cfg)
34 #if SIZEOF_VOID_P == 8
35 return cfg->next_vreg ++;
37 /* Use a pair of consecutive vregs */
38 guint32 res = cfg->next_vreg;
47 alloc_freg (MonoCompile *cfg)
49 #ifdef MONO_ARCH_SOFT_FLOAT
50 /* Allocate an lvreg so float ops can be decomposed into long ops */
51 return alloc_lreg (cfg);
53 /* Allocate these from the same pool as the int regs */
54 return cfg->next_vreg ++;
59 alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
66 return alloc_ireg (cfg);
68 return alloc_freg (cfg);
70 return alloc_lreg (cfg);
72 return alloc_ireg (cfg);
74 g_assert_not_reached ();
78 #ifdef MONO_ARCH_SOFT_FLOAT
79 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
81 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
84 #define NEW_VARLOADA(cfg,dest,var,vartype) do { \
85 MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
86 (dest)->inst_p0 = (var); \
87 (var)->flags |= MONO_INST_INDIRECT; \
88 (dest)->type = STACK_MP; \
89 (dest)->klass = (var)->klass; \
90 (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
91 if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
94 #define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
96 #define FORCE_INDIR_CALL 1
107 /* This mutex protects architecture specific caches */
108 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
109 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
110 static CRITICAL_SECTION mini_arch_mutex;
112 int mono_exc_esp_offset = 0;
113 static int tls_mode = TLS_MODE_DETECT;
114 static int lmf_pthread_key = -1;
115 static int monothread_key = -1;
116 static int monodomain_key = -1;
119 offsets_from_pthread_key (guint32 key, int *offset2)
123 *offset2 = idx2 * sizeof (gpointer);
124 return 284 + idx1 * sizeof (gpointer);
127 #define emit_linuxthreads_tls(code,dreg,key) do {\
129 off1 = offsets_from_pthread_key ((key), &off2); \
130 ppc_lwz ((code), (dreg), off1, ppc_r2); \
131 ppc_lwz ((code), (dreg), off2, (dreg)); \
134 #define emit_darwing5_tls(code,dreg,key) do {\
135 int off1 = 0x48 + key * sizeof (gpointer); \
136 ppc_mfspr ((code), (dreg), 104); \
137 ppc_lwz ((code), (dreg), off1, (dreg)); \
140 /* FIXME: ensure the sc call preserves all but r3 */
141 #define emit_darwing4_tls(code,dreg,key) do {\
142 int off1 = 0x48 + key * sizeof (gpointer); \
143 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
144 ppc_li ((code), ppc_r0, 0x7FF2); \
146 ppc_lwz ((code), (dreg), off1, ppc_r3); \
147 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
150 #define emit_tls_access(code,dreg,key) do { \
151 switch (tls_mode) { \
152 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
153 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
154 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
155 default: g_assert_not_reached (); \
160 mono_arch_regname (int reg) {
161 static const char rnames[][4] = {
162 "r0", "sp", "r2", "r3", "r4",
163 "r5", "r6", "r7", "r8", "r9",
164 "r10", "r11", "r12", "r13", "r14",
165 "r15", "r16", "r17", "r18", "r19",
166 "r20", "r21", "r22", "r23", "r24",
167 "r25", "r26", "r27", "r28", "r29",
170 if (reg >= 0 && reg < 32)
176 mono_arch_fregname (int reg) {
177 static const char rnames[][4] = {
178 "f0", "f1", "f2", "f3", "f4",
179 "f5", "f6", "f7", "f8", "f9",
180 "f10", "f11", "f12", "f13", "f14",
181 "f15", "f16", "f17", "f18", "f19",
182 "f20", "f21", "f22", "f23", "f24",
183 "f25", "f26", "f27", "f28", "f29",
186 if (reg >= 0 && reg < 32)
191 /* this function overwrites r0, r11, r12 */
193 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
195 /* unrolled, use the counter in big */
196 if (size > sizeof (gpointer) * 5) {
197 int shifted = size >> 2;
198 guint8 *copy_loop_start, *copy_loop_jump;
200 ppc_load (code, ppc_r0, shifted);
201 ppc_mtctr (code, ppc_r0);
202 g_assert (sreg == ppc_r11);
203 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
204 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
205 copy_loop_start = code;
206 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
207 ppc_stwu (code, ppc_r0, 4, ppc_r12);
208 copy_loop_jump = code;
209 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
210 ppc_patch (copy_loop_jump, copy_loop_start);
212 doffset = soffset = 0;
216 ppc_lwz (code, ppc_r0, soffset, sreg);
217 ppc_stw (code, ppc_r0, doffset, dreg);
223 ppc_lhz (code, ppc_r0, soffset, sreg);
224 ppc_sth (code, ppc_r0, doffset, dreg);
230 ppc_lbz (code, ppc_r0, soffset, sreg);
231 ppc_stb (code, ppc_r0, doffset, dreg);
240 * mono_arch_get_argument_info:
241 * @csig: a method signature
242 * @param_count: the number of parameters to consider
243 * @arg_info: an array to store the result infos
245 * Gathers information on parameters such as size, alignment and
246 * padding. arg_info should be large enought to hold param_count + 1 entries.
248 * Returns the size of the activation frame.
251 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
253 int k, frame_size = 0;
254 int size, align, pad;
257 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
258 frame_size += sizeof (gpointer);
262 arg_info [0].offset = offset;
265 frame_size += sizeof (gpointer);
269 arg_info [0].size = frame_size;
271 for (k = 0; k < param_count; k++) {
274 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
276 size = mini_type_stack_size (NULL, csig->params [k], &align);
278 /* ignore alignment for now */
281 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
282 arg_info [k].pad = pad;
284 arg_info [k + 1].pad = 0;
285 arg_info [k + 1].size = size;
287 arg_info [k + 1].offset = offset;
291 align = MONO_ARCH_FRAME_ALIGNMENT;
292 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
293 arg_info [k].pad = pad;
299 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
303 guint32* code = (guint32*)code_ptr;
307 /* This is the 'blrl' instruction */
310 /* Sanity check: instruction must be 'blrl' */
311 if (*code != 0x4e800021)
314 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
315 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
319 /* OK, we're now at the 'blrl' instruction. Now walk backwards
320 till we get to a 'mtlr rA' */
322 if((*code & 0x7c0803a6) == 0x7c0803a6) {
324 /* Here we are: we reached the 'mtlr rA'.
325 Extract the register from the instruction */
326 reg = (*code & 0x03e00000) >> 21;
328 /* ok, this is a lwz reg, offset (vtreg)
329 * it is emitted with:
330 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
332 soff = (*code & 0xffff);
334 reg = (*code >> 16) & 0x1f;
335 g_assert (reg != ppc_r1);
336 /*g_print ("patching reg is %d\n", reg);*/
338 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
339 /* saved in the MonoLMF structure */
340 o = (gpointer)lmf->iregs [reg - 13];
347 *displacement = offset;
352 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
356 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
359 return (gpointer*)((char*)vt + displacement);
362 #define MAX_ARCH_DELEGATE_PARAMS 7
365 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
367 guint8 *code, *start;
369 /* FIXME: Support more cases */
370 if (MONO_TYPE_ISSTRUCT (sig->ret))
374 static guint8* cached = NULL;
375 mono_mini_arch_lock ();
377 mono_mini_arch_unlock ();
381 start = code = mono_global_codeman_reserve (16);
383 /* Replace the this argument with the target */
384 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
385 ppc_mtctr (code, ppc_r0);
386 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
387 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
389 g_assert ((code - start) <= 16);
391 mono_arch_flush_icache (start, 16);
393 mono_mini_arch_unlock ();
396 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
399 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
401 for (i = 0; i < sig->param_count; ++i)
402 if (!mono_is_regsize_var (sig->params [i]))
405 mono_mini_arch_lock ();
406 code = cache [sig->param_count];
408 mono_mini_arch_unlock ();
412 size = 12 + sig->param_count * 4;
413 start = code = mono_global_codeman_reserve (size);
415 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 ppc_mtctr (code, ppc_r0);
417 /* slide down the arguments */
418 for (i = 0; i < sig->param_count; ++i) {
419 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
421 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
423 g_assert ((code - start) <= size);
425 mono_arch_flush_icache (start, size);
426 cache [sig->param_count] = start;
427 mono_mini_arch_unlock ();
434 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
436 /* FIXME: handle returning a struct */
437 if (MONO_TYPE_ISSTRUCT (sig->ret))
438 return (gpointer)regs [ppc_r4];
439 return (gpointer)regs [ppc_r3];
443 * Initialize the cpu to execute managed code.
446 mono_arch_cpu_init (void)
451 * Initialize architecture specific code.
454 mono_arch_init (void)
456 InitializeCriticalSection (&mini_arch_mutex);
460 * Cleanup architecture specific code.
463 mono_arch_cleanup (void)
465 DeleteCriticalSection (&mini_arch_mutex);
469 * This function returns the optimizations supported on this cpu.
472 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
476 /* no ppc-specific optimizations yet */
482 is_regsize_var (MonoType *t) {
485 t = mini_type_get_underlying_type (NULL, t);
492 case MONO_TYPE_FNPTR:
494 case MONO_TYPE_OBJECT:
495 case MONO_TYPE_STRING:
496 case MONO_TYPE_CLASS:
497 case MONO_TYPE_SZARRAY:
498 case MONO_TYPE_ARRAY:
500 case MONO_TYPE_GENERICINST:
501 if (!mono_type_generic_inst_is_valuetype (t))
504 case MONO_TYPE_VALUETYPE:
511 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
516 for (i = 0; i < cfg->num_varinfo; i++) {
517 MonoInst *ins = cfg->varinfo [i];
518 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
521 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
524 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
527 /* we can only allocate 32 bit values */
528 if (is_regsize_var (ins->inst_vtype)) {
529 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
530 g_assert (i == vmv->idx);
531 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
539 mono_arch_get_global_int_regs (MonoCompile *cfg)
543 if (cfg->frame_reg != ppc_sp)
545 /* ppc_r13 is used by the system on PPC EABI */
546 for (i = 14; i < top; ++i)
547 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
553 * mono_arch_regalloc_cost:
555 * Return the cost, in number of memory references, of the action of
556 * allocating the variable VMV into a register during global register
560 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
572 mono_arch_flush_icache (guint8 *code, gint size)
574 guint8 *p, *endp, *start;
575 static int cachelinesize = 0;
576 static int cachelineinc = 16;
578 if (!cachelinesize) {
583 mib [1] = HW_CACHELINE;
584 len = sizeof (cachelinesize);
585 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
589 cachelineinc = cachelinesize;
590 /*g_print ("setting cl size to %d\n", cachelinesize);*/
592 #elif defined(__linux__)
593 /* sadly this will work only with 2.6 kernels... */
594 FILE* f = fopen ("/proc/self/auxv", "rb");
597 while (fread (&vec, sizeof (vec), 1, f) == 1) {
598 if (vec.type == 19) {
599 cachelinesize = vec.value;
608 #warning Need a way to get cache line size
614 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
615 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
617 for (p = start; p < endp; p += cachelineinc) {
618 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
621 for (p = start; p < endp; p += cachelineinc) {
622 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
627 for (p = start; p < endp; p += cachelineinc) {
628 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
635 mono_arch_flush_register_windows (void)
640 #define ALWAYS_ON_STACK(s) s
641 #define FP_ALSO_IN_REG(s) s
643 #define ALWAYS_ON_STACK(s)
644 #define FP_ALSO_IN_REG(s)
645 #define ALIGN_DOUBLES
658 guint32 vtsize; /* in param area */
660 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
661 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
676 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
679 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
680 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
681 ainfo->reg = ppc_sp; /* in the caller */
682 ainfo->regtype = RegTypeBase;
685 ALWAYS_ON_STACK (*stack_size += 4);
689 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
691 //*stack_size += (*stack_size % 8);
693 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
694 ainfo->reg = ppc_sp; /* in the caller */
695 ainfo->regtype = RegTypeBase;
702 ALWAYS_ON_STACK (*stack_size += 8);
712 has_only_a_r48_field (MonoClass *klass)
716 gboolean have_field = FALSE;
718 while ((f = mono_class_get_fields (klass, &iter))) {
719 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
722 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
733 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
736 int n = sig->hasthis + sig->param_count;
738 guint32 stack_size = 0;
739 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
741 fr = PPC_FIRST_FPARG_REG;
742 gr = PPC_FIRST_ARG_REG;
744 /* FIXME: handle returning a struct */
745 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
746 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
747 cinfo->struct_ret = PPC_FIRST_ARG_REG;
752 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
755 DEBUG(printf("params: %d\n", sig->param_count));
756 for (i = 0; i < sig->param_count; ++i) {
757 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
758 /* Prevent implicit arguments and sig_cookie from
759 being passed in registers */
760 gr = PPC_LAST_ARG_REG + 1;
761 /* FIXME: don't we have to set fr, too? */
762 /* Emit the signature cookie just before the implicit arguments */
763 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
765 DEBUG(printf("param %d: ", i));
766 if (sig->params [i]->byref) {
767 DEBUG(printf("byref\n"));
768 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
772 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
773 switch (simpletype) {
774 case MONO_TYPE_BOOLEAN:
777 cinfo->args [n].size = 1;
778 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
784 cinfo->args [n].size = 2;
785 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
790 cinfo->args [n].size = 4;
791 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
797 case MONO_TYPE_FNPTR:
798 case MONO_TYPE_CLASS:
799 case MONO_TYPE_OBJECT:
800 case MONO_TYPE_STRING:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_ARRAY:
803 cinfo->args [n].size = sizeof (gpointer);
804 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
807 case MONO_TYPE_GENERICINST:
808 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
809 cinfo->args [n].size = sizeof (gpointer);
810 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
815 case MONO_TYPE_VALUETYPE: {
818 klass = mono_class_from_mono_type (sig->params [i]);
820 size = mono_class_native_size (klass, NULL);
822 size = mono_class_value_size (klass, NULL);
824 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
825 cinfo->args [n].size = size;
827 /* It was 7, now it is 8 in LinuxPPC */
828 if (fr <= PPC_LAST_FPARG_REG) {
829 cinfo->args [n].regtype = RegTypeFP;
830 cinfo->args [n].reg = fr;
832 FP_ALSO_IN_REG (gr ++);
834 FP_ALSO_IN_REG (gr ++);
835 ALWAYS_ON_STACK (stack_size += size);
837 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
838 cinfo->args [n].regtype = RegTypeBase;
839 cinfo->args [n].reg = ppc_sp; /* in the caller*/
846 DEBUG(printf ("load %d bytes struct\n",
847 mono_class_native_size (sig->params [i]->data.klass, NULL)));
848 #if PPC_PASS_STRUCTS_BY_VALUE
850 int align_size = size;
852 int rest = PPC_LAST_ARG_REG - gr + 1;
854 align_size += (sizeof (gpointer) - 1);
855 align_size &= ~(sizeof (gpointer) - 1);
856 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
857 n_in_regs = rest >= nwords? nwords: rest;
858 cinfo->args [n].regtype = RegTypeStructByVal;
859 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
860 cinfo->args [n].size = 0;
861 cinfo->args [n].vtsize = nwords;
863 cinfo->args [n].size = n_in_regs;
864 cinfo->args [n].vtsize = nwords - n_in_regs;
865 cinfo->args [n].reg = gr;
868 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
869 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
870 stack_size += nwords * sizeof (gpointer);
873 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
874 cinfo->args [n].regtype = RegTypeStructByAddr;
875 cinfo->args [n].vtsize = size;
880 case MONO_TYPE_TYPEDBYREF: {
881 int size = sizeof (MonoTypedRef);
882 /* keep in sync or merge with the valuetype case */
883 #if PPC_PASS_STRUCTS_BY_VALUE
885 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
886 cinfo->args [n].regtype = RegTypeStructByVal;
887 if (gr <= PPC_LAST_ARG_REG) {
888 int rest = PPC_LAST_ARG_REG - gr + 1;
889 int n_in_regs = rest >= nwords? nwords: rest;
890 cinfo->args [n].size = n_in_regs;
891 cinfo->args [n].vtsize = nwords - n_in_regs;
892 cinfo->args [n].reg = gr;
895 cinfo->args [n].size = 0;
896 cinfo->args [n].vtsize = nwords;
898 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
899 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
900 stack_size += nwords * sizeof (gpointer);
903 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
904 cinfo->args [n].regtype = RegTypeStructByAddr;
905 cinfo->args [n].vtsize = size;
912 cinfo->args [n].size = 8;
913 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
917 cinfo->args [n].size = 4;
919 /* It was 7, now it is 8 in LinuxPPC */
920 if (fr <= PPC_LAST_FPARG_REG) {
921 cinfo->args [n].regtype = RegTypeFP;
922 cinfo->args [n].reg = fr;
924 FP_ALSO_IN_REG (gr ++);
925 ALWAYS_ON_STACK (stack_size += 4);
927 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
928 cinfo->args [n].regtype = RegTypeBase;
929 cinfo->args [n].reg = ppc_sp; /* in the caller*/
935 cinfo->args [n].size = 8;
936 /* It was 7, now it is 8 in LinuxPPC */
937 if (fr <= PPC_LAST_FPARG_REG) {
938 cinfo->args [n].regtype = RegTypeFP;
939 cinfo->args [n].reg = fr;
941 FP_ALSO_IN_REG (gr += 2);
942 ALWAYS_ON_STACK (stack_size += 8);
944 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
945 cinfo->args [n].regtype = RegTypeBase;
946 cinfo->args [n].reg = ppc_sp; /* in the caller*/
952 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
956 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
957 /* Prevent implicit arguments and sig_cookie from
958 being passed in registers */
959 gr = PPC_LAST_ARG_REG + 1;
960 /* Emit the signature cookie just before the implicit arguments */
961 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
965 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
966 switch (simpletype) {
967 case MONO_TYPE_BOOLEAN:
978 case MONO_TYPE_FNPTR:
979 case MONO_TYPE_CLASS:
980 case MONO_TYPE_OBJECT:
981 case MONO_TYPE_SZARRAY:
982 case MONO_TYPE_ARRAY:
983 case MONO_TYPE_STRING:
984 cinfo->ret.reg = ppc_r3;
988 cinfo->ret.reg = ppc_r3;
992 cinfo->ret.reg = ppc_f1;
993 cinfo->ret.regtype = RegTypeFP;
995 case MONO_TYPE_GENERICINST:
996 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
997 cinfo->ret.reg = ppc_r3;
1001 case MONO_TYPE_VALUETYPE:
1003 case MONO_TYPE_TYPEDBYREF:
1004 case MONO_TYPE_VOID:
1007 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1011 /* align stack size to 16 */
1012 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1013 stack_size = (stack_size + 15) & ~15;
1015 cinfo->stack_usage = stack_size;
1020 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1022 #if !PPC_PASS_STRUCTS_BY_VALUE
1023 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1024 int num_structs = 0;
1027 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1030 for (i = 0; i < sig->param_count; ++i) {
1031 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1032 if (type->type == MONO_TYPE_VALUETYPE)
1037 cfg->tailcall_valuetype_addrs =
1038 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1039 for (i = 0; i < num_structs; ++i) {
1040 cfg->tailcall_valuetype_addrs [i] =
1041 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1042 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1049 * Set var information according to the calling convention. ppc version.
1050 * The locals var stuff should most likely be split in another method.
1053 mono_arch_allocate_vars (MonoCompile *m)
1055 MonoMethodSignature *sig;
1056 MonoMethodHeader *header;
1058 int i, offset, size, align, curinst;
1059 int frame_reg = ppc_sp;
1061 guint32 locals_stack_size, locals_stack_align;
1063 allocate_tailcall_valuetype_addrs (m);
1065 m->flags |= MONO_CFG_HAS_SPILLUP;
1067 /* allow room for the vararg method args: void* and long/double */
1068 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1069 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1070 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1071 * call convs needs to be handled this way.
1073 if (m->flags & MONO_CFG_HAS_VARARGS)
1074 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1075 /* gtk-sharp and other broken code will dllimport vararg functions even with
1076 * non-varargs signatures. Since there is little hope people will get this right
1077 * we assume they won't.
1079 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1080 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1082 header = mono_method_get_header (m->method);
1085 * We use the frame register also for any method that has
1086 * exception clauses. This way, when the handlers are called,
1087 * the code will reference local variables using the frame reg instead of
1088 * the stack pointer: if we had to restore the stack pointer, we'd
1089 * corrupt the method frames that are already on the stack (since
1090 * filters get called before stack unwinding happens) when the filter
1091 * code would call any method (this also applies to finally etc.).
1093 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1094 frame_reg = ppc_r31;
1095 m->frame_reg = frame_reg;
1096 if (frame_reg != ppc_sp) {
1097 m->used_int_regs |= 1 << frame_reg;
1100 sig = mono_method_signature (m->method);
1104 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1105 m->ret->opcode = OP_REGVAR;
1106 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1108 /* FIXME: handle long values? */
1109 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1110 case MONO_TYPE_VOID:
1114 m->ret->opcode = OP_REGVAR;
1115 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1118 m->ret->opcode = OP_REGVAR;
1119 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1123 /* local vars are at a positive offset from the stack pointer */
1125 * also note that if the function uses alloca, we use ppc_r31
1126 * to point at the local variables.
1128 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1129 /* align the offset to 16 bytes: not sure this is needed here */
1131 //offset &= ~(16 - 1);
1133 /* add parameter area size for called functions */
1134 offset += m->param_area;
1136 offset &= ~(16 - 1);
1138 /* allow room to save the return value */
1139 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1142 /* the MonoLMF structure is stored just below the stack pointer */
1145 /* this stuff should not be needed on ppc and the new jit,
1146 * because a call on ppc to the handlers doesn't change the
1147 * stack pointer and the jist doesn't manipulate the stack pointer
1148 * for operations involving valuetypes.
1150 /* reserve space to store the esp */
1151 offset += sizeof (gpointer);
1153 /* this is a global constant */
1154 mono_exc_esp_offset = offset;
1156 if (sig->call_convention == MONO_CALL_VARARG) {
1157 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1160 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1161 offset += sizeof(gpointer) - 1;
1162 offset &= ~(sizeof(gpointer) - 1);
1165 m->vret_addr->opcode = OP_REGOFFSET;
1166 m->vret_addr->inst_basereg = frame_reg;
1167 m->vret_addr->inst_offset = offset;
1169 if (G_UNLIKELY (m->verbose_level > 1)) {
1170 printf ("vret_addr =");
1171 mono_print_ins (m->vret_addr);
1175 inst->inst_offset = offset;
1176 inst->opcode = OP_REGOFFSET;
1177 inst->inst_basereg = frame_reg;
1180 offset += sizeof(gpointer);
1181 if (sig->call_convention == MONO_CALL_VARARG)
1182 m->sig_cookie += sizeof (gpointer);
1185 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1186 if (locals_stack_align) {
1187 offset += (locals_stack_align - 1);
1188 offset &= ~(locals_stack_align - 1);
1190 for (i = m->locals_start; i < m->num_varinfo; i++) {
1191 if (offsets [i] != -1) {
1192 MonoInst *inst = m->varinfo [i];
1193 inst->opcode = OP_REGOFFSET;
1194 inst->inst_basereg = frame_reg;
1195 inst->inst_offset = offset + offsets [i];
1197 g_print ("allocating local %d (%s) to %d\n",
1198 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1202 offset += locals_stack_size;
1206 inst = m->args [curinst];
1207 if (inst->opcode != OP_REGVAR) {
1208 inst->opcode = OP_REGOFFSET;
1209 inst->inst_basereg = frame_reg;
1210 offset += sizeof (gpointer) - 1;
1211 offset &= ~(sizeof (gpointer) - 1);
1212 inst->inst_offset = offset;
1213 offset += sizeof (gpointer);
1214 if (sig->call_convention == MONO_CALL_VARARG)
1215 m->sig_cookie += sizeof (gpointer);
1220 for (i = 0; i < sig->param_count; ++i) {
1221 inst = m->args [curinst];
1222 if (inst->opcode != OP_REGVAR) {
1223 inst->opcode = OP_REGOFFSET;
1224 inst->inst_basereg = frame_reg;
1226 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1227 inst->backend.is_pinvoke = 1;
1229 size = mono_type_size (sig->params [i], &align);
1231 offset += align - 1;
1232 offset &= ~(align - 1);
1233 inst->inst_offset = offset;
1235 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1236 m->sig_cookie += size;
1241 /* align the offset to 16 bytes */
1243 offset &= ~(16 - 1);
1246 m->stack_offset = offset;
1248 if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1249 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1251 m->sig_cookie = cinfo->sig_cookie.offset;
1258 mono_arch_create_vars (MonoCompile *cfg)
1260 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1262 if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1263 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1267 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1268 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1272 * take the arguments and generate the arch-specific
1273 * instructions to properly call the function in call.
1274 * This includes pushing, moving arguments to the right register
1276 * Issue: who does the spilling if needed, and when?
1279 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1281 MonoMethodSignature *sig;
1286 sig = call->signature;
1287 n = sig->param_count + sig->hasthis;
1289 cinfo = calculate_sizes (sig, sig->pinvoke);
1290 if (cinfo->struct_ret)
1291 call->used_iregs |= 1 << cinfo->struct_ret;
1293 for (i = 0; i < n; ++i) {
1294 ainfo = cinfo->args + i;
1295 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1297 cfg->disable_aot = TRUE;
1299 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1300 sig_arg->inst_p0 = call->signature;
1302 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1303 arg->inst_imm = cinfo->sig_cookie.offset;
1304 arg->inst_left = sig_arg;
1305 arg->inst_call = call;
1306 /* prepend, so they get reversed */
1307 arg->next = call->out_args;
1308 call->out_args = arg;
1310 if (is_virtual && i == 0) {
1311 /* the argument will be attached to the call instrucion */
1312 in = call->args [i];
1313 call->used_iregs |= 1 << ainfo->reg;
1315 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1316 in = call->args [i];
1317 arg->cil_code = in->cil_code;
1318 arg->inst_left = in;
1319 arg->inst_call = call;
1320 arg->type = in->type;
1321 /* prepend, so they get reversed */
1322 arg->next = call->out_args;
1323 call->out_args = arg;
1324 if (ainfo->regtype == RegTypeGeneral) {
1325 arg->backend.reg3 = ainfo->reg;
1326 call->used_iregs |= 1 << ainfo->reg;
1327 if (arg->type == STACK_I8)
1328 call->used_iregs |= 1 << (ainfo->reg + 1);
1329 } else if (ainfo->regtype == RegTypeStructByAddr) {
1330 if (ainfo->offset) {
1331 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1332 arg->opcode = OP_OUTARG_MEMBASE;
1333 ai->reg = ainfo->reg;
1334 ai->size = sizeof (gpointer);
1335 ai->offset = ainfo->offset;
1336 arg->backend.data = ai;
1338 arg->backend.reg3 = ainfo->reg;
1339 call->used_iregs |= 1 << ainfo->reg;
1341 } else if (ainfo->regtype == RegTypeStructByVal) {
1343 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1344 /* mark the used regs */
1345 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1346 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1348 arg->opcode = OP_OUTARG_VT;
1349 ai->reg = ainfo->reg;
1350 ai->size = ainfo->size;
1351 ai->vtsize = ainfo->vtsize;
1352 ai->offset = ainfo->offset;
1353 arg->backend.data = ai;
1354 } else if (ainfo->regtype == RegTypeBase) {
1355 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1356 arg->opcode = OP_OUTARG_MEMBASE;
1357 ai->reg = ainfo->reg;
1358 ai->size = ainfo->size;
1359 ai->offset = ainfo->offset;
1360 arg->backend.data = ai;
1361 } else if (ainfo->regtype == RegTypeFP) {
1362 arg->opcode = OP_OUTARG_R8;
1363 arg->backend.reg3 = ainfo->reg;
1364 call->used_fregs |= 1 << ainfo->reg;
1365 if (ainfo->size == 4) {
1366 arg->opcode = OP_OUTARG_R8;
1367 /* we reduce the precision */
1369 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1370 conv->inst_left = arg->inst_left;
1371 arg->inst_left = conv;*/
1374 g_assert_not_reached ();
1379 * Reverse the call->out_args list.
1382 MonoInst *prev = NULL, *list = call->out_args, *next;
1389 call->out_args = prev;
1392 call->stack_usage = cinfo->stack_usage;
1393 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1394 cfg->flags |= MONO_CFG_HAS_CALLS;
1396 * should set more info in call, such as the stack space
1397 * used by the args that needs to be added back to esp
1405 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1407 int sig_reg = mono_alloc_ireg (cfg);
1409 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1411 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1415 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1418 MonoMethodSignature *sig;
1422 sig = call->signature;
1423 n = sig->param_count + sig->hasthis;
1425 cinfo = calculate_sizes (sig, sig->pinvoke);
1427 for (i = 0; i < n; ++i) {
1428 ArgInfo *ainfo = cinfo->args + i;
1431 if (i >= sig->hasthis)
1432 t = sig->params [i - sig->hasthis];
1434 t = &mono_defaults.int_class->byval_arg;
1435 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1437 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1438 emit_sig_cookie (cfg, call, cinfo);
1440 in = call->args [i];
1442 if (ainfo->regtype == RegTypeGeneral) {
1443 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1444 MONO_INST_NEW (cfg, ins, OP_MOVE);
1445 ins->dreg = mono_alloc_ireg (cfg);
1446 ins->sreg1 = in->dreg + 1;
1447 MONO_ADD_INS (cfg->cbb, ins);
1448 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1450 MONO_INST_NEW (cfg, ins, OP_MOVE);
1451 ins->dreg = mono_alloc_ireg (cfg);
1452 ins->sreg1 = in->dreg + 2;
1453 MONO_ADD_INS (cfg->cbb, ins);
1454 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1456 MONO_INST_NEW (cfg, ins, OP_MOVE);
1457 ins->dreg = mono_alloc_ireg (cfg);
1458 ins->sreg1 = in->dreg;
1459 MONO_ADD_INS (cfg->cbb, ins);
1461 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1463 } else if (ainfo->regtype == RegTypeStructByAddr) {
1464 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1465 ins->opcode = OP_OUTARG_VT;
1466 ins->sreg1 = in->dreg;
1467 ins->klass = in->klass;
1468 ins->inst_p0 = call;
1469 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1470 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1471 MONO_ADD_INS (cfg->cbb, ins);
1472 } else if (ainfo->regtype == RegTypeStructByVal) {
1473 /* this is further handled in mono_arch_emit_outarg_vt () */
1474 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1475 ins->opcode = OP_OUTARG_VT;
1476 ins->sreg1 = in->dreg;
1477 ins->klass = in->klass;
1478 ins->inst_p0 = call;
1479 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1480 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1481 MONO_ADD_INS (cfg->cbb, ins);
1482 } else if (ainfo->regtype == RegTypeBase) {
1483 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1484 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1485 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1486 if (t->type == MONO_TYPE_R8)
1487 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1489 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1491 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1493 } else if (ainfo->regtype == RegTypeFP) {
1494 if (t->type == MONO_TYPE_VALUETYPE) {
1495 /* this is further handled in mono_arch_emit_outarg_vt () */
1496 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1497 ins->opcode = OP_OUTARG_VT;
1498 ins->sreg1 = in->dreg;
1499 ins->klass = in->klass;
1500 ins->inst_p0 = call;
1501 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1502 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1503 MONO_ADD_INS (cfg->cbb, ins);
1505 cfg->flags |= MONO_CFG_HAS_FPOUT;
1507 int dreg = mono_alloc_freg (cfg);
1509 if (ainfo->size == 4) {
1510 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1512 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1514 ins->sreg1 = in->dreg;
1515 MONO_ADD_INS (cfg->cbb, ins);
1518 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1519 cfg->flags |= MONO_CFG_HAS_FPOUT;
1522 g_assert_not_reached ();
1526 /* Emit the signature cookie in the case that there is no
1527 additional argument */
1528 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1529 emit_sig_cookie (cfg, call, cinfo);
1531 if (cinfo->struct_ret) {
1534 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1535 vtarg->sreg1 = call->vret_var->dreg;
1536 vtarg->dreg = mono_alloc_preg (cfg);
1537 MONO_ADD_INS (cfg->cbb, vtarg);
1539 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1542 call->stack_usage = cinfo->stack_usage;
1543 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1544 cfg->flags |= MONO_CFG_HAS_CALLS;
1550 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1552 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1553 ArgInfo *ainfo = ins->inst_p1;
1554 int ovf_size = ainfo->vtsize;
1555 int doffset = ainfo->offset;
1556 int i, soffset, dreg;
1558 if (ainfo->regtype == RegTypeStructByVal) {
1563 * Darwin pinvokes needs some special handling for 1
1564 * and 2 byte arguments
1566 g_assert (ins->klass);
1567 if (call->signature->pinvoke)
1568 size = mono_class_native_size (ins->klass, NULL);
1569 if (size == 2 || size == 1) {
1570 int tmpr = mono_alloc_ireg (cfg);
1572 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1574 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1575 dreg = mono_alloc_ireg (cfg);
1576 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1577 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1580 for (i = 0; i < ainfo->size; ++i) {
1581 dreg = mono_alloc_ireg (cfg);
1582 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1583 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1584 soffset += sizeof (gpointer);
1587 mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1588 } else if (ainfo->regtype == RegTypeFP) {
1589 int tmpr = mono_alloc_freg (cfg);
1590 if (ainfo->size == 4)
1591 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1593 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1594 dreg = mono_alloc_freg (cfg);
1595 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1596 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1598 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1602 /* FIXME: alignment? */
1603 if (call->signature->pinvoke) {
1604 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1605 vtcopy->backend.is_pinvoke = 1;
1607 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1610 g_assert (ovf_size > 0);
1612 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1613 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1616 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1618 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1623 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1625 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1626 mono_method_signature (method)->ret);
1629 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1632 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1633 ins->sreg1 = val->dreg + 1;
1634 ins->sreg2 = val->dreg + 2;
1635 MONO_ADD_INS (cfg->cbb, ins);
1638 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1639 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1643 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1646 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1648 mono_arch_is_inst_imm (gint64 imm)
1654 * Allow tracing to work with this interface (with an optional argument)
1658 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1662 ppc_load (code, ppc_r3, cfg->method);
1663 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1664 ppc_load (code, ppc_r0, func);
1665 ppc_mtlr (code, ppc_r0);
1679 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1682 int save_mode = SAVE_NONE;
1684 MonoMethod *method = cfg->method;
1685 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1686 mono_method_signature (method)->ret)->type;
1687 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1691 offset = code - cfg->native_code;
1692 /* we need about 16 instructions */
1693 if (offset > (cfg->code_size - 16 * 4)) {
1694 cfg->code_size *= 2;
1695 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1696 code = cfg->native_code + offset;
1700 case MONO_TYPE_VOID:
1701 /* special case string .ctor icall */
1702 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1703 save_mode = SAVE_ONE;
1705 save_mode = SAVE_NONE;
1709 save_mode = SAVE_TWO;
1713 save_mode = SAVE_FP;
1715 case MONO_TYPE_VALUETYPE:
1716 save_mode = SAVE_STRUCT;
1719 save_mode = SAVE_ONE;
1723 switch (save_mode) {
1725 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1726 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1727 if (enable_arguments) {
1728 ppc_mr (code, ppc_r5, ppc_r4);
1729 ppc_mr (code, ppc_r4, ppc_r3);
1733 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1734 if (enable_arguments) {
1735 ppc_mr (code, ppc_r4, ppc_r3);
1739 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1740 if (enable_arguments) {
1741 /* FIXME: what reg? */
1742 ppc_fmr (code, ppc_f3, ppc_f1);
1743 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1744 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1748 if (enable_arguments) {
1749 /* FIXME: get the actual address */
1750 ppc_mr (code, ppc_r4, ppc_r3);
1758 ppc_load (code, ppc_r3, cfg->method);
1759 ppc_load (code, ppc_r0, func);
1760 ppc_mtlr (code, ppc_r0);
1763 switch (save_mode) {
1765 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1766 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1769 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1772 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1782 * Conditional branches have a small offset, so if it is likely overflowed,
1783 * we do a branch to the end of the method (uncond branches have much larger
1784 * offsets) where we perform the conditional and jump back unconditionally.
1785 * It's slightly slower, since we add two uncond branches, but it's very simple
1786 * with the current patch implementation and such large methods are likely not
1787 * going to be perf critical anyway.
1792 const char *exception;
1799 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1800 if (ins->flags & MONO_INST_BRLABEL) { \
1801 if (0 && ins->inst_i0->inst_c0) { \
1802 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1804 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1805 ppc_bc (code, (b0), (b1), 0); \
1808 if (0 && ins->inst_true_bb->native_offset) { \
1809 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1811 int br_disp = ins->inst_true_bb->max_offset - offset; \
1812 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1813 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1814 ovfj->data.bb = ins->inst_true_bb; \
1815 ovfj->ip_offset = 0; \
1816 ovfj->b0_cond = (b0); \
1817 ovfj->b1_cond = (b1); \
1818 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1821 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1822 ppc_bc (code, (b0), (b1), 0); \
1827 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1829 /* emit an exception if condition is fail
1831 * We assign the extra code used to throw the implicit exceptions
1832 * to cfg->bb_exit as far as the big branch handling is concerned
1834 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1836 int br_disp = cfg->bb_exit->max_offset - offset; \
1837 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1838 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1839 ovfj->data.exception = (exc_name); \
1840 ovfj->ip_offset = code - cfg->native_code; \
1841 ovfj->b0_cond = (b0); \
1842 ovfj->b1_cond = (b1); \
1843 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1845 cfg->bb_exit->max_offset += 24; \
1847 mono_add_patch_info (cfg, code - cfg->native_code, \
1848 MONO_PATCH_INFO_EXC, exc_name); \
1849 ppc_bcl (code, (b0), (b1), 0); \
1853 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1856 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1861 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1863 MonoInst *ins, *n, *last_ins = NULL;
1865 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1866 switch (ins->opcode) {
1868 /* remove unnecessary multiplication with 1 */
1869 if (ins->inst_imm == 1) {
1870 if (ins->dreg != ins->sreg1) {
1871 ins->opcode = OP_MOVE;
1873 MONO_DELETE_INS (bb, ins);
1877 int power2 = mono_is_power_of_two (ins->inst_imm);
1879 ins->opcode = OP_SHL_IMM;
1880 ins->inst_imm = power2;
1884 case OP_LOAD_MEMBASE:
1885 case OP_LOADI4_MEMBASE:
1887 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1888 * OP_LOAD_MEMBASE offset(basereg), reg
1890 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1891 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1892 ins->inst_basereg == last_ins->inst_destbasereg &&
1893 ins->inst_offset == last_ins->inst_offset) {
1894 if (ins->dreg == last_ins->sreg1) {
1895 MONO_DELETE_INS (bb, ins);
1898 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1899 ins->opcode = OP_MOVE;
1900 ins->sreg1 = last_ins->sreg1;
1904 * Note: reg1 must be different from the basereg in the second load
1905 * OP_LOAD_MEMBASE offset(basereg), reg1
1906 * OP_LOAD_MEMBASE offset(basereg), reg2
1908 * OP_LOAD_MEMBASE offset(basereg), reg1
1909 * OP_MOVE reg1, reg2
1911 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1912 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1913 ins->inst_basereg != last_ins->dreg &&
1914 ins->inst_basereg == last_ins->inst_basereg &&
1915 ins->inst_offset == last_ins->inst_offset) {
1917 if (ins->dreg == last_ins->dreg) {
1918 MONO_DELETE_INS (bb, ins);
1921 ins->opcode = OP_MOVE;
1922 ins->sreg1 = last_ins->dreg;
1925 //g_assert_not_reached ();
1929 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1930 * OP_LOAD_MEMBASE offset(basereg), reg
1932 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1933 * OP_ICONST reg, imm
1935 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1936 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1937 ins->inst_basereg == last_ins->inst_destbasereg &&
1938 ins->inst_offset == last_ins->inst_offset) {
1939 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1940 ins->opcode = OP_ICONST;
1941 ins->inst_c0 = last_ins->inst_imm;
1942 g_assert_not_reached (); // check this rule
1946 case OP_LOADU1_MEMBASE:
1947 case OP_LOADI1_MEMBASE:
1948 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1949 ins->inst_basereg == last_ins->inst_destbasereg &&
1950 ins->inst_offset == last_ins->inst_offset) {
1951 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1952 ins->sreg1 = last_ins->sreg1;
1955 case OP_LOADU2_MEMBASE:
1956 case OP_LOADI2_MEMBASE:
1957 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1958 ins->inst_basereg == last_ins->inst_destbasereg &&
1959 ins->inst_offset == last_ins->inst_offset) {
1960 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1961 ins->sreg1 = last_ins->sreg1;
1965 ins->opcode = OP_MOVE;
1969 if (ins->dreg == ins->sreg1) {
1970 MONO_DELETE_INS (bb, ins);
1974 * OP_MOVE sreg, dreg
1975 * OP_MOVE dreg, sreg
1977 if (last_ins && last_ins->opcode == OP_MOVE &&
1978 ins->sreg1 == last_ins->dreg &&
1979 ins->dreg == last_ins->sreg1) {
1980 MONO_DELETE_INS (bb, ins);
1988 bb->last_ins = last_ins;
1992 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1994 g_assert (cfg->new_ir);
1996 switch (ins->opcode) {
1997 case OP_ICONV_TO_R_UN: {
1998 static const guint64 adjust_val = 0x4330000000000000ULL;
1999 int msw_reg = mono_alloc_ireg (cfg);
2000 int adj_reg = mono_alloc_freg (cfg);
2001 int tmp_reg = mono_alloc_freg (cfg);
2002 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2003 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2004 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
2005 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2006 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2007 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2008 ins->opcode = OP_NOP;
2011 case OP_ICONV_TO_R4:
2012 case OP_ICONV_TO_R8: {
2013 /* FIXME: change precision for CEE_CONV_R4 */
2014 static const guint64 adjust_val = 0x4330000080000000ULL;
2015 int msw_reg = mono_alloc_ireg (cfg);
2016 int xored = mono_alloc_ireg (cfg);
2017 int adj_reg = mono_alloc_freg (cfg);
2018 int tmp_reg = mono_alloc_freg (cfg);
2019 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2020 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2021 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2022 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2023 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2024 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2025 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2026 if (ins->opcode == OP_ICONV_TO_R4)
2027 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2028 ins->opcode = OP_NOP;
2032 int msw_reg = mono_alloc_ireg (cfg);
2033 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2034 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2035 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2036 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2037 ins->opcode = OP_NOP;
2044 * the branch_b0_table should maintain the order of these
2058 branch_b0_table [] = {
2073 branch_b1_table [] = {
2087 #define NEW_INS(cfg,dest,op) do { \
2088 MONO_INST_NEW((cfg), (dest), (op)); \
2089 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2093 map_to_reg_reg_op (int op)
2102 case OP_COMPARE_IMM:
2104 case OP_ICOMPARE_IMM:
2120 case OP_LOAD_MEMBASE:
2121 return OP_LOAD_MEMINDEX;
2122 case OP_LOADI4_MEMBASE:
2123 return OP_LOADI4_MEMINDEX;
2124 case OP_LOADU4_MEMBASE:
2125 return OP_LOADU4_MEMINDEX;
2126 case OP_LOADU1_MEMBASE:
2127 return OP_LOADU1_MEMINDEX;
2128 case OP_LOADI2_MEMBASE:
2129 return OP_LOADI2_MEMINDEX;
2130 case OP_LOADU2_MEMBASE:
2131 return OP_LOADU2_MEMINDEX;
2132 case OP_LOADI1_MEMBASE:
2133 return OP_LOADI1_MEMINDEX;
2134 case OP_LOADR4_MEMBASE:
2135 return OP_LOADR4_MEMINDEX;
2136 case OP_LOADR8_MEMBASE:
2137 return OP_LOADR8_MEMINDEX;
2138 case OP_STOREI1_MEMBASE_REG:
2139 return OP_STOREI1_MEMINDEX;
2140 case OP_STOREI2_MEMBASE_REG:
2141 return OP_STOREI2_MEMINDEX;
2142 case OP_STOREI4_MEMBASE_REG:
2143 return OP_STOREI4_MEMINDEX;
2144 case OP_STORE_MEMBASE_REG:
2145 return OP_STORE_MEMINDEX;
2146 case OP_STORER4_MEMBASE_REG:
2147 return OP_STORER4_MEMINDEX;
2148 case OP_STORER8_MEMBASE_REG:
2149 return OP_STORER8_MEMINDEX;
2150 case OP_STORE_MEMBASE_IMM:
2151 return OP_STORE_MEMBASE_REG;
2152 case OP_STOREI1_MEMBASE_IMM:
2153 return OP_STOREI1_MEMBASE_REG;
2154 case OP_STOREI2_MEMBASE_IMM:
2155 return OP_STOREI2_MEMBASE_REG;
2156 case OP_STOREI4_MEMBASE_IMM:
2157 return OP_STOREI4_MEMBASE_REG;
2159 return mono_op_imm_to_op (op);
2162 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2164 #define compare_opcode_is_unsigned(opcode) \
2165 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2166 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2167 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2168 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2169 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2171 * Remove from the instruction list the instructions that can't be
2172 * represented with very simple instructions with no register
2176 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2178 MonoInst *ins, *next, *temp, *last_ins = NULL;
2181 /* setup the virtual reg allocator */
2182 if (bb->max_vreg > cfg->rs->next_vreg)
2183 cfg->rs->next_vreg = bb->max_vreg;
2185 MONO_BB_FOR_EACH_INS (bb, ins) {
2187 switch (ins->opcode) {
2188 case OP_IDIV_UN_IMM:
2191 case OP_IREM_UN_IMM:
2192 NEW_INS (cfg, temp, OP_ICONST);
2193 temp->inst_c0 = ins->inst_imm;
2194 temp->dreg = mono_regstate_next_int (cfg->rs);
2195 ins->sreg2 = temp->dreg;
2196 if (ins->opcode == OP_IDIV_IMM)
2197 ins->opcode = OP_IDIV;
2198 else if (ins->opcode == OP_IREM_IMM)
2199 ins->opcode = OP_IREM;
2200 else if (ins->opcode == OP_IDIV_UN_IMM)
2201 ins->opcode = OP_IDIV_UN;
2202 else if (ins->opcode == OP_IREM_UN_IMM)
2203 ins->opcode = OP_IREM_UN;
2205 /* handle rem separately */
2210 /* we change a rem dest, src1, src2 to
2211 * div temp1, src1, src2
2212 * mul temp2, temp1, src2
2213 * sub dest, src1, temp2
2215 NEW_INS (cfg, mul, OP_IMUL);
2216 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2217 temp->sreg1 = ins->sreg1;
2218 temp->sreg2 = ins->sreg2;
2219 temp->dreg = mono_regstate_next_int (cfg->rs);
2220 mul->sreg1 = temp->dreg;
2221 mul->sreg2 = ins->sreg2;
2222 mul->dreg = mono_regstate_next_int (cfg->rs);
2223 ins->opcode = OP_ISUB;
2224 ins->sreg2 = mul->dreg;
2230 if (!ppc_is_imm16 (ins->inst_imm)) {
2231 NEW_INS (cfg, temp, OP_ICONST);
2232 temp->inst_c0 = ins->inst_imm;
2233 temp->dreg = mono_regstate_next_int (cfg->rs);
2234 ins->sreg2 = temp->dreg;
2235 ins->opcode = map_to_reg_reg_op (ins->opcode);
2240 if (!ppc_is_imm16 (-ins->inst_imm)) {
2241 NEW_INS (cfg, temp, OP_ICONST);
2242 temp->inst_c0 = ins->inst_imm;
2243 temp->dreg = mono_regstate_next_int (cfg->rs);
2244 ins->sreg2 = temp->dreg;
2245 ins->opcode = map_to_reg_reg_op (ins->opcode);
2254 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2255 NEW_INS (cfg, temp, OP_ICONST);
2256 temp->inst_c0 = ins->inst_imm;
2257 temp->dreg = mono_regstate_next_int (cfg->rs);
2258 ins->sreg2 = temp->dreg;
2259 ins->opcode = map_to_reg_reg_op (ins->opcode);
2267 NEW_INS (cfg, temp, OP_ICONST);
2268 temp->inst_c0 = ins->inst_imm;
2269 temp->dreg = mono_regstate_next_int (cfg->rs);
2270 ins->sreg2 = temp->dreg;
2271 ins->opcode = map_to_reg_reg_op (ins->opcode);
2273 case OP_COMPARE_IMM:
2274 case OP_ICOMPARE_IMM:
2276 /* Branch opts can eliminate the branch */
2277 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2278 ins->opcode = OP_NOP;
2282 if (compare_opcode_is_unsigned (next->opcode)) {
2283 if (!ppc_is_uimm16 (ins->inst_imm)) {
2284 NEW_INS (cfg, temp, OP_ICONST);
2285 temp->inst_c0 = ins->inst_imm;
2286 temp->dreg = mono_regstate_next_int (cfg->rs);
2287 ins->sreg2 = temp->dreg;
2288 ins->opcode = map_to_reg_reg_op (ins->opcode);
2291 if (!ppc_is_imm16 (ins->inst_imm)) {
2292 NEW_INS (cfg, temp, OP_ICONST);
2293 temp->inst_c0 = ins->inst_imm;
2294 temp->dreg = mono_regstate_next_int (cfg->rs);
2295 ins->sreg2 = temp->dreg;
2296 ins->opcode = map_to_reg_reg_op (ins->opcode);
2302 if (ins->inst_imm == 1) {
2303 ins->opcode = OP_MOVE;
2306 if (ins->inst_imm == 0) {
2307 ins->opcode = OP_ICONST;
2311 imm = mono_is_power_of_two (ins->inst_imm);
2313 ins->opcode = OP_SHL_IMM;
2314 ins->inst_imm = imm;
2317 if (!ppc_is_imm16 (ins->inst_imm)) {
2318 NEW_INS (cfg, temp, OP_ICONST);
2319 temp->inst_c0 = ins->inst_imm;
2320 temp->dreg = mono_regstate_next_int (cfg->rs);
2321 ins->sreg2 = temp->dreg;
2322 ins->opcode = map_to_reg_reg_op (ins->opcode);
2325 case OP_LOCALLOC_IMM:
2326 NEW_INS (cfg, temp, OP_ICONST);
2327 temp->inst_c0 = ins->inst_imm;
2328 temp->dreg = mono_regstate_next_int (cfg->rs);
2329 ins->sreg1 = temp->dreg;
2330 ins->opcode = OP_LOCALLOC;
2332 case OP_LOAD_MEMBASE:
2333 case OP_LOADI4_MEMBASE:
2334 case OP_LOADU4_MEMBASE:
2335 case OP_LOADI2_MEMBASE:
2336 case OP_LOADU2_MEMBASE:
2337 case OP_LOADI1_MEMBASE:
2338 case OP_LOADU1_MEMBASE:
2339 case OP_LOADR4_MEMBASE:
2340 case OP_LOADR8_MEMBASE:
2341 case OP_STORE_MEMBASE_REG:
2342 case OP_STOREI4_MEMBASE_REG:
2343 case OP_STOREI2_MEMBASE_REG:
2344 case OP_STOREI1_MEMBASE_REG:
2345 case OP_STORER4_MEMBASE_REG:
2346 case OP_STORER8_MEMBASE_REG:
2347 /* we can do two things: load the immed in a register
2348 * and use an indexed load, or see if the immed can be
2349 * represented as an ad_imm + a load with a smaller offset
2350 * that fits. We just do the first for now, optimize later.
2352 if (ppc_is_imm16 (ins->inst_offset))
2354 NEW_INS (cfg, temp, OP_ICONST);
2355 temp->inst_c0 = ins->inst_offset;
2356 temp->dreg = mono_regstate_next_int (cfg->rs);
2357 ins->sreg2 = temp->dreg;
2358 ins->opcode = map_to_reg_reg_op (ins->opcode);
2360 case OP_STORE_MEMBASE_IMM:
2361 case OP_STOREI1_MEMBASE_IMM:
2362 case OP_STOREI2_MEMBASE_IMM:
2363 case OP_STOREI4_MEMBASE_IMM:
2364 NEW_INS (cfg, temp, OP_ICONST);
2365 temp->inst_c0 = ins->inst_imm;
2366 temp->dreg = mono_regstate_next_int (cfg->rs);
2367 ins->sreg1 = temp->dreg;
2368 ins->opcode = map_to_reg_reg_op (ins->opcode);
2370 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2373 NEW_INS (cfg, temp, OP_ICONST);
2374 temp->inst_c0 = (guint32)ins->inst_p0;
2375 temp->dreg = mono_regstate_next_int (cfg->rs);
2376 ins->inst_basereg = temp->dreg;
2377 ins->inst_offset = 0;
2378 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2380 /* make it handle the possibly big ins->inst_offset
2381 * later optimize to use lis + load_membase
2387 bb->last_ins = last_ins;
2388 bb->max_vreg = cfg->rs->next_vreg;
2393 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2395 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2396 ppc_fctiwz (code, ppc_f0, sreg);
2397 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2398 ppc_lwz (code, dreg, -4, ppc_sp);
2401 ppc_andid (code, dreg, dreg, 0xff);
2403 ppc_andid (code, dreg, dreg, 0xffff);
2406 ppc_extsb (code, dreg, dreg);
2408 ppc_extsh (code, dreg, dreg);
2415 const guchar *target;
2420 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2423 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2424 PatchData *pdata = (PatchData*)user_data;
2425 guchar *code = data;
2426 guint32 *thunks = data;
2427 guint32 *endthunks = (guint32*)(code + bsize);
2431 int difflow, diffhigh;
2433 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2434 difflow = (char*)pdata->code - (char*)thunks;
2435 diffhigh = (char*)pdata->code - (char*)endthunks;
2436 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2439 templ = (guchar*)load;
2440 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2441 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2443 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2444 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2445 while (thunks < endthunks) {
2446 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2447 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2448 ppc_patch (pdata->code, (guchar*)thunks);
2449 mono_arch_flush_icache (pdata->code, 4);
2452 static int num_thunks = 0;
2454 if ((num_thunks % 20) == 0)
2455 g_print ("num_thunks lookup: %d\n", num_thunks);
2458 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2459 /* found a free slot instead: emit thunk */
2460 code = (guchar*)thunks;
2461 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2462 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2463 ppc_mtctr (code, ppc_r0);
2464 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2465 mono_arch_flush_icache ((guchar*)thunks, 16);
2467 ppc_patch (pdata->code, (guchar*)thunks);
2468 mono_arch_flush_icache (pdata->code, 4);
2471 static int num_thunks = 0;
2473 if ((num_thunks % 20) == 0)
2474 g_print ("num_thunks: %d\n", num_thunks);
2478 /* skip 16 bytes, the size of the thunk */
2482 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2488 handle_thunk (int absolute, guchar *code, const guchar *target) {
2489 MonoDomain *domain = mono_domain_get ();
2493 pdata.target = target;
2494 pdata.absolute = absolute;
2497 mono_domain_lock (domain);
2498 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2501 /* this uses the first available slot */
2503 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2505 mono_domain_unlock (domain);
2507 if (pdata.found != 1)
2508 g_print ("thunk failed for %p from %p\n", target, code);
2509 g_assert (pdata.found == 1);
2513 ppc_patch (guchar *code, const guchar *target)
2515 guint32 ins = *(guint32*)code;
2516 guint32 prim = ins >> 26;
2519 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2521 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2522 gint diff = target - code;
2524 if (diff <= 33554431){
2525 ins = (18 << 26) | (diff) | (ins & 1);
2526 *(guint32*)code = ins;
2530 /* diff between 0 and -33554432 */
2531 if (diff >= -33554432){
2532 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2533 *(guint32*)code = ins;
2538 if ((glong)target >= 0){
2539 if ((glong)target <= 33554431){
2540 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2541 *(guint32*)code = ins;
2545 if ((glong)target >= -33554432){
2546 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2547 *(guint32*)code = ins;
2552 handle_thunk (TRUE, code, target);
2555 g_assert_not_reached ();
2562 guint32 li = (guint32)target;
2563 ins = (ins & 0xffff0000) | (ins & 3);
2564 ovf = li & 0xffff0000;
2565 if (ovf != 0 && ovf != 0xffff0000)
2566 g_assert_not_reached ();
2569 // FIXME: assert the top bits of li are 0
2571 gint diff = target - code;
2572 ins = (ins & 0xffff0000) | (ins & 3);
2573 ovf = diff & 0xffff0000;
2574 if (ovf != 0 && ovf != 0xffff0000)
2575 g_assert_not_reached ();
2579 *(guint32*)code = ins;
2583 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2585 /* the trampoline code will try to patch the blrl, blr, bcctr */
2586 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2589 /* this is the lis/ori/mtlr/blrl sequence */
2590 seq = (guint32*)code;
2591 g_assert ((seq [0] >> 26) == 15);
2592 g_assert ((seq [1] >> 26) == 24);
2593 g_assert ((seq [2] >> 26) == 31);
2594 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2595 /* FIXME: make this thread safe */
2596 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2597 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2598 mono_arch_flush_icache (code - 8, 8);
2600 g_assert_not_reached ();
2602 // g_print ("patched with 0x%08x\n", ins);
2606 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2608 switch (ins->opcode) {
2611 case OP_FCALL_MEMBASE:
2612 if (ins->dreg != ppc_f1)
2613 ppc_fmr (code, ins->dreg, ppc_f1);
2621 * emit_load_volatile_arguments:
2623 * Load volatile arguments from the stack to the original input registers.
2624 * Required before a tail call.
2627 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2629 MonoMethod *method = cfg->method;
2630 MonoMethodSignature *sig;
2634 int struct_index = 0;
2636 /* FIXME: Generate intermediate code instead */
2638 sig = mono_method_signature (method);
2640 /* This is the opposite of the code in emit_prolog */
2644 cinfo = calculate_sizes (sig, sig->pinvoke);
2646 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2647 ArgInfo *ainfo = &cinfo->ret;
2648 inst = cfg->vret_addr;
2649 g_assert (ppc_is_imm16 (inst->inst_offset));
2650 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2652 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2653 ArgInfo *ainfo = cinfo->args + i;
2654 inst = cfg->args [pos];
2656 g_assert (inst->opcode != OP_REGVAR);
2657 g_assert (ppc_is_imm16 (inst->inst_offset));
2659 switch (ainfo->regtype) {
2660 case RegTypeGeneral:
2661 switch (ainfo->size) {
2663 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2666 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2669 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2675 switch (ainfo->size) {
2677 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2680 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2683 g_assert_not_reached ();
2688 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
2689 &inst->klass->byval_arg);
2691 if (!MONO_TYPE_IS_REFERENCE (type) && type->type != MONO_TYPE_I4)
2694 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2695 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
2699 case RegTypeStructByVal: {
2708 * Darwin pinvokes needs some special handling
2709 * for 1 and 2 byte arguments
2711 if (method->signature->pinvoke)
2712 size = mono_class_native_size (inst->klass, NULL);
2713 if (size == 1 || size == 2) {
2718 for (j = 0; j < ainfo->size; ++j) {
2719 ppc_lwz (code, ainfo->reg + j,
2720 inst->inst_offset + j * sizeof (gpointer), inst->inst_basereg);
2725 case RegTypeStructByAddr: {
2726 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2728 g_assert (ppc_is_imm16 (addr->inst_offset));
2729 g_assert (!ainfo->offset);
2730 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2737 g_assert_not_reached ();
2748 /* This must be kept in sync with emit_load_volatile_arguments(). */
2750 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2752 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2753 MonoMethodSignature *sig;
2758 if (ins->opcode != OP_JMP)
2761 call = (MonoCallInst*)ins;
2762 sig = mono_method_signature (cfg->method);
2763 cinfo = calculate_sizes (sig, sig->pinvoke);
2765 if (MONO_TYPE_ISSTRUCT (sig->ret))
2767 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2768 ArgInfo *ainfo = cinfo->args + i;
2770 switch (ainfo->regtype) {
2771 case RegTypeGeneral:
2780 case RegTypeStructByVal:
2781 len += 4 * ainfo->size;
2784 case RegTypeStructByAddr:
2789 g_assert_not_reached ();
2799 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2801 MonoInst *ins, *next;
2804 guint8 *code = cfg->native_code + cfg->code_len;
2805 MonoInst *last_ins = NULL;
2806 guint last_offset = 0;
2809 /* we don't align basic blocks of loops on ppc */
2811 if (cfg->verbose_level > 2)
2812 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2814 cpos = bb->max_offset;
2816 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2817 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2818 //g_assert (!mono_compile_aot);
2821 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2822 /* this is not thread save, but good enough */
2823 /* fixme: howto handle overflows? */
2824 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2827 MONO_BB_FOR_EACH_INS (bb, ins) {
2828 offset = code - cfg->native_code;
2830 max_len = ins_native_length (cfg, ins);
2832 if (offset > (cfg->code_size - max_len - 16)) {
2833 cfg->code_size *= 2;
2834 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2835 code = cfg->native_code + offset;
2837 // if (ins->cil_code)
2838 // g_print ("cil code\n");
2839 mono_debug_record_line_number (cfg, ins, offset);
2841 switch (ins->opcode) {
2842 case OP_RELAXED_NOP:
2845 case OP_DUMMY_STORE:
2846 case OP_NOT_REACHED:
2850 emit_tls_access (code, ins->dreg, ins->inst_offset);
2853 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2854 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2855 ppc_mr (code, ppc_r4, ppc_r0);
2858 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2859 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2860 ppc_mr (code, ppc_r4, ppc_r0);
2862 case OP_MEMORY_BARRIER:
2865 case OP_STOREI1_MEMBASE_REG:
2866 if (ppc_is_imm16 (ins->inst_offset)) {
2867 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2869 ppc_load (code, ppc_r0, ins->inst_offset);
2870 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2873 case OP_STOREI2_MEMBASE_REG:
2874 if (ppc_is_imm16 (ins->inst_offset)) {
2875 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2877 ppc_load (code, ppc_r0, ins->inst_offset);
2878 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2881 case OP_STORE_MEMBASE_REG:
2882 case OP_STOREI4_MEMBASE_REG:
2883 if (ppc_is_imm16 (ins->inst_offset)) {
2884 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2886 ppc_load (code, ppc_r0, ins->inst_offset);
2887 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2890 case OP_STOREI1_MEMINDEX:
2891 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2893 case OP_STOREI2_MEMINDEX:
2894 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2896 case OP_STORE_MEMINDEX:
2897 case OP_STOREI4_MEMINDEX:
2898 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2901 g_assert_not_reached ();
2903 case OP_LOAD_MEMBASE:
2904 case OP_LOADI4_MEMBASE:
2905 case OP_LOADU4_MEMBASE:
2906 if (ppc_is_imm16 (ins->inst_offset)) {
2907 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2909 ppc_load (code, ppc_r0, ins->inst_offset);
2910 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2913 case OP_LOADI1_MEMBASE:
2914 case OP_LOADU1_MEMBASE:
2915 if (ppc_is_imm16 (ins->inst_offset)) {
2916 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2918 ppc_load (code, ppc_r0, ins->inst_offset);
2919 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2921 if (ins->opcode == OP_LOADI1_MEMBASE)
2922 ppc_extsb (code, ins->dreg, ins->dreg);
2924 case OP_LOADU2_MEMBASE:
2925 if (ppc_is_imm16 (ins->inst_offset)) {
2926 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2928 ppc_load (code, ppc_r0, ins->inst_offset);
2929 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2932 case OP_LOADI2_MEMBASE:
2933 if (ppc_is_imm16 (ins->inst_offset)) {
2934 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2936 ppc_load (code, ppc_r0, ins->inst_offset);
2937 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2940 case OP_LOAD_MEMINDEX:
2941 case OP_LOADI4_MEMINDEX:
2942 case OP_LOADU4_MEMINDEX:
2943 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2945 case OP_LOADU2_MEMINDEX:
2946 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2948 case OP_LOADI2_MEMINDEX:
2949 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2951 case OP_LOADU1_MEMINDEX:
2952 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2954 case OP_LOADI1_MEMINDEX:
2955 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2956 ppc_extsb (code, ins->dreg, ins->dreg);
2958 case OP_ICONV_TO_I1:
2959 ppc_extsb (code, ins->dreg, ins->sreg1);
2961 case OP_ICONV_TO_I2:
2962 ppc_extsh (code, ins->dreg, ins->sreg1);
2964 case OP_ICONV_TO_U1:
2965 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2967 case OP_ICONV_TO_U2:
2968 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2973 if (next && compare_opcode_is_unsigned (next->opcode))
2974 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2976 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2978 case OP_COMPARE_IMM:
2979 case OP_ICOMPARE_IMM:
2981 if (next && compare_opcode_is_unsigned (next->opcode)) {
2982 if (ppc_is_uimm16 (ins->inst_imm)) {
2983 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2985 g_assert_not_reached ();
2988 if (ppc_is_imm16 (ins->inst_imm)) {
2989 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2991 g_assert_not_reached ();
3000 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
3003 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3007 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3010 if (ppc_is_imm16 (ins->inst_imm)) {
3011 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3013 g_assert_not_reached ();
3018 if (ppc_is_imm16 (ins->inst_imm)) {
3019 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3021 g_assert_not_reached ();
3025 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3027 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3028 ppc_mfspr (code, ppc_r0, ppc_xer);
3029 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3030 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3032 case OP_IADD_OVF_UN:
3033 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3035 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3036 ppc_mfspr (code, ppc_r0, ppc_xer);
3037 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3038 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3041 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3043 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3044 ppc_mfspr (code, ppc_r0, ppc_xer);
3045 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3046 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3048 case OP_ISUB_OVF_UN:
3049 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3051 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3052 ppc_mfspr (code, ppc_r0, ppc_xer);
3053 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3054 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3056 case OP_ADD_OVF_CARRY:
3057 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3059 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3060 ppc_mfspr (code, ppc_r0, ppc_xer);
3061 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3062 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3064 case OP_ADD_OVF_UN_CARRY:
3065 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3067 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3068 ppc_mfspr (code, ppc_r0, ppc_xer);
3069 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3070 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3072 case OP_SUB_OVF_CARRY:
3073 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3075 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3076 ppc_mfspr (code, ppc_r0, ppc_xer);
3077 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3078 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3080 case OP_SUB_OVF_UN_CARRY:
3081 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3083 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3084 ppc_mfspr (code, ppc_r0, ppc_xer);
3085 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3086 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3090 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3093 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3097 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3101 // we add the negated value
3102 if (ppc_is_imm16 (-ins->inst_imm))
3103 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3105 g_assert_not_reached ();
3109 g_assert (ppc_is_imm16 (ins->inst_imm));
3110 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3113 ppc_subfze (code, ins->dreg, ins->sreg1);
3116 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3117 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3121 if (!(ins->inst_imm & 0xffff0000)) {
3122 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3123 } else if (!(ins->inst_imm & 0xffff)) {
3124 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3126 g_assert_not_reached ();
3130 guint8 *divisor_is_m1;
3131 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3133 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3134 divisor_is_m1 = code;
3135 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3136 ppc_lis (code, ppc_r0, 0x8000);
3137 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3138 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3139 ppc_patch (divisor_is_m1, code);
3140 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3142 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3143 ppc_mfspr (code, ppc_r0, ppc_xer);
3144 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3145 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3149 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3150 ppc_mfspr (code, ppc_r0, ppc_xer);
3151 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3152 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3158 g_assert_not_reached ();
3160 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3164 if (!(ins->inst_imm & 0xffff0000)) {
3165 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3166 } else if (!(ins->inst_imm & 0xffff)) {
3167 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3169 g_assert_not_reached ();
3173 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3177 if (!(ins->inst_imm & 0xffff0000)) {
3178 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3179 } else if (!(ins->inst_imm & 0xffff)) {
3180 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3182 g_assert_not_reached ();
3186 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3190 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3193 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3197 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3200 case OP_ISHR_UN_IMM:
3202 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3204 ppc_mr (code, ins->dreg, ins->sreg1);
3207 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3210 ppc_not (code, ins->dreg, ins->sreg1);
3213 ppc_neg (code, ins->dreg, ins->sreg1);
3216 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3220 if (ppc_is_imm16 (ins->inst_imm)) {
3221 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3223 g_assert_not_reached ();
3227 /* we annot use mcrxr, since it's not implemented on some processors
3228 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3230 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3231 ppc_mfspr (code, ppc_r0, ppc_xer);
3232 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3233 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3235 case OP_IMUL_OVF_UN:
3236 /* we first multiply to get the high word and compare to 0
3237 * to set the flags, then the result is discarded and then
3238 * we multiply to get the lower * bits result
3240 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3241 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3242 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3243 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3246 ppc_load (code, ins->dreg, ins->inst_c0);
3249 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3250 ppc_lis (code, ins->dreg, 0);
3251 ppc_ori (code, ins->dreg, ins->dreg, 0);
3253 case OP_ICONV_TO_I4:
3254 case OP_ICONV_TO_U4:
3256 ppc_mr (code, ins->dreg, ins->sreg1);
3259 int saved = ins->sreg1;
3260 if (ins->sreg1 == ppc_r3) {
3261 ppc_mr (code, ppc_r0, ins->sreg1);
3264 if (ins->sreg2 != ppc_r3)
3265 ppc_mr (code, ppc_r3, ins->sreg2);
3266 if (saved != ppc_r4)
3267 ppc_mr (code, ppc_r4, saved);
3271 ppc_fmr (code, ins->dreg, ins->sreg1);
3273 case OP_FCONV_TO_R4:
3274 ppc_frsp (code, ins->dreg, ins->sreg1);
3280 * Keep in sync with mono_arch_emit_epilog
3282 g_assert (!cfg->method->save_lmf);
3284 * Note: we can use ppc_r11 here because it is dead anyway:
3285 * we're leaving the method.
3287 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3288 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3289 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3291 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3292 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3294 ppc_mtlr (code, ppc_r0);
3297 code = emit_load_volatile_arguments (cfg, code);
3299 if (ppc_is_imm16 (cfg->stack_usage)) {
3300 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3302 ppc_load (code, ppc_r11, cfg->stack_usage);
3303 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3305 if (!cfg->method->save_lmf) {
3306 /*for (i = 31; i >= 14; --i) {
3307 if (cfg->used_float_regs & (1 << i)) {
3308 pos += sizeof (double);
3309 ppc_lfd (code, i, -pos, cfg->frame_reg);
3312 for (i = 31; i >= 13; --i) {
3313 if (cfg->used_int_regs & (1 << i)) {
3314 pos += sizeof (gulong);
3315 ppc_lwz (code, i, -pos, ppc_sp);
3319 /* FIXME restore from MonoLMF: though this can't happen yet */
3321 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3326 /* ensure ins->sreg1 is not NULL */
3327 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3330 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3331 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3333 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3334 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3336 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3345 call = (MonoCallInst*)ins;
3346 if (ins->flags & MONO_INST_HAS_METHOD)
3347 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3349 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3350 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3351 ppc_lis (code, ppc_r0, 0);
3352 ppc_ori (code, ppc_r0, ppc_r0, 0);
3353 ppc_mtlr (code, ppc_r0);
3358 /* FIXME: this should be handled somewhere else in the new jit */
3359 code = emit_move_return_value (cfg, ins, code);
3365 case OP_VOIDCALL_REG:
3367 ppc_mtlr (code, ins->sreg1);
3369 /* FIXME: this should be handled somewhere else in the new jit */
3370 code = emit_move_return_value (cfg, ins, code);
3372 case OP_FCALL_MEMBASE:
3373 case OP_LCALL_MEMBASE:
3374 case OP_VCALL_MEMBASE:
3375 case OP_VCALL2_MEMBASE:
3376 case OP_VOIDCALL_MEMBASE:
3377 case OP_CALL_MEMBASE:
3378 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3379 ppc_mtlr (code, ppc_r0);
3381 /* FIXME: this should be handled somewhere else in the new jit */
3382 code = emit_move_return_value (cfg, ins, code);
3385 g_assert_not_reached ();
3388 guint8 * zero_loop_jump, * zero_loop_start;
3389 /* keep alignment */
3390 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3391 int area_offset = alloca_waste;
3393 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3394 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3395 /* use ctr to store the number of words to 0 if needed */
3396 if (ins->flags & MONO_INST_INIT) {
3397 /* we zero 4 bytes at a time:
3398 * we add 7 instead of 3 so that we set the counter to
3399 * at least 1, otherwise the bdnz instruction will make
3400 * it negative and iterate billions of times.
3402 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3403 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3404 ppc_mtctr (code, ppc_r0);
3406 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3407 ppc_neg (code, ppc_r11, ppc_r11);
3408 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3410 if (ins->flags & MONO_INST_INIT) {
3411 /* adjust the dest reg by -4 so we can use stwu */
3412 /* we actually adjust -8 because we let the loop
3415 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3416 ppc_li (code, ppc_r11, 0);
3417 zero_loop_start = code;
3418 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3419 zero_loop_jump = code;
3420 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3421 ppc_patch (zero_loop_jump, zero_loop_start);
3423 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3428 ppc_mr (code, ppc_r3, ins->sreg1);
3429 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3430 (gpointer)"mono_arch_throw_exception");
3431 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3432 ppc_lis (code, ppc_r0, 0);
3433 ppc_ori (code, ppc_r0, ppc_r0, 0);
3434 ppc_mtlr (code, ppc_r0);
3443 ppc_mr (code, ppc_r3, ins->sreg1);
3444 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3445 (gpointer)"mono_arch_rethrow_exception");
3446 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3447 ppc_lis (code, ppc_r0, 0);
3448 ppc_ori (code, ppc_r0, ppc_r0, 0);
3449 ppc_mtlr (code, ppc_r0);
3456 case OP_START_HANDLER: {
3457 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3458 ppc_mflr (code, ppc_r0);
3459 if (ppc_is_imm16 (spvar->inst_offset)) {
3460 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3462 ppc_load (code, ppc_r11, spvar->inst_offset);
3463 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3467 case OP_ENDFILTER: {
3468 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3469 if (ins->sreg1 != ppc_r3)
3470 ppc_mr (code, ppc_r3, ins->sreg1);
3471 if (ppc_is_imm16 (spvar->inst_offset)) {
3472 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3474 ppc_load (code, ppc_r11, spvar->inst_offset);
3475 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3477 ppc_mtlr (code, ppc_r0);
3481 case OP_ENDFINALLY: {
3482 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3483 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3484 ppc_mtlr (code, ppc_r0);
3488 case OP_CALL_HANDLER:
3489 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3493 ins->inst_c0 = code - cfg->native_code;
3496 if (ins->flags & MONO_INST_BRLABEL) {
3497 /*if (ins->inst_i0->inst_c0) {
3499 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3501 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3505 /*if (ins->inst_target_bb->native_offset) {
3507 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3509 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3515 ppc_mtctr (code, ins->sreg1);
3516 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3520 ppc_li (code, ins->dreg, 0);
3521 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3522 ppc_li (code, ins->dreg, 1);
3528 ppc_li (code, ins->dreg, 1);
3529 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3530 ppc_li (code, ins->dreg, 0);
3536 ppc_li (code, ins->dreg, 1);
3537 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3538 ppc_li (code, ins->dreg, 0);
3540 case OP_COND_EXC_EQ:
3541 case OP_COND_EXC_NE_UN:
3542 case OP_COND_EXC_LT:
3543 case OP_COND_EXC_LT_UN:
3544 case OP_COND_EXC_GT:
3545 case OP_COND_EXC_GT_UN:
3546 case OP_COND_EXC_GE:
3547 case OP_COND_EXC_GE_UN:
3548 case OP_COND_EXC_LE:
3549 case OP_COND_EXC_LE_UN:
3550 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3552 case OP_COND_EXC_IEQ:
3553 case OP_COND_EXC_INE_UN:
3554 case OP_COND_EXC_ILT:
3555 case OP_COND_EXC_ILT_UN:
3556 case OP_COND_EXC_IGT:
3557 case OP_COND_EXC_IGT_UN:
3558 case OP_COND_EXC_IGE:
3559 case OP_COND_EXC_IGE_UN:
3560 case OP_COND_EXC_ILE:
3561 case OP_COND_EXC_ILE_UN:
3562 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3565 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3567 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3568 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3569 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3571 case OP_COND_EXC_OV:
3572 /*ppc_mcrxr (code, 0);
3573 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3575 case OP_COND_EXC_NC:
3576 case OP_COND_EXC_NO:
3577 g_assert_not_reached ();
3589 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3592 /* floating point opcodes */
3595 g_assert_not_reached ();
3596 case OP_STORER8_MEMBASE_REG:
3597 if (ppc_is_imm16 (ins->inst_offset)) {
3598 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3600 ppc_load (code, ppc_r0, ins->inst_offset);
3601 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3604 case OP_LOADR8_MEMBASE:
3605 if (ppc_is_imm16 (ins->inst_offset)) {
3606 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3608 ppc_load (code, ppc_r0, ins->inst_offset);
3609 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3612 case OP_STORER4_MEMBASE_REG:
3613 ppc_frsp (code, ins->sreg1, ins->sreg1);
3614 if (ppc_is_imm16 (ins->inst_offset)) {
3615 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3617 ppc_load (code, ppc_r0, ins->inst_offset);
3618 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3621 case OP_LOADR4_MEMBASE:
3622 if (ppc_is_imm16 (ins->inst_offset)) {
3623 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3625 ppc_load (code, ppc_r0, ins->inst_offset);
3626 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3629 case OP_LOADR4_MEMINDEX:
3630 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3632 case OP_LOADR8_MEMINDEX:
3633 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3635 case OP_STORER4_MEMINDEX:
3636 ppc_frsp (code, ins->sreg1, ins->sreg1);
3637 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3639 case OP_STORER8_MEMINDEX:
3640 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3643 case CEE_CONV_R4: /* FIXME: change precision */
3645 g_assert_not_reached ();
3646 case OP_FCONV_TO_I1:
3647 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3649 case OP_FCONV_TO_U1:
3650 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3652 case OP_FCONV_TO_I2:
3653 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3655 case OP_FCONV_TO_U2:
3656 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3658 case OP_FCONV_TO_I4:
3660 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3662 case OP_FCONV_TO_U4:
3664 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3666 case OP_FCONV_TO_I8:
3667 case OP_FCONV_TO_U8:
3668 g_assert_not_reached ();
3669 /* Implemented as helper calls */
3671 case OP_LCONV_TO_R_UN:
3672 g_assert_not_reached ();
3673 /* Implemented as helper calls */
3675 case OP_LCONV_TO_OVF_I4_2:
3676 case OP_LCONV_TO_OVF_I: {
3677 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3678 // Check if its negative
3679 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3680 negative_branch = code;
3681 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3682 // Its positive msword == 0
3683 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3684 msword_positive_branch = code;
3685 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3687 ovf_ex_target = code;
3688 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3690 ppc_patch (negative_branch, code);
3691 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3692 msword_negative_branch = code;
3693 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3694 ppc_patch (msword_negative_branch, ovf_ex_target);
3696 ppc_patch (msword_positive_branch, code);
3697 if (ins->dreg != ins->sreg1)
3698 ppc_mr (code, ins->dreg, ins->sreg1);
3702 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3705 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3708 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3711 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3714 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3717 ppc_fneg (code, ins->dreg, ins->sreg1);
3721 g_assert_not_reached ();
3724 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3727 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3728 ppc_li (code, ins->dreg, 0);
3729 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3730 ppc_li (code, ins->dreg, 1);
3733 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3734 ppc_li (code, ins->dreg, 1);
3735 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3736 ppc_li (code, ins->dreg, 0);
3739 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3740 ppc_li (code, ins->dreg, 1);
3741 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3742 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3743 ppc_li (code, ins->dreg, 0);
3746 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3747 ppc_li (code, ins->dreg, 1);
3748 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3749 ppc_li (code, ins->dreg, 0);
3752 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3753 ppc_li (code, ins->dreg, 1);
3754 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3755 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3756 ppc_li (code, ins->dreg, 0);
3759 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3762 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3765 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3766 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3769 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3770 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3773 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3774 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3777 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3778 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3781 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3782 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3785 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3788 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3789 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3792 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3795 g_assert_not_reached ();
3796 case OP_CHECK_FINITE: {
3797 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3798 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3799 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3800 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3803 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3804 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3808 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3809 g_assert_not_reached ();
3812 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3813 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3814 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3815 g_assert_not_reached ();
3821 last_offset = offset;
3824 cfg->code_len = code - cfg->native_code;
3828 mono_arch_register_lowlevel_calls (void)
3832 #define patch_lis_ori(ip,val) do {\
3833 guint16 *__lis_ori = (guint16*)(ip); \
3834 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3835 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3839 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3841 MonoJumpInfo *patch_info;
3843 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3844 unsigned char *ip = patch_info->ip.i + code;
3845 unsigned char *target;
3847 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3849 switch (patch_info->type) {
3850 case MONO_PATCH_INFO_IP:
3851 patch_lis_ori (ip, ip);
3853 case MONO_PATCH_INFO_METHOD_REL:
3854 g_assert_not_reached ();
3855 *((gpointer *)(ip)) = code + patch_info->data.offset;
3857 case MONO_PATCH_INFO_SWITCH: {
3858 gpointer *table = (gpointer *)patch_info->data.table->table;
3861 patch_lis_ori (ip, table);
3863 for (i = 0; i < patch_info->data.table->table_size; i++) {
3864 table [i] = (int)patch_info->data.table->table [i] + code;
3866 /* we put into the table the absolute address, no need for ppc_patch in this case */
3869 case MONO_PATCH_INFO_METHODCONST:
3870 case MONO_PATCH_INFO_CLASS:
3871 case MONO_PATCH_INFO_IMAGE:
3872 case MONO_PATCH_INFO_FIELD:
3873 case MONO_PATCH_INFO_VTABLE:
3874 case MONO_PATCH_INFO_IID:
3875 case MONO_PATCH_INFO_SFLDA:
3876 case MONO_PATCH_INFO_LDSTR:
3877 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3878 case MONO_PATCH_INFO_LDTOKEN:
3879 /* from OP_AOTCONST : lis + ori */
3880 patch_lis_ori (ip, target);
3882 case MONO_PATCH_INFO_R4:
3883 case MONO_PATCH_INFO_R8:
3884 g_assert_not_reached ();
3885 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3887 case MONO_PATCH_INFO_EXC_NAME:
3888 g_assert_not_reached ();
3889 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3891 case MONO_PATCH_INFO_NONE:
3892 case MONO_PATCH_INFO_BB_OVF:
3893 case MONO_PATCH_INFO_EXC_OVF:
3894 /* everything is dealt with at epilog output time */
3899 ppc_patch (ip, target);
3904 * Stack frame layout:
3906 * ------------------- sp
3907 * MonoLMF structure or saved registers
3908 * -------------------
3910 * -------------------
3912 * -------------------
3913 * optional 8 bytes for tracing
3914 * -------------------
3915 * param area size is cfg->param_area
3916 * -------------------
3917 * linkage area size is PPC_STACK_PARAM_OFFSET
3918 * ------------------- sp
3922 mono_arch_emit_prolog (MonoCompile *cfg)
3924 MonoMethod *method = cfg->method;
3926 MonoMethodSignature *sig;
3928 int alloc_size, pos, max_offset, i;
3933 int tailcall_struct_index;
3935 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3938 sig = mono_method_signature (method);
3939 cfg->code_size = 256 + sig->param_count * 20;
3940 code = cfg->native_code = g_malloc (cfg->code_size);
3942 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3943 ppc_mflr (code, ppc_r0);
3944 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3947 alloc_size = cfg->stack_offset;
3950 if (!method->save_lmf) {
3951 /*for (i = 31; i >= 14; --i) {
3952 if (cfg->used_float_regs & (1 << i)) {
3953 pos += sizeof (gdouble);
3954 ppc_stfd (code, i, -pos, ppc_sp);
3957 for (i = 31; i >= 13; --i) {
3958 if (cfg->used_int_regs & (1 << i)) {
3959 pos += sizeof (gulong);
3960 ppc_stw (code, i, -pos, ppc_sp);
3965 pos += sizeof (MonoLMF);
3967 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3968 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3969 for (i = 14; i < 32; i++) {
3970 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3974 // align to PPC_STACK_ALIGNMENT bytes
3975 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3976 alloc_size += PPC_STACK_ALIGNMENT - 1;
3977 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3980 cfg->stack_usage = alloc_size;
3981 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3983 if (ppc_is_imm16 (-alloc_size)) {
3984 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3986 ppc_load (code, ppc_r11, -alloc_size);
3987 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3990 if (cfg->frame_reg != ppc_sp)
3991 ppc_mr (code, cfg->frame_reg, ppc_sp);
3993 /* store runtime generic context */
3994 if (cfg->rgctx_var) {
3995 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3996 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3998 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4001 /* compute max_offset in order to use short forward jumps
4002 * we always do it on ppc because the immediate displacement
4003 * for jumps is too small
4006 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4008 bb->max_offset = max_offset;
4010 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4013 MONO_BB_FOR_EACH_INS (bb, ins)
4014 max_offset += ins_native_length (cfg, ins);
4017 /* load arguments allocated to register from the stack */
4020 cinfo = calculate_sizes (sig, sig->pinvoke);
4022 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4023 ArgInfo *ainfo = &cinfo->ret;
4026 inst = cfg->vret_addr;
4031 if (ppc_is_imm16 (inst->inst_offset)) {
4032 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4034 ppc_load (code, ppc_r11, inst->inst_offset);
4035 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4039 tailcall_struct_index = 0;
4040 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4041 ArgInfo *ainfo = cinfo->args + i;
4042 inst = cfg->args [pos];
4044 if (cfg->verbose_level > 2)
4045 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4046 if (inst->opcode == OP_REGVAR) {
4047 if (ainfo->regtype == RegTypeGeneral)
4048 ppc_mr (code, inst->dreg, ainfo->reg);
4049 else if (ainfo->regtype == RegTypeFP)
4050 ppc_fmr (code, inst->dreg, ainfo->reg);
4051 else if (ainfo->regtype == RegTypeBase) {
4052 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4053 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
4055 g_assert_not_reached ();
4057 if (cfg->verbose_level > 2)
4058 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4060 /* the argument should be put on the stack: FIXME handle size != word */
4061 if (ainfo->regtype == RegTypeGeneral) {
4062 switch (ainfo->size) {
4064 if (ppc_is_imm16 (inst->inst_offset)) {
4065 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4067 ppc_load (code, ppc_r11, inst->inst_offset);
4068 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4072 if (ppc_is_imm16 (inst->inst_offset)) {
4073 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4075 ppc_load (code, ppc_r11, inst->inst_offset);
4076 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4080 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4081 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4082 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4084 ppc_load (code, ppc_r11, inst->inst_offset);
4085 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4086 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4087 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4091 if (ppc_is_imm16 (inst->inst_offset)) {
4092 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4094 ppc_load (code, ppc_r11, inst->inst_offset);
4095 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4099 } else if (ainfo->regtype == RegTypeBase) {
4100 /* load the previous stack pointer in r11 */
4101 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4102 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4103 switch (ainfo->size) {
4105 if (ppc_is_imm16 (inst->inst_offset)) {
4106 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4108 ppc_load (code, ppc_r11, inst->inst_offset);
4109 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4113 if (ppc_is_imm16 (inst->inst_offset)) {
4114 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4116 ppc_load (code, ppc_r11, inst->inst_offset);
4117 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4121 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4122 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4123 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4124 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4127 g_assert_not_reached ();
4131 if (ppc_is_imm16 (inst->inst_offset)) {
4132 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4134 ppc_load (code, ppc_r11, inst->inst_offset);
4135 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4139 } else if (ainfo->regtype == RegTypeFP) {
4140 g_assert (ppc_is_imm16 (inst->inst_offset));
4141 if (ainfo->size == 8)
4142 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4143 else if (ainfo->size == 4)
4144 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4146 g_assert_not_reached ();
4147 } else if (ainfo->regtype == RegTypeStructByVal) {
4148 int doffset = inst->inst_offset;
4152 g_assert (ppc_is_imm16 (inst->inst_offset));
4153 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4154 /* FIXME: what if there is no class? */
4155 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4156 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4157 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4160 * Darwin handles 1 and 2 byte
4161 * structs specially by
4162 * loading h/b into the arg
4163 * register. Only done for
4167 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4169 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4172 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4173 soffset += sizeof (gpointer);
4174 doffset += sizeof (gpointer);
4176 if (ainfo->vtsize) {
4177 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4178 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4179 if ((size & 3) != 0) {
4180 code = emit_memcpy (code, size - soffset,
4181 inst->inst_basereg, doffset,
4182 ppc_r11, ainfo->offset + soffset);
4184 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4185 inst->inst_basereg, doffset,
4186 ppc_r11, ainfo->offset + soffset);
4189 } else if (ainfo->regtype == RegTypeStructByAddr) {
4190 /* if it was originally a RegTypeBase */
4191 if (ainfo->offset) {
4192 /* load the previous stack pointer in r11 */
4193 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4194 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4196 ppc_mr (code, ppc_r11, ainfo->reg);
4199 if (cfg->tailcall_valuetype_addrs) {
4200 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4202 g_assert (ppc_is_imm16 (addr->inst_offset));
4203 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4205 tailcall_struct_index++;
4208 g_assert (ppc_is_imm16 (inst->inst_offset));
4209 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4210 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4212 g_assert_not_reached ();
4217 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4218 ppc_load (code, ppc_r3, cfg->domain);
4219 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4220 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4221 ppc_lis (code, ppc_r0, 0);
4222 ppc_ori (code, ppc_r0, ppc_r0, 0);
4223 ppc_mtlr (code, ppc_r0);
4230 if (method->save_lmf) {
4231 if (lmf_pthread_key != -1) {
4232 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4233 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4234 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4236 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4237 (gpointer)"mono_get_lmf_addr");
4238 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4239 ppc_lis (code, ppc_r0, 0);
4240 ppc_ori (code, ppc_r0, ppc_r0, 0);
4241 ppc_mtlr (code, ppc_r0);
4247 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4248 /* lmf_offset is the offset from the previous stack pointer,
4249 * alloc_size is the total stack space allocated, so the offset
4250 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4251 * The pointer to the struct is put in ppc_r11 (new_lmf).
4252 * The callee-saved registers are already in the MonoLMF structure
4254 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4255 /* ppc_r3 is the result from mono_get_lmf_addr () */
4256 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4257 /* new_lmf->previous_lmf = *lmf_addr */
4258 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4259 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4260 /* *(lmf_addr) = r11 */
4261 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4262 /* save method info */
4263 ppc_load (code, ppc_r0, method);
4264 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4265 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4266 /* save the current IP */
4267 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4268 ppc_load (code, ppc_r0, 0x01010101);
4269 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4273 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4275 cfg->code_len = code - cfg->native_code;
4276 g_assert (cfg->code_len < cfg->code_size);
4283 mono_arch_emit_epilog (MonoCompile *cfg)
4285 MonoMethod *method = cfg->method;
4287 int max_epilog_size = 16 + 20*4;
4290 if (cfg->method->save_lmf)
4291 max_epilog_size += 128;
4293 if (mono_jit_trace_calls != NULL)
4294 max_epilog_size += 50;
4296 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4297 max_epilog_size += 50;
4299 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4300 cfg->code_size *= 2;
4301 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4302 mono_jit_stats.code_reallocs++;
4306 * Keep in sync with OP_JMP
4308 code = cfg->native_code + cfg->code_len;
4310 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4311 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4315 if (method->save_lmf) {
4317 pos += sizeof (MonoLMF);
4319 /* save the frame reg in r8 */
4320 ppc_mr (code, ppc_r8, cfg->frame_reg);
4321 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4322 /* r5 = previous_lmf */
4323 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4325 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4326 /* *(lmf_addr) = previous_lmf */
4327 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4328 /* FIXME: speedup: there is no actual need to restore the registers if
4329 * we didn't actually change them (idea from Zoltan).
4332 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4334 /*for (i = 14; i < 32; i++) {
4335 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4337 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4338 /* use the saved copy of the frame reg in r8 */
4339 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4340 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4341 ppc_mtlr (code, ppc_r0);
4343 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4345 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4346 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4347 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4349 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4350 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4352 ppc_mtlr (code, ppc_r0);
4354 if (ppc_is_imm16 (cfg->stack_usage)) {
4355 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4357 ppc_load (code, ppc_r11, cfg->stack_usage);
4358 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4361 /*for (i = 31; i >= 14; --i) {
4362 if (cfg->used_float_regs & (1 << i)) {
4363 pos += sizeof (double);
4364 ppc_lfd (code, i, -pos, ppc_sp);
4367 for (i = 31; i >= 13; --i) {
4368 if (cfg->used_int_regs & (1 << i)) {
4369 pos += sizeof (gulong);
4370 ppc_lwz (code, i, -pos, ppc_sp);
4376 cfg->code_len = code - cfg->native_code;
4378 g_assert (cfg->code_len < cfg->code_size);
4382 /* remove once throw_exception_by_name is eliminated */
4384 exception_id_by_name (const char *name)
4386 if (strcmp (name, "IndexOutOfRangeException") == 0)
4387 return MONO_EXC_INDEX_OUT_OF_RANGE;
4388 if (strcmp (name, "OverflowException") == 0)
4389 return MONO_EXC_OVERFLOW;
4390 if (strcmp (name, "ArithmeticException") == 0)
4391 return MONO_EXC_ARITHMETIC;
4392 if (strcmp (name, "DivideByZeroException") == 0)
4393 return MONO_EXC_DIVIDE_BY_ZERO;
4394 if (strcmp (name, "InvalidCastException") == 0)
4395 return MONO_EXC_INVALID_CAST;
4396 if (strcmp (name, "NullReferenceException") == 0)
4397 return MONO_EXC_NULL_REF;
4398 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4399 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4400 g_error ("Unknown intrinsic exception %s\n", name);
4405 mono_arch_emit_exceptions (MonoCompile *cfg)
4407 MonoJumpInfo *patch_info;
4410 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4411 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4412 int max_epilog_size = 50;
4414 /* count the number of exception infos */
4417 * make sure we have enough space for exceptions
4418 * 24 is the simulated call to throw_exception_by_name
4420 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4421 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4422 i = exception_id_by_name (patch_info->data.target);
4423 if (!exc_throw_found [i]) {
4424 max_epilog_size += 24;
4425 exc_throw_found [i] = TRUE;
4427 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4428 max_epilog_size += 12;
4429 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4430 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4431 i = exception_id_by_name (ovfj->data.exception);
4432 if (!exc_throw_found [i]) {
4433 max_epilog_size += 24;
4434 exc_throw_found [i] = TRUE;
4436 max_epilog_size += 8;
4440 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4441 cfg->code_size *= 2;
4442 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4443 mono_jit_stats.code_reallocs++;
4446 code = cfg->native_code + cfg->code_len;
4448 /* add code to raise exceptions */
4449 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4450 switch (patch_info->type) {
4451 case MONO_PATCH_INFO_BB_OVF: {
4452 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4453 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4454 /* patch the initial jump */
4455 ppc_patch (ip, code);
4456 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4458 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4459 /* jump back to the true target */
4461 ip = ovfj->data.bb->native_offset + cfg->native_code;
4462 ppc_patch (code - 4, ip);
4465 case MONO_PATCH_INFO_EXC_OVF: {
4466 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4467 MonoJumpInfo *newji;
4468 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4469 unsigned char *bcl = code;
4470 /* patch the initial jump: we arrived here with a call */
4471 ppc_patch (ip, code);
4472 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4474 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4475 /* patch the conditional jump to the right handler */
4476 /* make it processed next */
4477 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4478 newji->type = MONO_PATCH_INFO_EXC;
4479 newji->ip.i = bcl - cfg->native_code;
4480 newji->data.target = ovfj->data.exception;
4481 newji->next = patch_info->next;
4482 patch_info->next = newji;
4485 case MONO_PATCH_INFO_EXC: {
4486 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4487 i = exception_id_by_name (patch_info->data.target);
4488 if (exc_throw_pos [i]) {
4489 ppc_patch (ip, exc_throw_pos [i]);
4490 patch_info->type = MONO_PATCH_INFO_NONE;
4493 exc_throw_pos [i] = code;
4495 ppc_patch (ip, code);
4496 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4497 ppc_load (code, ppc_r3, patch_info->data.target);
4498 /* we got here from a conditional call, so the calling ip is set in lr already */
4499 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4500 patch_info->data.name = "mono_arch_throw_exception_by_name";
4501 patch_info->ip.i = code - cfg->native_code;
4502 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4503 ppc_lis (code, ppc_r0, 0);
4504 ppc_ori (code, ppc_r0, ppc_r0, 0);
4505 ppc_mtctr (code, ppc_r0);
4506 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4518 cfg->code_len = code - cfg->native_code;
4520 g_assert (cfg->code_len < cfg->code_size);
4525 try_offset_access (void *value, guint32 idx)
4527 register void* me __asm__ ("r2");
4528 void ***p = (void***)((char*)me + 284);
4529 int idx1 = idx / 32;
4530 int idx2 = idx % 32;
4533 if (value != p[idx1][idx2])
4539 setup_tls_access (void)
4542 guint32 *ins, *code;
4543 guint32 cmplwi_1023, li_0x48, blr_ins;
4544 if (tls_mode == TLS_MODE_FAILED)
4547 if (g_getenv ("MONO_NO_TLS")) {
4548 tls_mode = TLS_MODE_FAILED;
4552 if (tls_mode == TLS_MODE_DETECT) {
4553 ins = (guint32*)pthread_getspecific;
4554 /* uncond branch to the real method */
4555 if ((*ins >> 26) == 18) {
4557 val = (*ins & ~3) << 6;
4561 ins = (guint32*)val;
4563 ins = (guint32*) ((char*)ins + val);
4566 code = &cmplwi_1023;
4567 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4569 ppc_li (code, ppc_r4, 0x48);
4572 if (*ins == cmplwi_1023) {
4573 int found_lwz_284 = 0;
4574 for (ptk = 0; ptk < 20; ++ptk) {
4576 if (!*ins || *ins == blr_ins)
4578 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4583 if (!found_lwz_284) {
4584 tls_mode = TLS_MODE_FAILED;
4587 tls_mode = TLS_MODE_LTHREADS;
4588 } else if (*ins == li_0x48) {
4590 /* uncond branch to the real method */
4591 if ((*ins >> 26) == 18) {
4593 val = (*ins & ~3) << 6;
4597 ins = (guint32*)val;
4599 ins = (guint32*) ((char*)ins + val);
4601 code = (guint32*)&val;
4602 ppc_li (code, ppc_r0, 0x7FF2);
4603 if (ins [1] == val) {
4604 /* Darwin on G4, implement */
4605 tls_mode = TLS_MODE_FAILED;
4608 code = (guint32*)&val;
4609 ppc_mfspr (code, ppc_r3, 104);
4610 if (ins [1] != val) {
4611 tls_mode = TLS_MODE_FAILED;
4614 tls_mode = TLS_MODE_DARWIN_G5;
4617 tls_mode = TLS_MODE_FAILED;
4621 tls_mode = TLS_MODE_FAILED;
4625 if (monodomain_key == -1) {
4626 ptk = mono_domain_get_tls_key ();
4628 ptk = mono_pthread_key_for_tls (ptk);
4630 monodomain_key = ptk;
4634 if (lmf_pthread_key == -1) {
4635 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4637 /*g_print ("MonoLMF at: %d\n", ptk);*/
4638 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4639 init_tls_failed = 1;
4642 lmf_pthread_key = ptk;
4645 if (monothread_key == -1) {
4646 ptk = mono_thread_get_tls_key ();
4648 ptk = mono_pthread_key_for_tls (ptk);
4650 monothread_key = ptk;
4651 /*g_print ("thread inited: %d\n", ptk);*/
4654 /*g_print ("thread not inited yet %d\n", ptk);*/
4660 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4662 setup_tls_access ();
4666 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4671 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4673 int this_dreg = ppc_r3;
4678 /* add the this argument */
4679 if (this_reg != -1) {
4681 MONO_INST_NEW (cfg, this, OP_MOVE);
4682 this->type = this_type;
4683 this->sreg1 = this_reg;
4684 this->dreg = mono_regstate_next_int (cfg->rs);
4685 mono_bblock_add_inst (cfg->cbb, this);
4686 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4691 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4692 vtarg->type = STACK_MP;
4693 vtarg->sreg1 = vt_reg;
4694 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4695 mono_bblock_add_inst (cfg->cbb, vtarg);
4696 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4700 #ifdef MONO_ARCH_HAVE_IMT
4704 #define JUMP_IMM_SIZE 12
4705 #define JUMP_IMM32_SIZE 16
4706 #define ENABLE_WRONG_METHOD_CHECK 0
4709 * LOCKING: called with the domain lock held
4712 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4713 gpointer fail_tramp)
4717 guint8 *code, *start;
4719 for (i = 0; i < count; ++i) {
4720 MonoIMTCheckItem *item = imt_entries [i];
4721 if (item->is_equals) {
4722 if (item->check_target_idx) {
4723 if (!item->compare_done)
4724 item->chunk_size += CMP_SIZE;
4726 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4728 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4731 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4733 item->chunk_size += JUMP_IMM_SIZE;
4734 #if ENABLE_WRONG_METHOD_CHECK
4735 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4740 item->chunk_size += CMP_SIZE + BR_SIZE;
4741 imt_entries [item->check_target_idx]->compare_done = TRUE;
4743 size += item->chunk_size;
4746 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4748 /* the initial load of the vtable address */
4750 code = mono_code_manager_reserve (domain->code_mp, size);
4754 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4755 for (i = 0; i < count; ++i) {
4756 MonoIMTCheckItem *item = imt_entries [i];
4757 item->code_target = code;
4758 if (item->is_equals) {
4759 if (item->check_target_idx) {
4760 if (!item->compare_done) {
4761 ppc_load (code, ppc_r0, (guint32)item->key);
4762 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4764 item->jmp_code = code;
4765 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4767 ppc_load (code, ppc_r0, item->value.target_code);
4769 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4770 ppc_mtctr (code, ppc_r0);
4771 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4774 ppc_load (code, ppc_r0, (guint32)item->key);
4775 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4776 item->jmp_code = code;
4777 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4778 ppc_load (code, ppc_r0, item->value.target_code);
4779 ppc_mtctr (code, ppc_r0);
4780 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4781 ppc_patch (item->jmp_code, code);
4782 ppc_load (code, ppc_r0, fail_tramp);
4783 ppc_mtctr (code, ppc_r0);
4784 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4785 item->jmp_code = NULL;
4787 /* enable the commented code to assert on wrong method */
4788 #if ENABLE_WRONG_METHOD_CHECK
4789 ppc_load (code, ppc_r0, (guint32)item->key);
4790 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4791 item->jmp_code = code;
4792 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4794 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4795 ppc_mtctr (code, ppc_r0);
4796 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4797 #if ENABLE_WRONG_METHOD_CHECK
4798 ppc_patch (item->jmp_code, code);
4800 item->jmp_code = NULL;
4805 ppc_load (code, ppc_r0, (guint32)item->key);
4806 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4807 item->jmp_code = code;
4808 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4811 /* patch the branches to get to the target items */
4812 for (i = 0; i < count; ++i) {
4813 MonoIMTCheckItem *item = imt_entries [i];
4814 if (item->jmp_code) {
4815 if (item->check_target_idx) {
4816 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4822 mono_stats.imt_thunks_size += code - start;
4823 g_assert (code - start <= size);
4824 mono_arch_flush_icache (start, size);
4829 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4831 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4835 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4837 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4842 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4844 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4848 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4850 MonoInst *ins = NULL;
4852 /*if (cmethod->klass == mono_defaults.math_class) {
4853 if (strcmp (cmethod->name, "Sqrt") == 0) {
4854 MONO_INST_NEW (cfg, ins, OP_SQRT);
4855 ins->inst_i0 = args [0];
4862 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4869 mono_arch_print_tree (MonoInst *tree, int arity)
4874 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4878 setup_tls_access ();
4879 if (monodomain_key == -1)
4882 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4883 ins->inst_offset = monodomain_key;
4888 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4892 setup_tls_access ();
4893 if (monothread_key == -1)
4896 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4897 ins->inst_offset = monothread_key;
4902 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4904 g_assert (reg >= ppc_r13);
4906 return (gpointer)ctx->regs [reg - ppc_r13];