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>
24 #define FORCE_INDIR_CALL 1
35 /* This mutex protects architecture specific caches */
36 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
37 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
38 static CRITICAL_SECTION mini_arch_mutex;
40 int mono_exc_esp_offset = 0;
41 static int tls_mode = TLS_MODE_DETECT;
42 static int lmf_pthread_key = -1;
43 static int monothread_key = -1;
44 static int monodomain_key = -1;
47 offsets_from_pthread_key (guint32 key, int *offset2)
51 *offset2 = idx2 * sizeof (gpointer);
52 return 284 + idx1 * sizeof (gpointer);
55 #define emit_linuxthreads_tls(code,dreg,key) do {\
57 off1 = offsets_from_pthread_key ((key), &off2); \
58 ppc_lwz ((code), (dreg), off1, ppc_r2); \
59 ppc_lwz ((code), (dreg), off2, (dreg)); \
62 #define emit_darwing5_tls(code,dreg,key) do {\
63 int off1 = 0x48 + key * sizeof (gpointer); \
64 ppc_mfspr ((code), (dreg), 104); \
65 ppc_lwz ((code), (dreg), off1, (dreg)); \
68 /* FIXME: ensure the sc call preserves all but r3 */
69 #define emit_darwing4_tls(code,dreg,key) do {\
70 int off1 = 0x48 + key * sizeof (gpointer); \
71 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
72 ppc_li ((code), ppc_r0, 0x7FF2); \
74 ppc_lwz ((code), (dreg), off1, ppc_r3); \
75 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
78 #define emit_tls_access(code,dreg,key) do { \
80 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
81 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
82 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
83 default: g_assert_not_reached (); \
87 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
90 inst->type = STACK_R8; \
92 inst->inst_p0 = (void*)(addr); \
93 mono_bblock_add_inst (cfg->cbb, inst); \
97 mono_arch_regname (int reg) {
98 static const char rnames[][4] = {
99 "r0", "sp", "r2", "r3", "r4",
100 "r5", "r6", "r7", "r8", "r9",
101 "r10", "r11", "r12", "r13", "r14",
102 "r15", "r16", "r17", "r18", "r19",
103 "r20", "r21", "r22", "r23", "r24",
104 "r25", "r26", "r27", "r28", "r29",
107 if (reg >= 0 && reg < 32)
113 mono_arch_fregname (int reg) {
114 static const char rnames[][4] = {
115 "f0", "f1", "f2", "f3", "f4",
116 "f5", "f6", "f7", "f8", "f9",
117 "f10", "f11", "f12", "f13", "f14",
118 "f15", "f16", "f17", "f18", "f19",
119 "f20", "f21", "f22", "f23", "f24",
120 "f25", "f26", "f27", "f28", "f29",
123 if (reg >= 0 && reg < 32)
128 /* this function overwrites r0, r11, r12 */
130 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
132 /* unrolled, use the counter in big */
133 if (size > sizeof (gpointer) * 5) {
134 int shifted = size >> 2;
135 guint8 *copy_loop_start, *copy_loop_jump;
137 ppc_load (code, ppc_r0, shifted);
138 ppc_mtctr (code, ppc_r0);
139 g_assert (sreg == ppc_r11);
140 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
141 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
142 copy_loop_start = code;
143 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
144 ppc_stwu (code, ppc_r0, 4, ppc_r12);
145 copy_loop_jump = code;
146 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
147 ppc_patch (copy_loop_jump, copy_loop_start);
149 doffset = soffset = 0;
153 ppc_lwz (code, ppc_r0, soffset, sreg);
154 ppc_stw (code, ppc_r0, doffset, dreg);
160 ppc_lhz (code, ppc_r0, soffset, sreg);
161 ppc_sth (code, ppc_r0, doffset, dreg);
167 ppc_lbz (code, ppc_r0, soffset, sreg);
168 ppc_stb (code, ppc_r0, doffset, dreg);
177 * mono_arch_get_argument_info:
178 * @csig: a method signature
179 * @param_count: the number of parameters to consider
180 * @arg_info: an array to store the result infos
182 * Gathers information on parameters such as size, alignment and
183 * padding. arg_info should be large enought to hold param_count + 1 entries.
185 * Returns the size of the activation frame.
188 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
190 int k, frame_size = 0;
191 int size, align, pad;
194 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
195 frame_size += sizeof (gpointer);
199 arg_info [0].offset = offset;
202 frame_size += sizeof (gpointer);
206 arg_info [0].size = frame_size;
208 for (k = 0; k < param_count; k++) {
211 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
213 size = mini_type_stack_size (NULL, csig->params [k], &align);
215 /* ignore alignment for now */
218 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
219 arg_info [k].pad = pad;
221 arg_info [k + 1].pad = 0;
222 arg_info [k + 1].size = size;
224 arg_info [k + 1].offset = offset;
228 align = MONO_ARCH_FRAME_ALIGNMENT;
229 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
230 arg_info [k].pad = pad;
236 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
240 guint32* code = (guint32*)code_ptr;
244 /* This is the 'blrl' instruction */
247 /* Sanity check: instruction must be 'blrl' */
248 if (*code != 0x4e800021)
251 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
252 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
256 /* OK, we're now at the 'blrl' instruction. Now walk backwards
257 till we get to a 'mtlr rA' */
259 if((*code & 0x7c0803a6) == 0x7c0803a6) {
261 /* Here we are: we reached the 'mtlr rA'.
262 Extract the register from the instruction */
263 reg = (*code & 0x03e00000) >> 21;
265 /* ok, this is a lwz reg, offset (vtreg)
266 * it is emitted with:
267 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
269 soff = (*code & 0xffff);
271 reg = (*code >> 16) & 0x1f;
272 g_assert (reg != ppc_r1);
273 /*g_print ("patching reg is %d\n", reg);*/
275 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
276 /* saved in the MonoLMF structure */
277 o = (gpointer)lmf->iregs [reg - 13];
284 *displacement = offset;
289 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
293 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
296 return (gpointer*)((char*)vt + displacement);
299 #define MAX_ARCH_DELEGATE_PARAMS 7
302 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
304 guint8 *code, *start;
306 /* FIXME: Support more cases */
307 if (MONO_TYPE_ISSTRUCT (sig->ret))
311 static guint8* cached = NULL;
312 mono_mini_arch_lock ();
314 mono_mini_arch_unlock ();
318 start = code = mono_global_codeman_reserve (16);
320 /* Replace the this argument with the target */
321 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
322 ppc_mtctr (code, ppc_r0);
323 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
324 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
326 g_assert ((code - start) <= 16);
328 mono_arch_flush_icache (start, 16);
330 mono_mini_arch_unlock ();
333 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
336 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
338 for (i = 0; i < sig->param_count; ++i)
339 if (!mono_is_regsize_var (sig->params [i]))
342 mono_mini_arch_lock ();
343 code = cache [sig->param_count];
345 mono_mini_arch_unlock ();
349 size = 12 + sig->param_count * 4;
350 start = code = mono_global_codeman_reserve (size);
352 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
353 ppc_mtctr (code, ppc_r0);
354 /* slide down the arguments */
355 for (i = 0; i < sig->param_count; ++i) {
356 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
358 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
360 g_assert ((code - start) <= size);
362 mono_arch_flush_icache (start, size);
363 cache [sig->param_count] = start;
364 mono_mini_arch_unlock ();
371 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
373 /* FIXME: handle returning a struct */
374 if (MONO_TYPE_ISSTRUCT (sig->ret))
375 return (gpointer)regs [ppc_r4];
376 return (gpointer)regs [ppc_r3];
380 * Initialize the cpu to execute managed code.
383 mono_arch_cpu_init (void)
388 * Initialize architecture specific code.
391 mono_arch_init (void)
393 InitializeCriticalSection (&mini_arch_mutex);
397 * Cleanup architecture specific code.
400 mono_arch_cleanup (void)
402 DeleteCriticalSection (&mini_arch_mutex);
406 * This function returns the optimizations supported on this cpu.
409 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
413 /* no ppc-specific optimizations yet */
419 is_regsize_var (MonoType *t) {
422 t = mini_type_get_underlying_type (NULL, t);
429 case MONO_TYPE_FNPTR:
431 case MONO_TYPE_OBJECT:
432 case MONO_TYPE_STRING:
433 case MONO_TYPE_CLASS:
434 case MONO_TYPE_SZARRAY:
435 case MONO_TYPE_ARRAY:
437 case MONO_TYPE_GENERICINST:
438 if (!mono_type_generic_inst_is_valuetype (t))
441 case MONO_TYPE_VALUETYPE:
448 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
453 for (i = 0; i < cfg->num_varinfo; i++) {
454 MonoInst *ins = cfg->varinfo [i];
455 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
458 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
461 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
464 /* we can only allocate 32 bit values */
465 if (is_regsize_var (ins->inst_vtype)) {
466 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
467 g_assert (i == vmv->idx);
468 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
476 mono_arch_get_global_int_regs (MonoCompile *cfg)
480 if (cfg->frame_reg != ppc_sp)
482 /* ppc_r13 is used by the system on PPC EABI */
483 for (i = 14; i < top; ++i)
484 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
490 * mono_arch_regalloc_cost:
492 * Return the cost, in number of memory references, of the action of
493 * allocating the variable VMV into a register during global register
497 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
509 mono_arch_flush_icache (guint8 *code, gint size)
512 guint8 *endp, *start;
513 static int cachelinesize = 0;
514 static int cachelineinc = 16;
516 if (!cachelinesize) {
521 mib [1] = HW_CACHELINE;
522 len = sizeof (cachelinesize);
523 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
527 cachelineinc = cachelinesize;
528 /*g_print ("setting cl size to %d\n", cachelinesize);*/
530 #elif defined(__linux__)
531 /* sadly this will work only with 2.6 kernels... */
532 FILE* f = fopen ("/proc/self/auxv", "rb");
535 while (fread (&vec, sizeof (vec), 1, f) == 1) {
536 if (vec.type == 19) {
537 cachelinesize = vec.value;
545 #elif defined(G_COMPILER_CODEWARRIOR)
549 #warning Need a way to get cache line size
555 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
556 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
557 #if defined(G_COMPILER_CODEWARRIOR)
559 for (p = start; p < endp; p += cachelineinc) {
563 for (p = start; p < endp; p += cachelineinc) {
569 for (p = start; p < endp; p += cachelineinc) {
581 for (p = start; p < endp; p += cachelineinc) {
582 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
585 for (p = start; p < endp; p += cachelineinc) {
586 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
591 for (p = start; p < endp; p += cachelineinc) {
592 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
600 mono_arch_flush_register_windows (void)
605 #define ALWAYS_ON_STACK(s) s
606 #define FP_ALSO_IN_REG(s) s
608 #define ALWAYS_ON_STACK(s)
609 #define FP_ALSO_IN_REG(s)
610 #define ALIGN_DOUBLES
623 guint32 vtsize; /* in param area */
625 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
626 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
641 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
644 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
645 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
646 ainfo->reg = ppc_sp; /* in the caller */
647 ainfo->regtype = RegTypeBase;
650 ALWAYS_ON_STACK (*stack_size += 4);
654 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
656 //*stack_size += (*stack_size % 8);
658 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
659 ainfo->reg = ppc_sp; /* in the caller */
660 ainfo->regtype = RegTypeBase;
667 ALWAYS_ON_STACK (*stack_size += 8);
677 has_only_a_r48_field (MonoClass *klass)
681 gboolean have_field = FALSE;
683 while ((f = mono_class_get_fields (klass, &iter))) {
684 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
687 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
698 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
701 int n = sig->hasthis + sig->param_count;
703 guint32 stack_size = 0;
704 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
706 fr = PPC_FIRST_FPARG_REG;
707 gr = PPC_FIRST_ARG_REG;
709 /* FIXME: handle returning a struct */
710 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
711 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
712 cinfo->struct_ret = PPC_FIRST_ARG_REG;
717 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
720 DEBUG(printf("params: %d\n", sig->param_count));
721 for (i = 0; i < sig->param_count; ++i) {
722 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
723 /* Prevent implicit arguments and sig_cookie from
724 being passed in registers */
725 gr = PPC_LAST_ARG_REG + 1;
726 /* FIXME: don't we have to set fr, too? */
727 /* Emit the signature cookie just before the implicit arguments */
728 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
730 DEBUG(printf("param %d: ", i));
731 if (sig->params [i]->byref) {
732 DEBUG(printf("byref\n"));
733 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
737 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
738 switch (simpletype) {
739 case MONO_TYPE_BOOLEAN:
742 cinfo->args [n].size = 1;
743 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
749 cinfo->args [n].size = 2;
750 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
755 cinfo->args [n].size = 4;
756 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
762 case MONO_TYPE_FNPTR:
763 case MONO_TYPE_CLASS:
764 case MONO_TYPE_OBJECT:
765 case MONO_TYPE_STRING:
766 case MONO_TYPE_SZARRAY:
767 case MONO_TYPE_ARRAY:
768 cinfo->args [n].size = sizeof (gpointer);
769 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
772 case MONO_TYPE_GENERICINST:
773 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
774 cinfo->args [n].size = sizeof (gpointer);
775 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
780 case MONO_TYPE_VALUETYPE: {
783 klass = mono_class_from_mono_type (sig->params [i]);
785 size = mono_class_native_size (klass, NULL);
787 size = mono_class_value_size (klass, NULL);
789 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
790 cinfo->args [n].size = size;
792 /* It was 7, now it is 8 in LinuxPPC */
793 if (fr <= PPC_LAST_FPARG_REG) {
794 cinfo->args [n].regtype = RegTypeFP;
795 cinfo->args [n].reg = fr;
797 FP_ALSO_IN_REG (gr ++);
799 FP_ALSO_IN_REG (gr ++);
800 ALWAYS_ON_STACK (stack_size += size);
802 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
803 cinfo->args [n].regtype = RegTypeBase;
804 cinfo->args [n].reg = ppc_sp; /* in the caller*/
811 DEBUG(printf ("load %d bytes struct\n",
812 mono_class_native_size (sig->params [i]->data.klass, NULL)));
813 #if PPC_PASS_STRUCTS_BY_VALUE
815 int align_size = size;
817 int rest = PPC_LAST_ARG_REG - gr + 1;
819 align_size += (sizeof (gpointer) - 1);
820 align_size &= ~(sizeof (gpointer) - 1);
821 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
822 n_in_regs = rest >= nwords? nwords: rest;
823 cinfo->args [n].regtype = RegTypeStructByVal;
824 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
825 cinfo->args [n].size = 0;
826 cinfo->args [n].vtsize = nwords;
828 cinfo->args [n].size = n_in_regs;
829 cinfo->args [n].vtsize = nwords - n_in_regs;
830 cinfo->args [n].reg = gr;
833 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
834 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
835 stack_size += nwords * sizeof (gpointer);
838 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
839 cinfo->args [n].regtype = RegTypeStructByAddr;
840 cinfo->args [n].vtsize = size;
845 case MONO_TYPE_TYPEDBYREF: {
846 int size = sizeof (MonoTypedRef);
847 /* keep in sync or merge with the valuetype case */
848 #if PPC_PASS_STRUCTS_BY_VALUE
850 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
851 cinfo->args [n].regtype = RegTypeStructByVal;
852 if (gr <= PPC_LAST_ARG_REG) {
853 int rest = PPC_LAST_ARG_REG - gr + 1;
854 int n_in_regs = rest >= nwords? nwords: rest;
855 cinfo->args [n].size = n_in_regs;
856 cinfo->args [n].vtsize = nwords - n_in_regs;
857 cinfo->args [n].reg = gr;
860 cinfo->args [n].size = 0;
861 cinfo->args [n].vtsize = nwords;
863 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
864 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
865 stack_size += nwords * sizeof (gpointer);
868 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
869 cinfo->args [n].regtype = RegTypeStructByAddr;
870 cinfo->args [n].vtsize = size;
877 cinfo->args [n].size = 8;
878 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
882 cinfo->args [n].size = 4;
884 /* It was 7, now it is 8 in LinuxPPC */
885 if (fr <= PPC_LAST_FPARG_REG) {
886 cinfo->args [n].regtype = RegTypeFP;
887 cinfo->args [n].reg = fr;
889 FP_ALSO_IN_REG (gr ++);
890 ALWAYS_ON_STACK (stack_size += 4);
892 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
893 cinfo->args [n].regtype = RegTypeBase;
894 cinfo->args [n].reg = ppc_sp; /* in the caller*/
900 cinfo->args [n].size = 8;
901 /* It was 7, now it is 8 in LinuxPPC */
902 if (fr <= PPC_LAST_FPARG_REG) {
903 cinfo->args [n].regtype = RegTypeFP;
904 cinfo->args [n].reg = fr;
906 FP_ALSO_IN_REG (gr += 2);
907 ALWAYS_ON_STACK (stack_size += 8);
909 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
910 cinfo->args [n].regtype = RegTypeBase;
911 cinfo->args [n].reg = ppc_sp; /* in the caller*/
917 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
921 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
922 /* Prevent implicit arguments and sig_cookie from
923 being passed in registers */
924 gr = PPC_LAST_ARG_REG + 1;
925 /* Emit the signature cookie just before the implicit arguments */
926 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
930 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
931 switch (simpletype) {
932 case MONO_TYPE_BOOLEAN:
943 case MONO_TYPE_FNPTR:
944 case MONO_TYPE_CLASS:
945 case MONO_TYPE_OBJECT:
946 case MONO_TYPE_SZARRAY:
947 case MONO_TYPE_ARRAY:
948 case MONO_TYPE_STRING:
949 cinfo->ret.reg = ppc_r3;
953 cinfo->ret.reg = ppc_r3;
957 cinfo->ret.reg = ppc_f1;
958 cinfo->ret.regtype = RegTypeFP;
960 case MONO_TYPE_GENERICINST:
961 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
962 cinfo->ret.reg = ppc_r3;
966 case MONO_TYPE_VALUETYPE:
968 case MONO_TYPE_TYPEDBYREF:
972 g_error ("Can't handle as return value 0x%x", sig->ret->type);
976 /* align stack size to 16 */
977 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
978 stack_size = (stack_size + 15) & ~15;
980 cinfo->stack_usage = stack_size;
985 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
987 #if !PPC_PASS_STRUCTS_BY_VALUE
988 MonoMethodSignature *sig = mono_method_signature (cfg->method);
992 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
995 for (i = 0; i < sig->param_count; ++i) {
996 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
997 if (type->type == MONO_TYPE_VALUETYPE)
1002 cfg->tailcall_valuetype_addrs =
1003 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1004 for (i = 0; i < num_structs; ++i) {
1005 cfg->tailcall_valuetype_addrs [i] =
1006 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1007 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1014 * Set var information according to the calling convention. ppc version.
1015 * The locals var stuff should most likely be split in another method.
1018 mono_arch_allocate_vars (MonoCompile *m)
1020 MonoMethodSignature *sig;
1021 MonoMethodHeader *header;
1023 int i, offset, size, align, curinst;
1024 int frame_reg = ppc_sp;
1026 guint32 locals_stack_size, locals_stack_align;
1028 allocate_tailcall_valuetype_addrs (m);
1030 m->flags |= MONO_CFG_HAS_SPILLUP;
1032 /* allow room for the vararg method args: void* and long/double */
1033 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1034 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1035 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1036 * call convs needs to be handled this way.
1038 if (m->flags & MONO_CFG_HAS_VARARGS)
1039 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1040 /* gtk-sharp and other broken code will dllimport vararg functions even with
1041 * non-varargs signatures. Since there is little hope people will get this right
1042 * we assume they won't.
1044 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1045 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1047 header = mono_method_get_header (m->method);
1050 * We use the frame register also for any method that has
1051 * exception clauses. This way, when the handlers are called,
1052 * the code will reference local variables using the frame reg instead of
1053 * the stack pointer: if we had to restore the stack pointer, we'd
1054 * corrupt the method frames that are already on the stack (since
1055 * filters get called before stack unwinding happens) when the filter
1056 * code would call any method (this also applies to finally etc.).
1058 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1059 frame_reg = ppc_r31;
1060 m->frame_reg = frame_reg;
1061 if (frame_reg != ppc_sp) {
1062 m->used_int_regs |= 1 << frame_reg;
1065 sig = mono_method_signature (m->method);
1069 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1070 m->ret->opcode = OP_REGVAR;
1071 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1073 /* FIXME: handle long values? */
1074 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1075 case MONO_TYPE_VOID:
1079 m->ret->opcode = OP_REGVAR;
1080 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1083 m->ret->opcode = OP_REGVAR;
1084 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1088 /* local vars are at a positive offset from the stack pointer */
1090 * also note that if the function uses alloca, we use ppc_r31
1091 * to point at the local variables.
1093 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1094 /* align the offset to 16 bytes: not sure this is needed here */
1096 //offset &= ~(16 - 1);
1098 /* add parameter area size for called functions */
1099 offset += m->param_area;
1101 offset &= ~(16 - 1);
1103 /* allow room to save the return value */
1104 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1107 /* the MonoLMF structure is stored just below the stack pointer */
1110 /* this stuff should not be needed on ppc and the new jit,
1111 * because a call on ppc to the handlers doesn't change the
1112 * stack pointer and the jist doesn't manipulate the stack pointer
1113 * for operations involving valuetypes.
1115 /* reserve space to store the esp */
1116 offset += sizeof (gpointer);
1118 /* this is a global constant */
1119 mono_exc_esp_offset = offset;
1121 if (sig->call_convention == MONO_CALL_VARARG) {
1122 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1125 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1126 offset += sizeof(gpointer) - 1;
1127 offset &= ~(sizeof(gpointer) - 1);
1129 m->vret_addr->opcode = OP_REGOFFSET;
1130 m->vret_addr->inst_basereg = frame_reg;
1131 m->vret_addr->inst_offset = offset;
1133 if (G_UNLIKELY (m->verbose_level > 1)) {
1134 printf ("vret_addr =");
1135 mono_print_ins (m->vret_addr);
1138 offset += sizeof(gpointer);
1139 if (sig->call_convention == MONO_CALL_VARARG)
1140 m->sig_cookie += sizeof (gpointer);
1143 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1144 if (locals_stack_align) {
1145 offset += (locals_stack_align - 1);
1146 offset &= ~(locals_stack_align - 1);
1148 for (i = m->locals_start; i < m->num_varinfo; i++) {
1149 if (offsets [i] != -1) {
1150 MonoInst *inst = m->varinfo [i];
1151 inst->opcode = OP_REGOFFSET;
1152 inst->inst_basereg = frame_reg;
1153 inst->inst_offset = offset + offsets [i];
1155 g_print ("allocating local %d (%s) to %d\n",
1156 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1160 offset += locals_stack_size;
1164 inst = m->args [curinst];
1165 if (inst->opcode != OP_REGVAR) {
1166 inst->opcode = OP_REGOFFSET;
1167 inst->inst_basereg = frame_reg;
1168 offset += sizeof (gpointer) - 1;
1169 offset &= ~(sizeof (gpointer) - 1);
1170 inst->inst_offset = offset;
1171 offset += sizeof (gpointer);
1172 if (sig->call_convention == MONO_CALL_VARARG)
1173 m->sig_cookie += sizeof (gpointer);
1178 for (i = 0; i < sig->param_count; ++i) {
1179 inst = m->args [curinst];
1180 if (inst->opcode != OP_REGVAR) {
1181 inst->opcode = OP_REGOFFSET;
1182 inst->inst_basereg = frame_reg;
1184 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1185 inst->backend.is_pinvoke = 1;
1187 size = mono_type_size (sig->params [i], &align);
1189 offset += align - 1;
1190 offset &= ~(align - 1);
1191 inst->inst_offset = offset;
1193 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1194 m->sig_cookie += size;
1199 /* some storage for fp conversions */
1202 m->arch.fp_conv_var_offset = offset;
1205 /* align the offset to 16 bytes */
1207 offset &= ~(16 - 1);
1210 m->stack_offset = offset;
1212 if (sig->call_convention == MONO_CALL_VARARG) {
1213 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1215 m->sig_cookie = cinfo->sig_cookie.offset;
1222 mono_arch_create_vars (MonoCompile *cfg)
1224 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1226 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1227 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1231 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1232 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1236 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1238 int sig_reg = mono_alloc_ireg (cfg);
1240 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1241 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1242 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1246 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1249 MonoMethodSignature *sig;
1253 sig = call->signature;
1254 n = sig->param_count + sig->hasthis;
1256 cinfo = calculate_sizes (sig, sig->pinvoke);
1258 for (i = 0; i < n; ++i) {
1259 ArgInfo *ainfo = cinfo->args + i;
1262 if (i >= sig->hasthis)
1263 t = sig->params [i - sig->hasthis];
1265 t = &mono_defaults.int_class->byval_arg;
1266 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1268 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1269 emit_sig_cookie (cfg, call, cinfo);
1271 in = call->args [i];
1273 if (ainfo->regtype == RegTypeGeneral) {
1274 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1275 MONO_INST_NEW (cfg, ins, OP_MOVE);
1276 ins->dreg = mono_alloc_ireg (cfg);
1277 ins->sreg1 = in->dreg + 1;
1278 MONO_ADD_INS (cfg->cbb, ins);
1279 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1281 MONO_INST_NEW (cfg, ins, OP_MOVE);
1282 ins->dreg = mono_alloc_ireg (cfg);
1283 ins->sreg1 = in->dreg + 2;
1284 MONO_ADD_INS (cfg->cbb, ins);
1285 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1287 MONO_INST_NEW (cfg, ins, OP_MOVE);
1288 ins->dreg = mono_alloc_ireg (cfg);
1289 ins->sreg1 = in->dreg;
1290 MONO_ADD_INS (cfg->cbb, ins);
1292 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1294 } else if (ainfo->regtype == RegTypeStructByAddr) {
1295 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1296 ins->opcode = OP_OUTARG_VT;
1297 ins->sreg1 = in->dreg;
1298 ins->klass = in->klass;
1299 ins->inst_p0 = call;
1300 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1301 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1302 MONO_ADD_INS (cfg->cbb, ins);
1303 } else if (ainfo->regtype == RegTypeStructByVal) {
1304 /* this is further handled in mono_arch_emit_outarg_vt () */
1305 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1306 ins->opcode = OP_OUTARG_VT;
1307 ins->sreg1 = in->dreg;
1308 ins->klass = in->klass;
1309 ins->inst_p0 = call;
1310 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1311 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1312 MONO_ADD_INS (cfg->cbb, ins);
1313 } else if (ainfo->regtype == RegTypeBase) {
1314 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1315 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1316 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1317 if (t->type == MONO_TYPE_R8)
1318 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1320 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1322 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1324 } else if (ainfo->regtype == RegTypeFP) {
1325 if (t->type == MONO_TYPE_VALUETYPE) {
1326 /* this is further handled in mono_arch_emit_outarg_vt () */
1327 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1328 ins->opcode = OP_OUTARG_VT;
1329 ins->sreg1 = in->dreg;
1330 ins->klass = in->klass;
1331 ins->inst_p0 = call;
1332 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1333 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1334 MONO_ADD_INS (cfg->cbb, ins);
1336 cfg->flags |= MONO_CFG_HAS_FPOUT;
1338 int dreg = mono_alloc_freg (cfg);
1340 if (ainfo->size == 4) {
1341 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1343 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1345 ins->sreg1 = in->dreg;
1346 MONO_ADD_INS (cfg->cbb, ins);
1349 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1350 cfg->flags |= MONO_CFG_HAS_FPOUT;
1353 g_assert_not_reached ();
1357 /* Emit the signature cookie in the case that there is no
1358 additional argument */
1359 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1360 emit_sig_cookie (cfg, call, cinfo);
1362 if (cinfo->struct_ret) {
1365 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1366 vtarg->sreg1 = call->vret_var->dreg;
1367 vtarg->dreg = mono_alloc_preg (cfg);
1368 MONO_ADD_INS (cfg->cbb, vtarg);
1370 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1373 call->stack_usage = cinfo->stack_usage;
1374 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1375 cfg->flags |= MONO_CFG_HAS_CALLS;
1381 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1383 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1384 ArgInfo *ainfo = ins->inst_p1;
1385 int ovf_size = ainfo->vtsize;
1386 int doffset = ainfo->offset;
1387 int i, soffset, dreg;
1389 if (ainfo->regtype == RegTypeStructByVal) {
1394 * Darwin pinvokes needs some special handling for 1
1395 * and 2 byte arguments
1397 g_assert (ins->klass);
1398 if (call->signature->pinvoke)
1399 size = mono_class_native_size (ins->klass, NULL);
1400 if (size == 2 || size == 1) {
1401 int tmpr = mono_alloc_ireg (cfg);
1403 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1405 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1406 dreg = mono_alloc_ireg (cfg);
1407 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1408 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1411 for (i = 0; i < ainfo->size; ++i) {
1412 dreg = mono_alloc_ireg (cfg);
1413 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1414 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1415 soffset += sizeof (gpointer);
1418 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1419 } else if (ainfo->regtype == RegTypeFP) {
1420 int tmpr = mono_alloc_freg (cfg);
1421 if (ainfo->size == 4)
1422 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1424 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1425 dreg = mono_alloc_freg (cfg);
1426 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1427 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1429 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1433 /* FIXME: alignment? */
1434 if (call->signature->pinvoke) {
1435 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1436 vtcopy->backend.is_pinvoke = 1;
1438 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1441 g_assert (ovf_size > 0);
1443 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1444 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1447 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1449 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1454 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1456 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1457 mono_method_signature (method)->ret);
1460 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1463 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1464 ins->sreg1 = val->dreg + 1;
1465 ins->sreg2 = val->dreg + 2;
1466 MONO_ADD_INS (cfg->cbb, ins);
1469 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1470 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1474 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1477 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1479 mono_arch_is_inst_imm (gint64 imm)
1485 * Allow tracing to work with this interface (with an optional argument)
1489 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1493 ppc_load (code, ppc_r3, cfg->method);
1494 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1495 ppc_load (code, ppc_r0, func);
1496 ppc_mtlr (code, ppc_r0);
1510 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1513 int save_mode = SAVE_NONE;
1515 MonoMethod *method = cfg->method;
1516 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1517 mono_method_signature (method)->ret)->type;
1518 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1522 offset = code - cfg->native_code;
1523 /* we need about 16 instructions */
1524 if (offset > (cfg->code_size - 16 * 4)) {
1525 cfg->code_size *= 2;
1526 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1527 code = cfg->native_code + offset;
1531 case MONO_TYPE_VOID:
1532 /* special case string .ctor icall */
1533 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1534 save_mode = SAVE_ONE;
1536 save_mode = SAVE_NONE;
1540 save_mode = SAVE_TWO;
1544 save_mode = SAVE_FP;
1546 case MONO_TYPE_VALUETYPE:
1547 save_mode = SAVE_STRUCT;
1550 save_mode = SAVE_ONE;
1554 switch (save_mode) {
1556 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1557 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1558 if (enable_arguments) {
1559 ppc_mr (code, ppc_r5, ppc_r4);
1560 ppc_mr (code, ppc_r4, ppc_r3);
1564 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1565 if (enable_arguments) {
1566 ppc_mr (code, ppc_r4, ppc_r3);
1570 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1571 if (enable_arguments) {
1572 /* FIXME: what reg? */
1573 ppc_fmr (code, ppc_f3, ppc_f1);
1574 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1575 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1579 if (enable_arguments) {
1580 /* FIXME: get the actual address */
1581 ppc_mr (code, ppc_r4, ppc_r3);
1589 ppc_load (code, ppc_r3, cfg->method);
1590 ppc_load (code, ppc_r0, func);
1591 ppc_mtlr (code, ppc_r0);
1594 switch (save_mode) {
1596 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1597 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1600 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1603 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1613 * Conditional branches have a small offset, so if it is likely overflowed,
1614 * we do a branch to the end of the method (uncond branches have much larger
1615 * offsets) where we perform the conditional and jump back unconditionally.
1616 * It's slightly slower, since we add two uncond branches, but it's very simple
1617 * with the current patch implementation and such large methods are likely not
1618 * going to be perf critical anyway.
1623 const char *exception;
1630 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1631 if (ins->flags & MONO_INST_BRLABEL) { \
1632 if (0 && ins->inst_i0->inst_c0) { \
1633 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1635 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1636 ppc_bc (code, (b0), (b1), 0); \
1639 if (0 && ins->inst_true_bb->native_offset) { \
1640 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1642 int br_disp = ins->inst_true_bb->max_offset - offset; \
1643 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1644 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1645 ovfj->data.bb = ins->inst_true_bb; \
1646 ovfj->ip_offset = 0; \
1647 ovfj->b0_cond = (b0); \
1648 ovfj->b1_cond = (b1); \
1649 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1652 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1653 ppc_bc (code, (b0), (b1), 0); \
1658 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1660 /* emit an exception if condition is fail
1662 * We assign the extra code used to throw the implicit exceptions
1663 * to cfg->bb_exit as far as the big branch handling is concerned
1665 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1667 int br_disp = cfg->bb_exit->max_offset - offset; \
1668 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1669 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1670 ovfj->data.exception = (exc_name); \
1671 ovfj->ip_offset = code - cfg->native_code; \
1672 ovfj->b0_cond = (b0); \
1673 ovfj->b1_cond = (b1); \
1674 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1676 cfg->bb_exit->max_offset += 24; \
1678 mono_add_patch_info (cfg, code - cfg->native_code, \
1679 MONO_PATCH_INFO_EXC, exc_name); \
1680 ppc_bcl (code, (b0), (b1), 0); \
1684 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1687 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1692 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1694 MonoInst *ins, *n, *last_ins = NULL;
1696 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1697 switch (ins->opcode) {
1699 /* remove unnecessary multiplication with 1 */
1700 if (ins->inst_imm == 1) {
1701 if (ins->dreg != ins->sreg1) {
1702 ins->opcode = OP_MOVE;
1704 MONO_DELETE_INS (bb, ins);
1708 int power2 = mono_is_power_of_two (ins->inst_imm);
1710 ins->opcode = OP_SHL_IMM;
1711 ins->inst_imm = power2;
1715 case OP_LOAD_MEMBASE:
1716 case OP_LOADI4_MEMBASE:
1718 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1719 * OP_LOAD_MEMBASE offset(basereg), reg
1721 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1722 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1723 ins->inst_basereg == last_ins->inst_destbasereg &&
1724 ins->inst_offset == last_ins->inst_offset) {
1725 if (ins->dreg == last_ins->sreg1) {
1726 MONO_DELETE_INS (bb, ins);
1729 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1730 ins->opcode = OP_MOVE;
1731 ins->sreg1 = last_ins->sreg1;
1735 * Note: reg1 must be different from the basereg in the second load
1736 * OP_LOAD_MEMBASE offset(basereg), reg1
1737 * OP_LOAD_MEMBASE offset(basereg), reg2
1739 * OP_LOAD_MEMBASE offset(basereg), reg1
1740 * OP_MOVE reg1, reg2
1742 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1743 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1744 ins->inst_basereg != last_ins->dreg &&
1745 ins->inst_basereg == last_ins->inst_basereg &&
1746 ins->inst_offset == last_ins->inst_offset) {
1748 if (ins->dreg == last_ins->dreg) {
1749 MONO_DELETE_INS (bb, ins);
1752 ins->opcode = OP_MOVE;
1753 ins->sreg1 = last_ins->dreg;
1756 //g_assert_not_reached ();
1760 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1761 * OP_LOAD_MEMBASE offset(basereg), reg
1763 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1764 * OP_ICONST reg, imm
1766 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1767 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1768 ins->inst_basereg == last_ins->inst_destbasereg &&
1769 ins->inst_offset == last_ins->inst_offset) {
1770 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1771 ins->opcode = OP_ICONST;
1772 ins->inst_c0 = last_ins->inst_imm;
1773 g_assert_not_reached (); // check this rule
1777 case OP_LOADU1_MEMBASE:
1778 case OP_LOADI1_MEMBASE:
1779 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1780 ins->inst_basereg == last_ins->inst_destbasereg &&
1781 ins->inst_offset == last_ins->inst_offset) {
1782 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1783 ins->sreg1 = last_ins->sreg1;
1786 case OP_LOADU2_MEMBASE:
1787 case OP_LOADI2_MEMBASE:
1788 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1789 ins->inst_basereg == last_ins->inst_destbasereg &&
1790 ins->inst_offset == last_ins->inst_offset) {
1791 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1792 ins->sreg1 = last_ins->sreg1;
1796 ins->opcode = OP_MOVE;
1800 if (ins->dreg == ins->sreg1) {
1801 MONO_DELETE_INS (bb, ins);
1805 * OP_MOVE sreg, dreg
1806 * OP_MOVE dreg, sreg
1808 if (last_ins && last_ins->opcode == OP_MOVE &&
1809 ins->sreg1 == last_ins->dreg &&
1810 ins->dreg == last_ins->sreg1) {
1811 MONO_DELETE_INS (bb, ins);
1819 bb->last_ins = last_ins;
1823 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1825 switch (ins->opcode) {
1826 case OP_ICONV_TO_R_UN: {
1827 static const guint64 adjust_val = 0x4330000000000000ULL;
1828 int msw_reg = mono_alloc_ireg (cfg);
1829 int adj_reg = mono_alloc_freg (cfg);
1830 int tmp_reg = mono_alloc_freg (cfg);
1831 int basereg = ppc_sp;
1833 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1834 if (!ppc_is_imm16 (offset + 4)) {
1835 basereg = mono_alloc_ireg (cfg);
1836 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1838 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1839 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
1840 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1841 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1842 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1843 ins->opcode = OP_NOP;
1846 case OP_ICONV_TO_R4:
1847 case OP_ICONV_TO_R8: {
1848 /* FIXME: change precision for CEE_CONV_R4 */
1849 static const guint64 adjust_val = 0x4330000080000000ULL;
1850 int msw_reg = mono_alloc_ireg (cfg);
1851 int xored = mono_alloc_ireg (cfg);
1852 int adj_reg = mono_alloc_freg (cfg);
1853 int tmp_reg = mono_alloc_freg (cfg);
1854 int basereg = ppc_sp;
1856 if (!ppc_is_imm16 (offset + 4)) {
1857 basereg = mono_alloc_ireg (cfg);
1858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1860 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1861 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1862 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
1863 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
1864 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
1865 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1866 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1867 if (ins->opcode == OP_ICONV_TO_R4)
1868 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
1869 ins->opcode = OP_NOP;
1873 int msw_reg = mono_alloc_ireg (cfg);
1874 int basereg = ppc_sp;
1876 if (!ppc_is_imm16 (offset + 4)) {
1877 basereg = mono_alloc_ireg (cfg);
1878 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1880 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
1881 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
1882 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
1883 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1884 ins->opcode = OP_NOP;
1891 * the branch_b0_table should maintain the order of these
1905 branch_b0_table [] = {
1920 branch_b1_table [] = {
1934 #define NEW_INS(cfg,dest,op) do { \
1935 MONO_INST_NEW((cfg), (dest), (op)); \
1936 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1940 map_to_reg_reg_op (int op)
1949 case OP_COMPARE_IMM:
1951 case OP_ICOMPARE_IMM:
1967 case OP_LOAD_MEMBASE:
1968 return OP_LOAD_MEMINDEX;
1969 case OP_LOADI4_MEMBASE:
1970 return OP_LOADI4_MEMINDEX;
1971 case OP_LOADU4_MEMBASE:
1972 return OP_LOADU4_MEMINDEX;
1973 case OP_LOADU1_MEMBASE:
1974 return OP_LOADU1_MEMINDEX;
1975 case OP_LOADI2_MEMBASE:
1976 return OP_LOADI2_MEMINDEX;
1977 case OP_LOADU2_MEMBASE:
1978 return OP_LOADU2_MEMINDEX;
1979 case OP_LOADI1_MEMBASE:
1980 return OP_LOADI1_MEMINDEX;
1981 case OP_LOADR4_MEMBASE:
1982 return OP_LOADR4_MEMINDEX;
1983 case OP_LOADR8_MEMBASE:
1984 return OP_LOADR8_MEMINDEX;
1985 case OP_STOREI1_MEMBASE_REG:
1986 return OP_STOREI1_MEMINDEX;
1987 case OP_STOREI2_MEMBASE_REG:
1988 return OP_STOREI2_MEMINDEX;
1989 case OP_STOREI4_MEMBASE_REG:
1990 return OP_STOREI4_MEMINDEX;
1991 case OP_STORE_MEMBASE_REG:
1992 return OP_STORE_MEMINDEX;
1993 case OP_STORER4_MEMBASE_REG:
1994 return OP_STORER4_MEMINDEX;
1995 case OP_STORER8_MEMBASE_REG:
1996 return OP_STORER8_MEMINDEX;
1997 case OP_STORE_MEMBASE_IMM:
1998 return OP_STORE_MEMBASE_REG;
1999 case OP_STOREI1_MEMBASE_IMM:
2000 return OP_STOREI1_MEMBASE_REG;
2001 case OP_STOREI2_MEMBASE_IMM:
2002 return OP_STOREI2_MEMBASE_REG;
2003 case OP_STOREI4_MEMBASE_IMM:
2004 return OP_STOREI4_MEMBASE_REG;
2006 return mono_op_imm_to_op (op);
2009 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2011 #define compare_opcode_is_unsigned(opcode) \
2012 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2013 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2014 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2015 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2016 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2018 * Remove from the instruction list the instructions that can't be
2019 * represented with very simple instructions with no register
2023 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2025 MonoInst *ins, *next, *temp, *last_ins = NULL;
2028 MONO_BB_FOR_EACH_INS (bb, ins) {
2030 switch (ins->opcode) {
2031 case OP_IDIV_UN_IMM:
2034 case OP_IREM_UN_IMM:
2035 NEW_INS (cfg, temp, OP_ICONST);
2036 temp->inst_c0 = ins->inst_imm;
2037 temp->dreg = mono_alloc_ireg (cfg);
2038 ins->sreg2 = temp->dreg;
2039 if (ins->opcode == OP_IDIV_IMM)
2040 ins->opcode = OP_IDIV;
2041 else if (ins->opcode == OP_IREM_IMM)
2042 ins->opcode = OP_IREM;
2043 else if (ins->opcode == OP_IDIV_UN_IMM)
2044 ins->opcode = OP_IDIV_UN;
2045 else if (ins->opcode == OP_IREM_UN_IMM)
2046 ins->opcode = OP_IREM_UN;
2048 /* handle rem separately */
2053 /* we change a rem dest, src1, src2 to
2054 * div temp1, src1, src2
2055 * mul temp2, temp1, src2
2056 * sub dest, src1, temp2
2058 NEW_INS (cfg, mul, OP_IMUL);
2059 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2060 temp->sreg1 = ins->sreg1;
2061 temp->sreg2 = ins->sreg2;
2062 temp->dreg = mono_alloc_ireg (cfg);
2063 mul->sreg1 = temp->dreg;
2064 mul->sreg2 = ins->sreg2;
2065 mul->dreg = mono_alloc_ireg (cfg);
2066 ins->opcode = OP_ISUB;
2067 ins->sreg2 = mul->dreg;
2073 if (!ppc_is_imm16 (ins->inst_imm)) {
2074 NEW_INS (cfg, temp, OP_ICONST);
2075 temp->inst_c0 = ins->inst_imm;
2076 temp->dreg = mono_alloc_ireg (cfg);
2077 ins->sreg2 = temp->dreg;
2078 ins->opcode = map_to_reg_reg_op (ins->opcode);
2083 if (!ppc_is_imm16 (-ins->inst_imm)) {
2084 NEW_INS (cfg, temp, OP_ICONST);
2085 temp->inst_c0 = ins->inst_imm;
2086 temp->dreg = mono_alloc_ireg (cfg);
2087 ins->sreg2 = temp->dreg;
2088 ins->opcode = map_to_reg_reg_op (ins->opcode);
2097 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2098 NEW_INS (cfg, temp, OP_ICONST);
2099 temp->inst_c0 = ins->inst_imm;
2100 temp->dreg = mono_alloc_ireg (cfg);
2101 ins->sreg2 = temp->dreg;
2102 ins->opcode = map_to_reg_reg_op (ins->opcode);
2110 NEW_INS (cfg, temp, OP_ICONST);
2111 temp->inst_c0 = ins->inst_imm;
2112 temp->dreg = mono_alloc_ireg (cfg);
2113 ins->sreg2 = temp->dreg;
2114 ins->opcode = map_to_reg_reg_op (ins->opcode);
2116 case OP_COMPARE_IMM:
2117 case OP_ICOMPARE_IMM:
2119 /* Branch opts can eliminate the branch */
2120 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2121 ins->opcode = OP_NOP;
2125 if (compare_opcode_is_unsigned (next->opcode)) {
2126 if (!ppc_is_uimm16 (ins->inst_imm)) {
2127 NEW_INS (cfg, temp, OP_ICONST);
2128 temp->inst_c0 = ins->inst_imm;
2129 temp->dreg = mono_alloc_ireg (cfg);
2130 ins->sreg2 = temp->dreg;
2131 ins->opcode = map_to_reg_reg_op (ins->opcode);
2134 if (!ppc_is_imm16 (ins->inst_imm)) {
2135 NEW_INS (cfg, temp, OP_ICONST);
2136 temp->inst_c0 = ins->inst_imm;
2137 temp->dreg = mono_alloc_ireg (cfg);
2138 ins->sreg2 = temp->dreg;
2139 ins->opcode = map_to_reg_reg_op (ins->opcode);
2145 if (ins->inst_imm == 1) {
2146 ins->opcode = OP_MOVE;
2149 if (ins->inst_imm == 0) {
2150 ins->opcode = OP_ICONST;
2154 imm = mono_is_power_of_two (ins->inst_imm);
2156 ins->opcode = OP_SHL_IMM;
2157 ins->inst_imm = imm;
2160 if (!ppc_is_imm16 (ins->inst_imm)) {
2161 NEW_INS (cfg, temp, OP_ICONST);
2162 temp->inst_c0 = ins->inst_imm;
2163 temp->dreg = mono_alloc_ireg (cfg);
2164 ins->sreg2 = temp->dreg;
2165 ins->opcode = map_to_reg_reg_op (ins->opcode);
2168 case OP_LOCALLOC_IMM:
2169 NEW_INS (cfg, temp, OP_ICONST);
2170 temp->inst_c0 = ins->inst_imm;
2171 temp->dreg = mono_alloc_ireg (cfg);
2172 ins->sreg1 = temp->dreg;
2173 ins->opcode = OP_LOCALLOC;
2175 case OP_LOAD_MEMBASE:
2176 case OP_LOADI4_MEMBASE:
2177 case OP_LOADU4_MEMBASE:
2178 case OP_LOADI2_MEMBASE:
2179 case OP_LOADU2_MEMBASE:
2180 case OP_LOADI1_MEMBASE:
2181 case OP_LOADU1_MEMBASE:
2182 case OP_LOADR4_MEMBASE:
2183 case OP_LOADR8_MEMBASE:
2184 case OP_STORE_MEMBASE_REG:
2185 case OP_STOREI4_MEMBASE_REG:
2186 case OP_STOREI2_MEMBASE_REG:
2187 case OP_STOREI1_MEMBASE_REG:
2188 case OP_STORER4_MEMBASE_REG:
2189 case OP_STORER8_MEMBASE_REG:
2190 /* we can do two things: load the immed in a register
2191 * and use an indexed load, or see if the immed can be
2192 * represented as an ad_imm + a load with a smaller offset
2193 * that fits. We just do the first for now, optimize later.
2195 if (ppc_is_imm16 (ins->inst_offset))
2197 NEW_INS (cfg, temp, OP_ICONST);
2198 temp->inst_c0 = ins->inst_offset;
2199 temp->dreg = mono_alloc_ireg (cfg);
2200 ins->sreg2 = temp->dreg;
2201 ins->opcode = map_to_reg_reg_op (ins->opcode);
2203 case OP_STORE_MEMBASE_IMM:
2204 case OP_STOREI1_MEMBASE_IMM:
2205 case OP_STOREI2_MEMBASE_IMM:
2206 case OP_STOREI4_MEMBASE_IMM:
2207 NEW_INS (cfg, temp, OP_ICONST);
2208 temp->inst_c0 = ins->inst_imm;
2209 temp->dreg = mono_alloc_ireg (cfg);
2210 ins->sreg1 = temp->dreg;
2211 ins->opcode = map_to_reg_reg_op (ins->opcode);
2213 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2216 NEW_INS (cfg, temp, OP_ICONST);
2217 temp->inst_c0 = (guint32)ins->inst_p0;
2218 temp->dreg = mono_alloc_ireg (cfg);
2219 ins->inst_basereg = temp->dreg;
2220 ins->inst_offset = 0;
2221 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2223 /* make it handle the possibly big ins->inst_offset
2224 * later optimize to use lis + load_membase
2230 bb->last_ins = last_ins;
2231 bb->max_vreg = cfg->next_vreg;
2235 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2237 int offset = cfg->arch.fp_conv_var_offset;
2238 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2239 ppc_fctiwz (code, ppc_f0, sreg);
2240 if (ppc_is_imm16 (offset + 4)) {
2241 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2242 ppc_lwz (code, dreg, offset + 4, cfg->frame_reg);
2244 ppc_load (code, dreg, offset);
2245 ppc_add (code, dreg, dreg, cfg->frame_reg);
2246 ppc_stfd (code, ppc_f0, 0, dreg);
2247 ppc_lwz (code, dreg, 4, dreg);
2251 ppc_andid (code, dreg, dreg, 0xff);
2253 ppc_andid (code, dreg, dreg, 0xffff);
2256 ppc_extsb (code, dreg, dreg);
2258 ppc_extsh (code, dreg, dreg);
2265 const guchar *target;
2270 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2273 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2274 PatchData *pdata = (PatchData*)user_data;
2275 guchar *code = data;
2276 guint32 *thunks = data;
2277 guint32 *endthunks = (guint32*)(code + bsize);
2281 int difflow, diffhigh;
2283 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2284 difflow = (char*)pdata->code - (char*)thunks;
2285 diffhigh = (char*)pdata->code - (char*)endthunks;
2286 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2289 templ = (guchar*)load;
2290 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2291 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2293 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2294 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2295 while (thunks < endthunks) {
2296 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2297 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2298 ppc_patch (pdata->code, (guchar*)thunks);
2299 mono_arch_flush_icache (pdata->code, 4);
2302 static int num_thunks = 0;
2304 if ((num_thunks % 20) == 0)
2305 g_print ("num_thunks lookup: %d\n", num_thunks);
2308 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2309 /* found a free slot instead: emit thunk */
2310 code = (guchar*)thunks;
2311 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2312 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2313 ppc_mtctr (code, ppc_r0);
2314 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2315 mono_arch_flush_icache ((guchar*)thunks, 16);
2317 ppc_patch (pdata->code, (guchar*)thunks);
2318 mono_arch_flush_icache (pdata->code, 4);
2321 static int num_thunks = 0;
2323 if ((num_thunks % 20) == 0)
2324 g_print ("num_thunks: %d\n", num_thunks);
2328 /* skip 16 bytes, the size of the thunk */
2332 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2338 handle_thunk (int absolute, guchar *code, const guchar *target) {
2339 MonoDomain *domain = mono_domain_get ();
2343 pdata.target = target;
2344 pdata.absolute = absolute;
2347 mono_domain_lock (domain);
2348 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2351 /* this uses the first available slot */
2353 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2355 mono_domain_unlock (domain);
2357 if (pdata.found != 1)
2358 g_print ("thunk failed for %p from %p\n", target, code);
2359 g_assert (pdata.found == 1);
2363 ppc_patch (guchar *code, const guchar *target)
2365 guint32 ins = *(guint32*)code;
2366 guint32 prim = ins >> 26;
2369 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2371 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2372 gint diff = target - code;
2374 if (diff <= 33554431){
2375 ins = (18 << 26) | (diff) | (ins & 1);
2376 *(guint32*)code = ins;
2380 /* diff between 0 and -33554432 */
2381 if (diff >= -33554432){
2382 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2383 *(guint32*)code = ins;
2388 if ((glong)target >= 0){
2389 if ((glong)target <= 33554431){
2390 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2391 *(guint32*)code = ins;
2395 if ((glong)target >= -33554432){
2396 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2397 *(guint32*)code = ins;
2402 handle_thunk (TRUE, code, target);
2405 g_assert_not_reached ();
2412 guint32 li = (guint32)target;
2413 ins = (ins & 0xffff0000) | (ins & 3);
2414 ovf = li & 0xffff0000;
2415 if (ovf != 0 && ovf != 0xffff0000)
2416 g_assert_not_reached ();
2419 // FIXME: assert the top bits of li are 0
2421 gint diff = target - code;
2422 ins = (ins & 0xffff0000) | (ins & 3);
2423 ovf = diff & 0xffff0000;
2424 if (ovf != 0 && ovf != 0xffff0000)
2425 g_assert_not_reached ();
2429 *(guint32*)code = ins;
2433 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2435 /* the trampoline code will try to patch the blrl, blr, bcctr */
2436 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2439 /* this is the lis/ori/mtlr/blrl sequence */
2440 seq = (guint32*)code;
2441 g_assert ((seq [0] >> 26) == 15);
2442 g_assert ((seq [1] >> 26) == 24);
2443 g_assert ((seq [2] >> 26) == 31);
2444 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2445 /* FIXME: make this thread safe */
2446 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2447 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2448 mono_arch_flush_icache (code - 8, 8);
2450 g_assert_not_reached ();
2452 // g_print ("patched with 0x%08x\n", ins);
2456 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2458 switch (ins->opcode) {
2461 case OP_FCALL_MEMBASE:
2462 if (ins->dreg != ppc_f1)
2463 ppc_fmr (code, ins->dreg, ppc_f1);
2471 * emit_load_volatile_arguments:
2473 * Load volatile arguments from the stack to the original input registers.
2474 * Required before a tail call.
2477 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2479 MonoMethod *method = cfg->method;
2480 MonoMethodSignature *sig;
2484 int struct_index = 0;
2486 /* FIXME: Generate intermediate code instead */
2488 sig = mono_method_signature (method);
2490 /* This is the opposite of the code in emit_prolog */
2494 cinfo = calculate_sizes (sig, sig->pinvoke);
2496 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2497 ArgInfo *ainfo = &cinfo->ret;
2498 inst = cfg->vret_addr;
2499 g_assert (ppc_is_imm16 (inst->inst_offset));
2500 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2502 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2503 ArgInfo *ainfo = cinfo->args + i;
2504 inst = cfg->args [pos];
2506 g_assert (inst->opcode != OP_REGVAR);
2507 g_assert (ppc_is_imm16 (inst->inst_offset));
2509 switch (ainfo->regtype) {
2510 case RegTypeGeneral:
2511 switch (ainfo->size) {
2513 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2516 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2519 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2525 switch (ainfo->size) {
2527 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2530 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2533 g_assert_not_reached ();
2538 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
2539 &inst->klass->byval_arg);
2541 if (!MONO_TYPE_IS_REFERENCE (type) && type->type != MONO_TYPE_I4)
2544 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2545 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
2549 case RegTypeStructByVal: {
2558 * Darwin pinvokes needs some special handling
2559 * for 1 and 2 byte arguments
2561 if (method->signature->pinvoke)
2562 size = mono_class_native_size (inst->klass, NULL);
2563 if (size == 1 || size == 2) {
2568 for (j = 0; j < ainfo->size; ++j) {
2569 ppc_lwz (code, ainfo->reg + j,
2570 inst->inst_offset + j * sizeof (gpointer), inst->inst_basereg);
2575 case RegTypeStructByAddr: {
2576 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2578 g_assert (ppc_is_imm16 (addr->inst_offset));
2579 g_assert (!ainfo->offset);
2580 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2587 g_assert_not_reached ();
2598 /* This must be kept in sync with emit_load_volatile_arguments(). */
2600 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2602 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2603 MonoMethodSignature *sig;
2608 if (ins->opcode != OP_JMP)
2611 call = (MonoCallInst*)ins;
2612 sig = mono_method_signature (cfg->method);
2613 cinfo = calculate_sizes (sig, sig->pinvoke);
2615 if (MONO_TYPE_ISSTRUCT (sig->ret))
2617 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2618 ArgInfo *ainfo = cinfo->args + i;
2620 switch (ainfo->regtype) {
2621 case RegTypeGeneral:
2630 case RegTypeStructByVal:
2631 len += 4 * ainfo->size;
2634 case RegTypeStructByAddr:
2639 g_assert_not_reached ();
2649 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2651 int size = cfg->param_area;
2653 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2654 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2659 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2660 if (ppc_is_imm16 (-size)) {
2661 ppc_stwu (code, ppc_r0, -size, ppc_sp);
2663 ppc_load (code, ppc_r11, -size);
2664 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2671 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
2673 int size = cfg->param_area;
2675 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2676 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2681 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2682 if (ppc_is_imm16 (size)) {
2683 ppc_stwu (code, ppc_r0, size, ppc_sp);
2685 ppc_load (code, ppc_r11, size);
2686 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2693 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2695 MonoInst *ins, *next;
2698 guint8 *code = cfg->native_code + cfg->code_len;
2699 MonoInst *last_ins = NULL;
2700 guint last_offset = 0;
2703 /* we don't align basic blocks of loops on ppc */
2705 if (cfg->verbose_level > 2)
2706 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2708 cpos = bb->max_offset;
2710 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2711 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2712 //g_assert (!mono_compile_aot);
2715 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2716 /* this is not thread save, but good enough */
2717 /* fixme: howto handle overflows? */
2718 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2721 MONO_BB_FOR_EACH_INS (bb, ins) {
2722 offset = code - cfg->native_code;
2724 max_len = ins_native_length (cfg, ins);
2726 if (offset > (cfg->code_size - max_len - 16)) {
2727 cfg->code_size *= 2;
2728 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2729 code = cfg->native_code + offset;
2731 // if (ins->cil_code)
2732 // g_print ("cil code\n");
2733 mono_debug_record_line_number (cfg, ins, offset);
2735 switch (ins->opcode) {
2736 case OP_RELAXED_NOP:
2739 case OP_DUMMY_STORE:
2740 case OP_NOT_REACHED:
2744 emit_tls_access (code, ins->dreg, ins->inst_offset);
2747 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2748 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2749 ppc_mr (code, ppc_r4, ppc_r0);
2752 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2753 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2754 ppc_mr (code, ppc_r4, ppc_r0);
2756 case OP_MEMORY_BARRIER:
2759 case OP_STOREI1_MEMBASE_REG:
2760 if (ppc_is_imm16 (ins->inst_offset)) {
2761 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2763 ppc_load (code, ppc_r0, ins->inst_offset);
2764 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2767 case OP_STOREI2_MEMBASE_REG:
2768 if (ppc_is_imm16 (ins->inst_offset)) {
2769 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2771 ppc_load (code, ppc_r0, ins->inst_offset);
2772 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2775 case OP_STORE_MEMBASE_REG:
2776 case OP_STOREI4_MEMBASE_REG:
2777 if (ppc_is_imm16 (ins->inst_offset)) {
2778 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2780 ppc_load (code, ppc_r0, ins->inst_offset);
2781 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2784 case OP_STOREI1_MEMINDEX:
2785 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2787 case OP_STOREI2_MEMINDEX:
2788 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2790 case OP_STORE_MEMINDEX:
2791 case OP_STOREI4_MEMINDEX:
2792 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2795 g_assert_not_reached ();
2797 case OP_LOAD_MEMBASE:
2798 case OP_LOADI4_MEMBASE:
2799 case OP_LOADU4_MEMBASE:
2800 if (ppc_is_imm16 (ins->inst_offset)) {
2801 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2803 ppc_load (code, ppc_r0, ins->inst_offset);
2804 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2807 case OP_LOADI1_MEMBASE:
2808 case OP_LOADU1_MEMBASE:
2809 if (ppc_is_imm16 (ins->inst_offset)) {
2810 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2812 ppc_load (code, ppc_r0, ins->inst_offset);
2813 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2815 if (ins->opcode == OP_LOADI1_MEMBASE)
2816 ppc_extsb (code, ins->dreg, ins->dreg);
2818 case OP_LOADU2_MEMBASE:
2819 if (ppc_is_imm16 (ins->inst_offset)) {
2820 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2822 ppc_load (code, ppc_r0, ins->inst_offset);
2823 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2826 case OP_LOADI2_MEMBASE:
2827 if (ppc_is_imm16 (ins->inst_offset)) {
2828 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2830 ppc_load (code, ppc_r0, ins->inst_offset);
2831 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2834 case OP_LOAD_MEMINDEX:
2835 case OP_LOADI4_MEMINDEX:
2836 case OP_LOADU4_MEMINDEX:
2837 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2839 case OP_LOADU2_MEMINDEX:
2840 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2842 case OP_LOADI2_MEMINDEX:
2843 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2845 case OP_LOADU1_MEMINDEX:
2846 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2848 case OP_LOADI1_MEMINDEX:
2849 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2850 ppc_extsb (code, ins->dreg, ins->dreg);
2852 case OP_ICONV_TO_I1:
2853 ppc_extsb (code, ins->dreg, ins->sreg1);
2855 case OP_ICONV_TO_I2:
2856 ppc_extsh (code, ins->dreg, ins->sreg1);
2858 case OP_ICONV_TO_U1:
2859 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2861 case OP_ICONV_TO_U2:
2862 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2867 if (next && compare_opcode_is_unsigned (next->opcode))
2868 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2870 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2872 case OP_COMPARE_IMM:
2873 case OP_ICOMPARE_IMM:
2875 if (next && compare_opcode_is_unsigned (next->opcode)) {
2876 if (ppc_is_uimm16 (ins->inst_imm)) {
2877 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2879 g_assert_not_reached ();
2882 if (ppc_is_imm16 (ins->inst_imm)) {
2883 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2885 g_assert_not_reached ();
2894 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2897 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2901 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2904 if (ppc_is_imm16 (ins->inst_imm)) {
2905 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2907 g_assert_not_reached ();
2912 if (ppc_is_imm16 (ins->inst_imm)) {
2913 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2915 g_assert_not_reached ();
2919 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2921 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2922 ppc_mfspr (code, ppc_r0, ppc_xer);
2923 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2924 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2926 case OP_IADD_OVF_UN:
2927 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2929 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2930 ppc_mfspr (code, ppc_r0, ppc_xer);
2931 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2932 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2935 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2937 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2938 ppc_mfspr (code, ppc_r0, ppc_xer);
2939 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2940 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2942 case OP_ISUB_OVF_UN:
2943 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2945 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2946 ppc_mfspr (code, ppc_r0, ppc_xer);
2947 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2948 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2950 case OP_ADD_OVF_CARRY:
2951 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2953 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2954 ppc_mfspr (code, ppc_r0, ppc_xer);
2955 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2956 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2958 case OP_ADD_OVF_UN_CARRY:
2959 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2961 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2962 ppc_mfspr (code, ppc_r0, ppc_xer);
2963 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2964 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2966 case OP_SUB_OVF_CARRY:
2967 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2969 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2970 ppc_mfspr (code, ppc_r0, ppc_xer);
2971 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2972 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2974 case OP_SUB_OVF_UN_CARRY:
2975 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2977 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2978 ppc_mfspr (code, ppc_r0, ppc_xer);
2979 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2980 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2984 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2987 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2991 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2995 // we add the negated value
2996 if (ppc_is_imm16 (-ins->inst_imm))
2997 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2999 g_assert_not_reached ();
3003 g_assert (ppc_is_imm16 (ins->inst_imm));
3004 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3007 ppc_subfze (code, ins->dreg, ins->sreg1);
3010 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3011 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3015 if (!(ins->inst_imm & 0xffff0000)) {
3016 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3017 } else if (!(ins->inst_imm & 0xffff)) {
3018 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3020 g_assert_not_reached ();
3024 guint8 *divisor_is_m1;
3025 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3027 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3028 divisor_is_m1 = code;
3029 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3030 ppc_lis (code, ppc_r0, 0x8000);
3031 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3032 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3033 ppc_patch (divisor_is_m1, code);
3034 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3036 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3037 ppc_mfspr (code, ppc_r0, ppc_xer);
3038 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3039 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3043 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
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, "DivideByZeroException");
3052 g_assert_not_reached ();
3054 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3058 if (!(ins->inst_imm & 0xffff0000)) {
3059 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3060 } else if (!(ins->inst_imm & 0xffff)) {
3061 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3063 g_assert_not_reached ();
3067 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3071 if (!(ins->inst_imm & 0xffff0000)) {
3072 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3073 } else if (!(ins->inst_imm & 0xffff)) {
3074 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3076 g_assert_not_reached ();
3080 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3084 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3087 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3091 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3094 case OP_ISHR_UN_IMM:
3096 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3098 ppc_mr (code, ins->dreg, ins->sreg1);
3101 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3104 ppc_not (code, ins->dreg, ins->sreg1);
3107 ppc_neg (code, ins->dreg, ins->sreg1);
3110 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3114 if (ppc_is_imm16 (ins->inst_imm)) {
3115 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3117 g_assert_not_reached ();
3121 /* we annot use mcrxr, since it's not implemented on some processors
3122 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3124 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3125 ppc_mfspr (code, ppc_r0, ppc_xer);
3126 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3127 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3129 case OP_IMUL_OVF_UN:
3130 /* we first multiply to get the high word and compare to 0
3131 * to set the flags, then the result is discarded and then
3132 * we multiply to get the lower * bits result
3134 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3135 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3136 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3137 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3140 ppc_load (code, ins->dreg, ins->inst_c0);
3143 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3144 ppc_lis (code, ins->dreg, 0);
3145 ppc_ori (code, ins->dreg, ins->dreg, 0);
3147 case OP_ICONV_TO_I4:
3148 case OP_ICONV_TO_U4:
3150 ppc_mr (code, ins->dreg, ins->sreg1);
3153 int saved = ins->sreg1;
3154 if (ins->sreg1 == ppc_r3) {
3155 ppc_mr (code, ppc_r0, ins->sreg1);
3158 if (ins->sreg2 != ppc_r3)
3159 ppc_mr (code, ppc_r3, ins->sreg2);
3160 if (saved != ppc_r4)
3161 ppc_mr (code, ppc_r4, saved);
3165 ppc_fmr (code, ins->dreg, ins->sreg1);
3167 case OP_FCONV_TO_R4:
3168 ppc_frsp (code, ins->dreg, ins->sreg1);
3174 * Keep in sync with mono_arch_emit_epilog
3176 g_assert (!cfg->method->save_lmf);
3178 * Note: we can use ppc_r11 here because it is dead anyway:
3179 * we're leaving the method.
3181 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3182 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3183 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3185 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3186 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3188 ppc_mtlr (code, ppc_r0);
3191 code = emit_load_volatile_arguments (cfg, code);
3193 if (ppc_is_imm16 (cfg->stack_usage)) {
3194 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3196 ppc_load (code, ppc_r11, cfg->stack_usage);
3197 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3199 if (!cfg->method->save_lmf) {
3200 /*for (i = 31; i >= 14; --i) {
3201 if (cfg->used_float_regs & (1 << i)) {
3202 pos += sizeof (double);
3203 ppc_lfd (code, i, -pos, cfg->frame_reg);
3206 /* FIXME: restore registers before changing ppc_sp */
3207 for (i = 31; i >= 13; --i) {
3208 if (cfg->used_int_regs & (1 << i)) {
3209 pos += sizeof (gulong);
3210 ppc_lwz (code, i, -pos, ppc_sp);
3214 /* FIXME restore from MonoLMF: though this can't happen yet */
3216 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3221 /* ensure ins->sreg1 is not NULL */
3222 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3225 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3226 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3228 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3229 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3231 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3240 call = (MonoCallInst*)ins;
3241 if (ins->flags & MONO_INST_HAS_METHOD)
3242 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3244 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3245 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3246 ppc_lis (code, ppc_r0, 0);
3247 ppc_ori (code, ppc_r0, ppc_r0, 0);
3248 ppc_mtlr (code, ppc_r0);
3253 /* FIXME: this should be handled somewhere else in the new jit */
3254 code = emit_move_return_value (cfg, ins, code);
3260 case OP_VOIDCALL_REG:
3262 ppc_mtlr (code, ins->sreg1);
3264 /* FIXME: this should be handled somewhere else in the new jit */
3265 code = emit_move_return_value (cfg, ins, code);
3267 case OP_FCALL_MEMBASE:
3268 case OP_LCALL_MEMBASE:
3269 case OP_VCALL_MEMBASE:
3270 case OP_VCALL2_MEMBASE:
3271 case OP_VOIDCALL_MEMBASE:
3272 case OP_CALL_MEMBASE:
3273 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3274 ppc_mtlr (code, ppc_r0);
3276 /* FIXME: this should be handled somewhere else in the new jit */
3277 code = emit_move_return_value (cfg, ins, code);
3280 guint8 * zero_loop_jump, * zero_loop_start;
3281 /* keep alignment */
3282 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3283 int area_offset = alloca_waste;
3285 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3286 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3287 /* use ctr to store the number of words to 0 if needed */
3288 if (ins->flags & MONO_INST_INIT) {
3289 /* we zero 4 bytes at a time:
3290 * we add 7 instead of 3 so that we set the counter to
3291 * at least 1, otherwise the bdnz instruction will make
3292 * it negative and iterate billions of times.
3294 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3295 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3296 ppc_mtctr (code, ppc_r0);
3298 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3299 ppc_neg (code, ppc_r11, ppc_r11);
3300 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3302 if (ins->flags & MONO_INST_INIT) {
3303 /* adjust the dest reg by -4 so we can use stwu */
3304 /* we actually adjust -8 because we let the loop
3307 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3308 ppc_li (code, ppc_r11, 0);
3309 zero_loop_start = code;
3310 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3311 zero_loop_jump = code;
3312 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3313 ppc_patch (zero_loop_jump, zero_loop_start);
3315 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3320 ppc_mr (code, ppc_r3, ins->sreg1);
3321 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3322 (gpointer)"mono_arch_throw_exception");
3323 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3324 ppc_lis (code, ppc_r0, 0);
3325 ppc_ori (code, ppc_r0, ppc_r0, 0);
3326 ppc_mtlr (code, ppc_r0);
3335 ppc_mr (code, ppc_r3, ins->sreg1);
3336 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3337 (gpointer)"mono_arch_rethrow_exception");
3338 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3339 ppc_lis (code, ppc_r0, 0);
3340 ppc_ori (code, ppc_r0, ppc_r0, 0);
3341 ppc_mtlr (code, ppc_r0);
3348 case OP_START_HANDLER: {
3349 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3350 g_assert (spvar->inst_basereg != ppc_sp);
3351 code = emit_reserve_param_area (cfg, code);
3352 ppc_mflr (code, ppc_r0);
3353 if (ppc_is_imm16 (spvar->inst_offset)) {
3354 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3356 ppc_load (code, ppc_r11, spvar->inst_offset);
3357 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3361 case OP_ENDFILTER: {
3362 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3363 g_assert (spvar->inst_basereg != ppc_sp);
3364 code = emit_unreserve_param_area (cfg, code);
3365 if (ins->sreg1 != ppc_r3)
3366 ppc_mr (code, ppc_r3, ins->sreg1);
3367 if (ppc_is_imm16 (spvar->inst_offset)) {
3368 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3370 ppc_load (code, ppc_r11, spvar->inst_offset);
3371 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3373 ppc_mtlr (code, ppc_r0);
3377 case OP_ENDFINALLY: {
3378 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3379 g_assert (spvar->inst_basereg != ppc_sp);
3380 code = emit_unreserve_param_area (cfg, code);
3381 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3382 ppc_mtlr (code, ppc_r0);
3386 case OP_CALL_HANDLER:
3387 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3391 ins->inst_c0 = code - cfg->native_code;
3394 if (ins->flags & MONO_INST_BRLABEL) {
3395 /*if (ins->inst_i0->inst_c0) {
3397 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3399 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3403 /*if (ins->inst_target_bb->native_offset) {
3405 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3407 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3413 ppc_mtctr (code, ins->sreg1);
3414 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3418 ppc_li (code, ins->dreg, 0);
3419 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3420 ppc_li (code, ins->dreg, 1);
3426 ppc_li (code, ins->dreg, 1);
3427 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3428 ppc_li (code, ins->dreg, 0);
3434 ppc_li (code, ins->dreg, 1);
3435 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3436 ppc_li (code, ins->dreg, 0);
3438 case OP_COND_EXC_EQ:
3439 case OP_COND_EXC_NE_UN:
3440 case OP_COND_EXC_LT:
3441 case OP_COND_EXC_LT_UN:
3442 case OP_COND_EXC_GT:
3443 case OP_COND_EXC_GT_UN:
3444 case OP_COND_EXC_GE:
3445 case OP_COND_EXC_GE_UN:
3446 case OP_COND_EXC_LE:
3447 case OP_COND_EXC_LE_UN:
3448 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3450 case OP_COND_EXC_IEQ:
3451 case OP_COND_EXC_INE_UN:
3452 case OP_COND_EXC_ILT:
3453 case OP_COND_EXC_ILT_UN:
3454 case OP_COND_EXC_IGT:
3455 case OP_COND_EXC_IGT_UN:
3456 case OP_COND_EXC_IGE:
3457 case OP_COND_EXC_IGE_UN:
3458 case OP_COND_EXC_ILE:
3459 case OP_COND_EXC_ILE_UN:
3460 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3463 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3465 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3466 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3467 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3469 case OP_COND_EXC_OV:
3470 /*ppc_mcrxr (code, 0);
3471 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3473 case OP_COND_EXC_NC:
3474 case OP_COND_EXC_NO:
3475 g_assert_not_reached ();
3487 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3490 /* floating point opcodes */
3493 g_assert_not_reached ();
3494 case OP_STORER8_MEMBASE_REG:
3495 if (ppc_is_imm16 (ins->inst_offset)) {
3496 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3498 ppc_load (code, ppc_r0, ins->inst_offset);
3499 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3502 case OP_LOADR8_MEMBASE:
3503 if (ppc_is_imm16 (ins->inst_offset)) {
3504 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3506 ppc_load (code, ppc_r0, ins->inst_offset);
3507 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3510 case OP_STORER4_MEMBASE_REG:
3511 ppc_frsp (code, ins->sreg1, ins->sreg1);
3512 if (ppc_is_imm16 (ins->inst_offset)) {
3513 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3515 ppc_load (code, ppc_r0, ins->inst_offset);
3516 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3519 case OP_LOADR4_MEMBASE:
3520 if (ppc_is_imm16 (ins->inst_offset)) {
3521 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3523 ppc_load (code, ppc_r0, ins->inst_offset);
3524 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3527 case OP_LOADR4_MEMINDEX:
3528 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3530 case OP_LOADR8_MEMINDEX:
3531 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3533 case OP_STORER4_MEMINDEX:
3534 ppc_frsp (code, ins->sreg1, ins->sreg1);
3535 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3537 case OP_STORER8_MEMINDEX:
3538 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3541 case CEE_CONV_R4: /* FIXME: change precision */
3543 g_assert_not_reached ();
3544 case OP_FCONV_TO_I1:
3545 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3547 case OP_FCONV_TO_U1:
3548 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3550 case OP_FCONV_TO_I2:
3551 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3553 case OP_FCONV_TO_U2:
3554 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3556 case OP_FCONV_TO_I4:
3558 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3560 case OP_FCONV_TO_U4:
3562 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3564 case OP_FCONV_TO_I8:
3565 case OP_FCONV_TO_U8:
3566 g_assert_not_reached ();
3567 /* Implemented as helper calls */
3569 case OP_LCONV_TO_R_UN:
3570 g_assert_not_reached ();
3571 /* Implemented as helper calls */
3573 case OP_LCONV_TO_OVF_I4_2:
3574 case OP_LCONV_TO_OVF_I: {
3575 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3576 // Check if its negative
3577 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3578 negative_branch = code;
3579 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3580 // Its positive msword == 0
3581 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3582 msword_positive_branch = code;
3583 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3585 ovf_ex_target = code;
3586 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3588 ppc_patch (negative_branch, code);
3589 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3590 msword_negative_branch = code;
3591 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3592 ppc_patch (msword_negative_branch, ovf_ex_target);
3594 ppc_patch (msword_positive_branch, code);
3595 if (ins->dreg != ins->sreg1)
3596 ppc_mr (code, ins->dreg, ins->sreg1);
3600 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3603 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3606 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3612 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 ppc_fneg (code, ins->dreg, ins->sreg1);
3619 g_assert_not_reached ();
3622 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3625 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3626 ppc_li (code, ins->dreg, 0);
3627 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3628 ppc_li (code, ins->dreg, 1);
3631 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3632 ppc_li (code, ins->dreg, 1);
3633 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3634 ppc_li (code, ins->dreg, 0);
3637 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3638 ppc_li (code, ins->dreg, 1);
3639 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3640 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3641 ppc_li (code, ins->dreg, 0);
3644 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3645 ppc_li (code, ins->dreg, 1);
3646 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3647 ppc_li (code, ins->dreg, 0);
3650 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3651 ppc_li (code, ins->dreg, 1);
3652 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3653 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3654 ppc_li (code, ins->dreg, 0);
3657 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3660 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3663 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3664 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3667 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3668 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3671 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3672 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3675 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3676 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3679 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3680 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3683 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3686 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3687 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3690 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3693 g_assert_not_reached ();
3694 case OP_CHECK_FINITE: {
3695 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3696 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3697 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3698 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3701 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3702 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3706 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3707 g_assert_not_reached ();
3710 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3711 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3712 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3713 g_assert_not_reached ();
3719 last_offset = offset;
3722 cfg->code_len = code - cfg->native_code;
3726 mono_arch_register_lowlevel_calls (void)
3730 #define patch_lis_ori(ip,val) do {\
3731 guint16 *__lis_ori = (guint16*)(ip); \
3732 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3733 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3737 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3739 MonoJumpInfo *patch_info;
3741 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3742 unsigned char *ip = patch_info->ip.i + code;
3743 unsigned char *target;
3745 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3747 switch (patch_info->type) {
3748 case MONO_PATCH_INFO_IP:
3749 patch_lis_ori (ip, ip);
3751 case MONO_PATCH_INFO_METHOD_REL:
3752 g_assert_not_reached ();
3753 *((gpointer *)(ip)) = code + patch_info->data.offset;
3755 case MONO_PATCH_INFO_SWITCH: {
3756 gpointer *table = (gpointer *)patch_info->data.table->table;
3759 patch_lis_ori (ip, table);
3761 for (i = 0; i < patch_info->data.table->table_size; i++) {
3762 table [i] = (int)patch_info->data.table->table [i] + code;
3764 /* we put into the table the absolute address, no need for ppc_patch in this case */
3767 case MONO_PATCH_INFO_METHODCONST:
3768 case MONO_PATCH_INFO_CLASS:
3769 case MONO_PATCH_INFO_IMAGE:
3770 case MONO_PATCH_INFO_FIELD:
3771 case MONO_PATCH_INFO_VTABLE:
3772 case MONO_PATCH_INFO_IID:
3773 case MONO_PATCH_INFO_SFLDA:
3774 case MONO_PATCH_INFO_LDSTR:
3775 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3776 case MONO_PATCH_INFO_LDTOKEN:
3777 /* from OP_AOTCONST : lis + ori */
3778 patch_lis_ori (ip, target);
3780 case MONO_PATCH_INFO_R4:
3781 case MONO_PATCH_INFO_R8:
3782 g_assert_not_reached ();
3783 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3785 case MONO_PATCH_INFO_EXC_NAME:
3786 g_assert_not_reached ();
3787 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3789 case MONO_PATCH_INFO_NONE:
3790 case MONO_PATCH_INFO_BB_OVF:
3791 case MONO_PATCH_INFO_EXC_OVF:
3792 /* everything is dealt with at epilog output time */
3797 ppc_patch (ip, target);
3802 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
3803 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
3804 * the instruction offset immediate for all the registers.
3807 save_registers (guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs)
3811 for (i = 13; i <= 31; i++) {
3812 if (used_int_regs & (1 << i)) {
3813 ppc_stw (code, i, pos, base_reg);
3814 pos += sizeof (gulong);
3818 /* pos is the start of the MonoLMF structure */
3819 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
3820 for (i = 13; i <= 31; i++) {
3821 ppc_stw (code, i, offset, base_reg);
3822 offset += sizeof (gulong);
3824 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
3825 for (i = 14; i < 32; i++) {
3826 ppc_stfd (code, i, offset, base_reg);
3827 offset += sizeof (gdouble);
3834 * Stack frame layout:
3836 * ------------------- sp
3837 * MonoLMF structure or saved registers
3838 * -------------------
3840 * -------------------
3842 * -------------------
3843 * optional 8 bytes for tracing
3844 * -------------------
3845 * param area size is cfg->param_area
3846 * -------------------
3847 * linkage area size is PPC_STACK_PARAM_OFFSET
3848 * ------------------- sp
3852 mono_arch_emit_prolog (MonoCompile *cfg)
3854 MonoMethod *method = cfg->method;
3856 MonoMethodSignature *sig;
3858 int alloc_size, pos, max_offset, i;
3863 int tailcall_struct_index;
3865 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3868 sig = mono_method_signature (method);
3869 cfg->code_size = 256 + sig->param_count * 20;
3870 code = cfg->native_code = g_malloc (cfg->code_size);
3872 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3873 ppc_mflr (code, ppc_r0);
3874 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3877 alloc_size = cfg->stack_offset;
3880 if (!method->save_lmf) {
3881 for (i = 31; i >= 13; --i) {
3882 if (cfg->used_int_regs & (1 << i)) {
3883 pos += sizeof (gulong);
3887 pos += sizeof (MonoLMF);
3891 // align to PPC_STACK_ALIGNMENT bytes
3892 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3893 alloc_size += PPC_STACK_ALIGNMENT - 1;
3894 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3897 cfg->stack_usage = alloc_size;
3898 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3900 if (ppc_is_imm16 (-alloc_size)) {
3901 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3902 code = save_registers (code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs);
3905 ppc_addi (code, ppc_r11, ppc_sp, -pos);
3906 ppc_load (code, ppc_r0, -alloc_size);
3907 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r0);
3908 code = save_registers (code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs);
3911 if (cfg->frame_reg != ppc_sp)
3912 ppc_mr (code, cfg->frame_reg, ppc_sp);
3914 /* store runtime generic context */
3915 if (cfg->rgctx_var) {
3916 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3917 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3919 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3922 /* compute max_offset in order to use short forward jumps
3923 * we always do it on ppc because the immediate displacement
3924 * for jumps is too small
3927 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3929 bb->max_offset = max_offset;
3931 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3934 MONO_BB_FOR_EACH_INS (bb, ins)
3935 max_offset += ins_native_length (cfg, ins);
3938 /* load arguments allocated to register from the stack */
3941 cinfo = calculate_sizes (sig, sig->pinvoke);
3943 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3944 ArgInfo *ainfo = &cinfo->ret;
3946 inst = cfg->vret_addr;
3949 if (ppc_is_imm16 (inst->inst_offset)) {
3950 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3952 ppc_load (code, ppc_r11, inst->inst_offset);
3953 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3957 tailcall_struct_index = 0;
3958 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3959 ArgInfo *ainfo = cinfo->args + i;
3960 inst = cfg->args [pos];
3962 if (cfg->verbose_level > 2)
3963 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3964 if (inst->opcode == OP_REGVAR) {
3965 if (ainfo->regtype == RegTypeGeneral)
3966 ppc_mr (code, inst->dreg, ainfo->reg);
3967 else if (ainfo->regtype == RegTypeFP)
3968 ppc_fmr (code, inst->dreg, ainfo->reg);
3969 else if (ainfo->regtype == RegTypeBase) {
3970 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3971 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3973 g_assert_not_reached ();
3975 if (cfg->verbose_level > 2)
3976 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3978 /* the argument should be put on the stack: FIXME handle size != word */
3979 if (ainfo->regtype == RegTypeGeneral) {
3980 switch (ainfo->size) {
3982 if (ppc_is_imm16 (inst->inst_offset)) {
3983 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3985 ppc_load (code, ppc_r11, inst->inst_offset);
3986 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3990 if (ppc_is_imm16 (inst->inst_offset)) {
3991 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3993 ppc_load (code, ppc_r11, inst->inst_offset);
3994 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3998 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3999 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4000 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4002 ppc_load (code, ppc_r11, inst->inst_offset);
4003 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4004 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4005 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4009 if (ppc_is_imm16 (inst->inst_offset)) {
4010 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4012 ppc_load (code, ppc_r11, inst->inst_offset);
4013 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4017 } else if (ainfo->regtype == RegTypeBase) {
4018 /* load the previous stack pointer in r11 */
4019 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4020 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4021 switch (ainfo->size) {
4023 if (ppc_is_imm16 (inst->inst_offset)) {
4024 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4026 ppc_load (code, ppc_r11, inst->inst_offset);
4027 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4031 if (ppc_is_imm16 (inst->inst_offset)) {
4032 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4034 ppc_load (code, ppc_r11, inst->inst_offset);
4035 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4039 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4040 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4041 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4042 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4045 g_assert_not_reached ();
4049 if (ppc_is_imm16 (inst->inst_offset)) {
4050 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4052 ppc_load (code, ppc_r11, inst->inst_offset);
4053 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4057 } else if (ainfo->regtype == RegTypeFP) {
4058 g_assert (ppc_is_imm16 (inst->inst_offset));
4059 if (ainfo->size == 8)
4060 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4061 else if (ainfo->size == 4)
4062 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4064 g_assert_not_reached ();
4065 } else if (ainfo->regtype == RegTypeStructByVal) {
4066 int doffset = inst->inst_offset;
4070 g_assert (ppc_is_imm16 (inst->inst_offset));
4071 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4072 /* FIXME: what if there is no class? */
4073 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4074 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4075 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4078 * Darwin handles 1 and 2 byte
4079 * structs specially by
4080 * loading h/b into the arg
4081 * register. Only done for
4085 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4087 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4090 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4091 soffset += sizeof (gpointer);
4092 doffset += sizeof (gpointer);
4094 if (ainfo->vtsize) {
4095 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4096 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4097 if ((size & 3) != 0) {
4098 code = emit_memcpy (code, size - soffset,
4099 inst->inst_basereg, doffset,
4100 ppc_r11, ainfo->offset + soffset);
4102 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4103 inst->inst_basereg, doffset,
4104 ppc_r11, ainfo->offset + soffset);
4107 } else if (ainfo->regtype == RegTypeStructByAddr) {
4108 /* if it was originally a RegTypeBase */
4109 if (ainfo->offset) {
4110 /* load the previous stack pointer in r11 */
4111 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4112 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4114 ppc_mr (code, ppc_r11, ainfo->reg);
4117 if (cfg->tailcall_valuetype_addrs) {
4118 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4120 g_assert (ppc_is_imm16 (addr->inst_offset));
4121 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4123 tailcall_struct_index++;
4126 g_assert (ppc_is_imm16 (inst->inst_offset));
4127 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4128 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4130 g_assert_not_reached ();
4135 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4136 ppc_load (code, ppc_r3, cfg->domain);
4137 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4138 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4139 ppc_lis (code, ppc_r0, 0);
4140 ppc_ori (code, ppc_r0, ppc_r0, 0);
4141 ppc_mtlr (code, ppc_r0);
4148 if (method->save_lmf) {
4149 if (lmf_pthread_key != -1) {
4150 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4151 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4152 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4154 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4155 (gpointer)"mono_get_lmf_addr");
4156 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4157 ppc_lis (code, ppc_r0, 0);
4158 ppc_ori (code, ppc_r0, ppc_r0, 0);
4159 ppc_mtlr (code, ppc_r0);
4165 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4166 /* lmf_offset is the offset from the previous stack pointer,
4167 * alloc_size is the total stack space allocated, so the offset
4168 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4169 * The pointer to the struct is put in ppc_r11 (new_lmf).
4170 * The callee-saved registers are already in the MonoLMF structure
4172 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4173 /* ppc_r3 is the result from mono_get_lmf_addr () */
4174 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4175 /* new_lmf->previous_lmf = *lmf_addr */
4176 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4177 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4178 /* *(lmf_addr) = r11 */
4179 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4180 /* save method info */
4181 ppc_load (code, ppc_r0, method);
4182 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4183 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4184 /* save the current IP */
4185 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4186 ppc_load (code, ppc_r0, 0x01010101);
4187 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4191 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4193 cfg->code_len = code - cfg->native_code;
4194 g_assert (cfg->code_len < cfg->code_size);
4201 mono_arch_emit_epilog (MonoCompile *cfg)
4203 MonoMethod *method = cfg->method;
4205 int max_epilog_size = 16 + 20*4;
4208 if (cfg->method->save_lmf)
4209 max_epilog_size += 128;
4211 if (mono_jit_trace_calls != NULL)
4212 max_epilog_size += 50;
4214 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4215 max_epilog_size += 50;
4217 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4218 cfg->code_size *= 2;
4219 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4220 mono_jit_stats.code_reallocs++;
4224 * Keep in sync with OP_JMP
4226 code = cfg->native_code + cfg->code_len;
4228 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4229 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4233 if (method->save_lmf) {
4235 pos += sizeof (MonoLMF);
4237 /* save the frame reg in r8 */
4238 ppc_mr (code, ppc_r8, cfg->frame_reg);
4239 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4240 /* r5 = previous_lmf */
4241 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4243 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4244 /* *(lmf_addr) = previous_lmf */
4245 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4246 /* FIXME: speedup: there is no actual need to restore the registers if
4247 * we didn't actually change them (idea from Zoltan).
4250 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4252 /*for (i = 14; i < 32; i++) {
4253 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4255 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4256 /* use the saved copy of the frame reg in r8 */
4257 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4258 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4259 ppc_mtlr (code, ppc_r0);
4261 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4263 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4264 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4265 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4267 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4268 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4270 ppc_mtlr (code, ppc_r0);
4272 if (ppc_is_imm16 (cfg->stack_usage)) {
4273 int offset = cfg->stack_usage;
4274 for (i = 13; i <= 31; i++) {
4275 if (cfg->used_int_regs & (1 << i))
4276 offset -= sizeof (gulong);
4278 if (cfg->frame_reg != ppc_sp)
4279 ppc_mr (code, ppc_r11, cfg->frame_reg);
4280 /* note r31 (possibly the frame register) is restored last */
4281 for (i = 13; i <= 31; i++) {
4282 if (cfg->used_int_regs & (1 << i)) {
4283 ppc_lwz (code, i, offset, cfg->frame_reg);
4284 offset += sizeof (gulong);
4287 if (cfg->frame_reg != ppc_sp)
4288 ppc_addic (code, ppc_sp, ppc_r11, cfg->stack_usage);
4290 ppc_addic (code, ppc_sp, ppc_sp, cfg->stack_usage);
4292 ppc_load (code, ppc_r11, cfg->stack_usage);
4293 if (cfg->used_int_regs) {
4294 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
4295 for (i = 31; i >= 13; --i) {
4296 if (cfg->used_int_regs & (1 << i)) {
4297 pos += sizeof (gulong);
4298 ppc_lwz (code, i, -pos, ppc_r11);
4301 ppc_mr (code, ppc_sp, ppc_r11);
4303 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4310 cfg->code_len = code - cfg->native_code;
4312 g_assert (cfg->code_len < cfg->code_size);
4316 /* remove once throw_exception_by_name is eliminated */
4318 exception_id_by_name (const char *name)
4320 if (strcmp (name, "IndexOutOfRangeException") == 0)
4321 return MONO_EXC_INDEX_OUT_OF_RANGE;
4322 if (strcmp (name, "OverflowException") == 0)
4323 return MONO_EXC_OVERFLOW;
4324 if (strcmp (name, "ArithmeticException") == 0)
4325 return MONO_EXC_ARITHMETIC;
4326 if (strcmp (name, "DivideByZeroException") == 0)
4327 return MONO_EXC_DIVIDE_BY_ZERO;
4328 if (strcmp (name, "InvalidCastException") == 0)
4329 return MONO_EXC_INVALID_CAST;
4330 if (strcmp (name, "NullReferenceException") == 0)
4331 return MONO_EXC_NULL_REF;
4332 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4333 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4334 g_error ("Unknown intrinsic exception %s\n", name);
4339 mono_arch_emit_exceptions (MonoCompile *cfg)
4341 MonoJumpInfo *patch_info;
4344 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4345 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4346 int max_epilog_size = 50;
4348 /* count the number of exception infos */
4351 * make sure we have enough space for exceptions
4352 * 24 is the simulated call to throw_exception_by_name
4354 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4355 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4356 i = exception_id_by_name (patch_info->data.target);
4357 if (!exc_throw_found [i]) {
4358 max_epilog_size += 24;
4359 exc_throw_found [i] = TRUE;
4361 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4362 max_epilog_size += 12;
4363 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4364 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4365 i = exception_id_by_name (ovfj->data.exception);
4366 if (!exc_throw_found [i]) {
4367 max_epilog_size += 24;
4368 exc_throw_found [i] = TRUE;
4370 max_epilog_size += 8;
4374 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4375 cfg->code_size *= 2;
4376 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4377 mono_jit_stats.code_reallocs++;
4380 code = cfg->native_code + cfg->code_len;
4382 /* add code to raise exceptions */
4383 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4384 switch (patch_info->type) {
4385 case MONO_PATCH_INFO_BB_OVF: {
4386 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4387 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4388 /* patch the initial jump */
4389 ppc_patch (ip, code);
4390 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4392 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4393 /* jump back to the true target */
4395 ip = ovfj->data.bb->native_offset + cfg->native_code;
4396 ppc_patch (code - 4, ip);
4399 case MONO_PATCH_INFO_EXC_OVF: {
4400 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4401 MonoJumpInfo *newji;
4402 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4403 unsigned char *bcl = code;
4404 /* patch the initial jump: we arrived here with a call */
4405 ppc_patch (ip, code);
4406 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4408 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4409 /* patch the conditional jump to the right handler */
4410 /* make it processed next */
4411 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4412 newji->type = MONO_PATCH_INFO_EXC;
4413 newji->ip.i = bcl - cfg->native_code;
4414 newji->data.target = ovfj->data.exception;
4415 newji->next = patch_info->next;
4416 patch_info->next = newji;
4419 case MONO_PATCH_INFO_EXC: {
4420 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4421 i = exception_id_by_name (patch_info->data.target);
4422 if (exc_throw_pos [i]) {
4423 ppc_patch (ip, exc_throw_pos [i]);
4424 patch_info->type = MONO_PATCH_INFO_NONE;
4427 exc_throw_pos [i] = code;
4429 ppc_patch (ip, code);
4430 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4431 ppc_load (code, ppc_r3, patch_info->data.target);
4432 /* we got here from a conditional call, so the calling ip is set in lr already */
4433 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4434 patch_info->data.name = "mono_arch_throw_exception_by_name";
4435 patch_info->ip.i = code - cfg->native_code;
4436 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4437 ppc_lis (code, ppc_r0, 0);
4438 ppc_ori (code, ppc_r0, ppc_r0, 0);
4439 ppc_mtctr (code, ppc_r0);
4440 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4452 cfg->code_len = code - cfg->native_code;
4454 g_assert (cfg->code_len < cfg->code_size);
4459 try_offset_access (void *value, guint32 idx)
4461 register void* me __asm__ ("r2");
4462 void ***p = (void***)((char*)me + 284);
4463 int idx1 = idx / 32;
4464 int idx2 = idx % 32;
4467 if (value != p[idx1][idx2])
4473 setup_tls_access (void)
4476 guint32 *ins, *code;
4477 guint32 cmplwi_1023, li_0x48, blr_ins;
4478 if (tls_mode == TLS_MODE_FAILED)
4481 if (g_getenv ("MONO_NO_TLS")) {
4482 tls_mode = TLS_MODE_FAILED;
4486 if (tls_mode == TLS_MODE_DETECT) {
4487 ins = (guint32*)pthread_getspecific;
4488 /* uncond branch to the real method */
4489 if ((*ins >> 26) == 18) {
4491 val = (*ins & ~3) << 6;
4495 ins = (guint32*)val;
4497 ins = (guint32*) ((char*)ins + val);
4500 code = &cmplwi_1023;
4501 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4503 ppc_li (code, ppc_r4, 0x48);
4506 if (*ins == cmplwi_1023) {
4507 int found_lwz_284 = 0;
4508 for (ptk = 0; ptk < 20; ++ptk) {
4510 if (!*ins || *ins == blr_ins)
4512 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4517 if (!found_lwz_284) {
4518 tls_mode = TLS_MODE_FAILED;
4521 tls_mode = TLS_MODE_LTHREADS;
4522 } else if (*ins == li_0x48) {
4524 /* uncond branch to the real method */
4525 if ((*ins >> 26) == 18) {
4527 val = (*ins & ~3) << 6;
4531 ins = (guint32*)val;
4533 ins = (guint32*) ((char*)ins + val);
4535 code = (guint32*)&val;
4536 ppc_li (code, ppc_r0, 0x7FF2);
4537 if (ins [1] == val) {
4538 /* Darwin on G4, implement */
4539 tls_mode = TLS_MODE_FAILED;
4542 code = (guint32*)&val;
4543 ppc_mfspr (code, ppc_r3, 104);
4544 if (ins [1] != val) {
4545 tls_mode = TLS_MODE_FAILED;
4548 tls_mode = TLS_MODE_DARWIN_G5;
4551 tls_mode = TLS_MODE_FAILED;
4555 tls_mode = TLS_MODE_FAILED;
4559 if (monodomain_key == -1) {
4560 ptk = mono_domain_get_tls_key ();
4562 ptk = mono_pthread_key_for_tls (ptk);
4564 monodomain_key = ptk;
4568 if (lmf_pthread_key == -1) {
4569 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4571 /*g_print ("MonoLMF at: %d\n", ptk);*/
4572 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4573 init_tls_failed = 1;
4576 lmf_pthread_key = ptk;
4579 if (monothread_key == -1) {
4580 ptk = mono_thread_get_tls_key ();
4582 ptk = mono_pthread_key_for_tls (ptk);
4584 monothread_key = ptk;
4585 /*g_print ("thread inited: %d\n", ptk);*/
4588 /*g_print ("thread not inited yet %d\n", ptk);*/
4594 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4596 setup_tls_access ();
4600 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4604 #ifdef MONO_ARCH_HAVE_IMT
4608 #define JUMP_IMM_SIZE 12
4609 #define JUMP_IMM32_SIZE 16
4610 #define ENABLE_WRONG_METHOD_CHECK 0
4613 * LOCKING: called with the domain lock held
4616 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4617 gpointer fail_tramp)
4621 guint8 *code, *start;
4623 for (i = 0; i < count; ++i) {
4624 MonoIMTCheckItem *item = imt_entries [i];
4625 if (item->is_equals) {
4626 if (item->check_target_idx) {
4627 if (!item->compare_done)
4628 item->chunk_size += CMP_SIZE;
4630 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4632 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4635 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4637 item->chunk_size += JUMP_IMM_SIZE;
4638 #if ENABLE_WRONG_METHOD_CHECK
4639 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4644 item->chunk_size += CMP_SIZE + BR_SIZE;
4645 imt_entries [item->check_target_idx]->compare_done = TRUE;
4647 size += item->chunk_size;
4650 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4652 /* the initial load of the vtable address */
4654 code = mono_code_manager_reserve (domain->code_mp, size);
4658 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4659 for (i = 0; i < count; ++i) {
4660 MonoIMTCheckItem *item = imt_entries [i];
4661 item->code_target = code;
4662 if (item->is_equals) {
4663 if (item->check_target_idx) {
4664 if (!item->compare_done) {
4665 ppc_load (code, ppc_r0, (guint32)item->key);
4666 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4668 item->jmp_code = code;
4669 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4671 ppc_load (code, ppc_r0, item->value.target_code);
4673 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4674 ppc_mtctr (code, ppc_r0);
4675 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4678 ppc_load (code, ppc_r0, (guint32)item->key);
4679 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4680 item->jmp_code = code;
4681 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4682 ppc_load (code, ppc_r0, item->value.target_code);
4683 ppc_mtctr (code, ppc_r0);
4684 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4685 ppc_patch (item->jmp_code, code);
4686 ppc_load (code, ppc_r0, fail_tramp);
4687 ppc_mtctr (code, ppc_r0);
4688 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4689 item->jmp_code = NULL;
4691 /* enable the commented code to assert on wrong method */
4692 #if ENABLE_WRONG_METHOD_CHECK
4693 ppc_load (code, ppc_r0, (guint32)item->key);
4694 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4695 item->jmp_code = code;
4696 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4698 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4699 ppc_mtctr (code, ppc_r0);
4700 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4701 #if ENABLE_WRONG_METHOD_CHECK
4702 ppc_patch (item->jmp_code, code);
4704 item->jmp_code = NULL;
4709 ppc_load (code, ppc_r0, (guint32)item->key);
4710 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4711 item->jmp_code = code;
4712 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4715 /* patch the branches to get to the target items */
4716 for (i = 0; i < count; ++i) {
4717 MonoIMTCheckItem *item = imt_entries [i];
4718 if (item->jmp_code) {
4719 if (item->check_target_idx) {
4720 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4726 mono_stats.imt_thunks_size += code - start;
4727 g_assert (code - start <= size);
4728 mono_arch_flush_icache (start, size);
4733 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4735 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4739 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4741 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4746 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4748 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4752 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4759 mono_arch_print_tree (MonoInst *tree, int arity)
4764 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4768 setup_tls_access ();
4769 if (monodomain_key == -1)
4772 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4773 ins->inst_offset = monodomain_key;
4778 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4782 setup_tls_access ();
4783 if (monothread_key == -1)
4786 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4787 ins->inst_offset = monothread_key;
4792 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4794 g_assert (reg >= ppc_r13);
4796 return (gpointer)ctx->regs [reg - ppc_r13];