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 int mono_exc_esp_offset = 0;
36 static int tls_mode = TLS_MODE_DETECT;
37 static int lmf_pthread_key = -1;
38 static int monothread_key = -1;
39 static int monodomain_key = -1;
42 offsets_from_pthread_key (guint32 key, int *offset2)
46 *offset2 = idx2 * sizeof (gpointer);
47 return 284 + idx1 * sizeof (gpointer);
50 #define emit_linuxthreads_tls(code,dreg,key) do {\
52 off1 = offsets_from_pthread_key ((key), &off2); \
53 ppc_lwz ((code), (dreg), off1, ppc_r2); \
54 ppc_lwz ((code), (dreg), off2, (dreg)); \
57 #define emit_darwing5_tls(code,dreg,key) do {\
58 int off1 = 0x48 + key * sizeof (gpointer); \
59 ppc_mfspr ((code), (dreg), 104); \
60 ppc_lwz ((code), (dreg), off1, (dreg)); \
63 /* FIXME: ensure the sc call preserves all but r3 */
64 #define emit_darwing4_tls(code,dreg,key) do {\
65 int off1 = 0x48 + key * sizeof (gpointer); \
66 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
67 ppc_li ((code), ppc_r0, 0x7FF2); \
69 ppc_lwz ((code), (dreg), off1, ppc_r3); \
70 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
73 #define emit_tls_access(code,dreg,key) do { \
75 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
76 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
77 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
78 default: g_assert_not_reached (); \
83 mono_arch_regname (int reg) {
84 static const char rnames[][4] = {
85 "r0", "sp", "r2", "r3", "r4",
86 "r5", "r6", "r7", "r8", "r9",
87 "r10", "r11", "r12", "r13", "r14",
88 "r15", "r16", "r17", "r18", "r19",
89 "r20", "r21", "r22", "r23", "r24",
90 "r25", "r26", "r27", "r28", "r29",
93 if (reg >= 0 && reg < 32)
99 mono_arch_fregname (int reg) {
100 static const char rnames[][4] = {
101 "f0", "f1", "f2", "f3", "f4",
102 "f5", "f6", "f7", "f8", "f9",
103 "f10", "f11", "f12", "f13", "f14",
104 "f15", "f16", "f17", "f18", "f19",
105 "f20", "f21", "f22", "f23", "f24",
106 "f25", "f26", "f27", "f28", "f29",
109 if (reg >= 0 && reg < 32)
114 /* this function overwrites r0, r11, r12 */
116 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
118 /* unrolled, use the counter in big */
119 if (size > sizeof (gpointer) * 5) {
120 int shifted = size >> 2;
121 guint8 *copy_loop_start, *copy_loop_jump;
123 ppc_load (code, ppc_r0, shifted);
124 ppc_mtctr (code, ppc_r0);
125 g_assert (sreg == ppc_r11);
126 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
127 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
128 copy_loop_start = code;
129 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
130 ppc_stwu (code, ppc_r0, 4, ppc_r12);
131 copy_loop_jump = code;
132 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
133 ppc_patch (copy_loop_jump, copy_loop_start);
135 doffset = soffset = 0;
139 ppc_lwz (code, ppc_r0, soffset, sreg);
140 ppc_stw (code, ppc_r0, doffset, dreg);
146 ppc_lhz (code, ppc_r0, soffset, sreg);
147 ppc_sth (code, ppc_r0, doffset, dreg);
153 ppc_lbz (code, ppc_r0, soffset, sreg);
154 ppc_stb (code, ppc_r0, doffset, dreg);
163 * mono_arch_get_argument_info:
164 * @csig: a method signature
165 * @param_count: the number of parameters to consider
166 * @arg_info: an array to store the result infos
168 * Gathers information on parameters such as size, alignment and
169 * padding. arg_info should be large enought to hold param_count + 1 entries.
171 * Returns the size of the activation frame.
174 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
176 int k, frame_size = 0;
177 int size, align, pad;
180 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
181 frame_size += sizeof (gpointer);
185 arg_info [0].offset = offset;
188 frame_size += sizeof (gpointer);
192 arg_info [0].size = frame_size;
194 for (k = 0; k < param_count; k++) {
197 size = mono_type_native_stack_size (csig->params [k], &align);
199 size = mono_type_stack_size (csig->params [k], &align);
201 /* ignore alignment for now */
204 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
205 arg_info [k].pad = pad;
207 arg_info [k + 1].pad = 0;
208 arg_info [k + 1].size = size;
210 arg_info [k + 1].offset = offset;
214 align = MONO_ARCH_FRAME_ALIGNMENT;
215 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
216 arg_info [k].pad = pad;
222 * Initialize the cpu to execute managed code.
225 mono_arch_cpu_init (void)
230 * Initialize architecture specific code.
233 mono_arch_init (void)
238 * Cleanup architecture specific code.
241 mono_arch_cleanup (void)
246 * This function returns the optimizations supported on this cpu.
249 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
253 /* no ppc-specific optimizations yet */
259 is_regsize_var (MonoType *t) {
262 t = mono_type_get_underlying_type (t);
269 case MONO_TYPE_FNPTR:
271 case MONO_TYPE_OBJECT:
272 case MONO_TYPE_STRING:
273 case MONO_TYPE_CLASS:
274 case MONO_TYPE_SZARRAY:
275 case MONO_TYPE_ARRAY:
277 case MONO_TYPE_GENERICINST:
278 if (!mono_type_generic_inst_is_valuetype (t))
281 case MONO_TYPE_VALUETYPE:
288 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
293 for (i = 0; i < cfg->num_varinfo; i++) {
294 MonoInst *ins = cfg->varinfo [i];
295 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
298 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
301 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
304 /* we can only allocate 32 bit values */
305 if (is_regsize_var (ins->inst_vtype)) {
306 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
307 g_assert (i == vmv->idx);
308 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
316 mono_arch_get_global_int_regs (MonoCompile *cfg)
320 if (cfg->frame_reg != ppc_sp)
322 /* ppc_r13 is used by the system on PPC EABI */
323 for (i = 14; i < top; ++i)
324 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
330 * mono_arch_regalloc_cost:
332 * Return the cost, in number of memory references, of the action of
333 * allocating the variable VMV into a register during global register
337 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
349 mono_arch_flush_icache (guint8 *code, gint size)
351 guint8 *p, *endp, *start;
352 static int cachelinesize = 0;
353 static int cachelineinc = 16;
355 if (!cachelinesize) {
359 mib [1] = HW_CACHELINE;
360 len = sizeof (cachelinesize);
361 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
365 cachelineinc = cachelinesize;
366 /*g_print ("setting cl size to %d\n", cachelinesize);*/
368 #elif defined(__linux__)
369 /* sadly this will work only with 2.6 kernels... */
370 FILE* f = fopen ("/proc/self/auxv", "rb");
373 while (fread (&vec, sizeof (vec), 1, f) == 1) {
374 if (vec.type == 19) {
375 cachelinesize = vec.value;
384 #warning Need a way to get cache line size
390 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
391 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
393 for (p = start; p < endp; p += cachelineinc) {
394 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
397 for (p = start; p < endp; p += cachelineinc) {
398 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
403 for (p = start; p < endp; p += cachelineinc) {
404 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
410 #define NOT_IMPLEMENTED(x) \
411 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
414 #define ALWAYS_ON_STACK(s) s
415 #define FP_ALSO_IN_REG(s) s
417 #define ALWAYS_ON_STACK(s)
418 #define FP_ALSO_IN_REG(s)
419 #define ALIGN_DOUBLES
432 guint32 vtsize; /* in param area */
434 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
435 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
450 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
453 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
454 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
455 ainfo->reg = ppc_sp; /* in the caller */
456 ainfo->regtype = RegTypeBase;
459 ALWAYS_ON_STACK (*stack_size += 4);
463 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
465 //*stack_size += (*stack_size % 8);
467 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
468 ainfo->reg = ppc_sp; /* in the caller */
469 ainfo->regtype = RegTypeBase;
476 ALWAYS_ON_STACK (*stack_size += 8);
485 /* size == 4 is checked already */
487 has_only_a_r4_field (MonoClass *klass)
492 while ((f = mono_class_get_fields (klass, &iter))) {
493 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
494 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
504 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
507 int n = sig->hasthis + sig->param_count;
509 guint32 stack_size = 0;
510 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
512 fr = PPC_FIRST_FPARG_REG;
513 gr = PPC_FIRST_ARG_REG;
515 /* FIXME: handle returning a struct */
516 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
517 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
518 cinfo->struct_ret = PPC_FIRST_ARG_REG;
523 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
526 DEBUG(printf("params: %d\n", sig->param_count));
527 for (i = 0; i < sig->param_count; ++i) {
528 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
529 /* Prevent implicit arguments and sig_cookie from
530 being passed in registers */
531 gr = PPC_LAST_ARG_REG + 1;
532 /* Emit the signature cookie just before the implicit arguments */
533 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
535 DEBUG(printf("param %d: ", i));
536 if (sig->params [i]->byref) {
537 DEBUG(printf("byref\n"));
538 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
542 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
543 switch (simpletype) {
544 case MONO_TYPE_BOOLEAN:
547 cinfo->args [n].size = 1;
548 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
554 cinfo->args [n].size = 2;
555 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
560 cinfo->args [n].size = 4;
561 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
567 case MONO_TYPE_FNPTR:
568 case MONO_TYPE_CLASS:
569 case MONO_TYPE_OBJECT:
570 case MONO_TYPE_STRING:
571 case MONO_TYPE_SZARRAY:
572 case MONO_TYPE_ARRAY:
573 cinfo->args [n].size = sizeof (gpointer);
574 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
577 case MONO_TYPE_GENERICINST:
578 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
579 cinfo->args [n].size = sizeof (gpointer);
580 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
585 case MONO_TYPE_VALUETYPE: {
588 klass = mono_class_from_mono_type (sig->params [i]);
590 size = mono_class_native_size (klass, NULL);
592 size = mono_class_value_size (klass, NULL);
594 if (size == 4 && has_only_a_r4_field (klass)) {
595 cinfo->args [n].size = 4;
597 /* It was 7, now it is 8 in LinuxPPC */
598 if (fr <= PPC_LAST_FPARG_REG) {
599 cinfo->args [n].regtype = RegTypeFP;
600 cinfo->args [n].reg = fr;
602 FP_ALSO_IN_REG (gr ++);
603 ALWAYS_ON_STACK (stack_size += 4);
605 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
606 cinfo->args [n].regtype = RegTypeBase;
607 cinfo->args [n].reg = ppc_sp; /* in the caller*/
614 DEBUG(printf ("load %d bytes struct\n",
615 mono_class_native_size (sig->params [i]->data.klass, NULL)));
616 #if PPC_PASS_STRUCTS_BY_VALUE
618 int align_size = size;
620 align_size += (sizeof (gpointer) - 1);
621 align_size &= ~(sizeof (gpointer) - 1);
622 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
623 cinfo->args [n].regtype = RegTypeStructByVal;
624 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
625 cinfo->args [n].size = 0;
626 cinfo->args [n].vtsize = nwords;
628 int rest = PPC_LAST_ARG_REG - gr + 1;
629 int n_in_regs = rest >= nwords? nwords: rest;
630 cinfo->args [n].size = n_in_regs;
631 cinfo->args [n].vtsize = nwords - n_in_regs;
632 cinfo->args [n].reg = gr;
635 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
636 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
637 stack_size += nwords * sizeof (gpointer);
640 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
641 cinfo->args [n].regtype = RegTypeStructByAddr;
642 cinfo->args [n].vtsize = size;
647 case MONO_TYPE_TYPEDBYREF: {
648 int size = sizeof (MonoTypedRef);
649 /* keep in sync or merge with the valuetype case */
650 #if PPC_PASS_STRUCTS_BY_VALUE
652 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
653 cinfo->args [n].regtype = RegTypeStructByVal;
654 if (gr <= PPC_LAST_ARG_REG) {
655 int rest = PPC_LAST_ARG_REG - gr + 1;
656 int n_in_regs = rest >= nwords? nwords: rest;
657 cinfo->args [n].size = n_in_regs;
658 cinfo->args [n].vtsize = nwords - n_in_regs;
659 cinfo->args [n].reg = gr;
662 cinfo->args [n].size = 0;
663 cinfo->args [n].vtsize = nwords;
665 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
666 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
667 stack_size += nwords * sizeof (gpointer);
670 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
671 cinfo->args [n].regtype = RegTypeStructByAddr;
672 cinfo->args [n].vtsize = size;
679 cinfo->args [n].size = 8;
680 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
684 cinfo->args [n].size = 4;
686 /* It was 7, now it is 8 in LinuxPPC */
687 if (fr <= PPC_LAST_FPARG_REG) {
688 cinfo->args [n].regtype = RegTypeFP;
689 cinfo->args [n].reg = fr;
691 FP_ALSO_IN_REG (gr ++);
692 ALWAYS_ON_STACK (stack_size += 4);
694 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
695 cinfo->args [n].regtype = RegTypeBase;
696 cinfo->args [n].reg = ppc_sp; /* in the caller*/
702 cinfo->args [n].size = 8;
703 /* It was 7, now it is 8 in LinuxPPC */
704 if (fr <= PPC_LAST_FPARG_REG) {
705 cinfo->args [n].regtype = RegTypeFP;
706 cinfo->args [n].reg = fr;
708 FP_ALSO_IN_REG (gr += 2);
709 ALWAYS_ON_STACK (stack_size += 8);
711 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
712 cinfo->args [n].regtype = RegTypeBase;
713 cinfo->args [n].reg = ppc_sp; /* in the caller*/
719 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
724 simpletype = mono_type_get_underlying_type (sig->ret)->type;
725 switch (simpletype) {
726 case MONO_TYPE_BOOLEAN:
737 case MONO_TYPE_FNPTR:
738 case MONO_TYPE_CLASS:
739 case MONO_TYPE_OBJECT:
740 case MONO_TYPE_SZARRAY:
741 case MONO_TYPE_ARRAY:
742 case MONO_TYPE_STRING:
743 cinfo->ret.reg = ppc_r3;
747 cinfo->ret.reg = ppc_r3;
751 cinfo->ret.reg = ppc_f1;
752 cinfo->ret.regtype = RegTypeFP;
754 case MONO_TYPE_GENERICINST:
755 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
756 cinfo->ret.reg = ppc_r3;
760 case MONO_TYPE_VALUETYPE:
762 case MONO_TYPE_TYPEDBYREF:
766 g_error ("Can't handle as return value 0x%x", sig->ret->type);
770 /* align stack size to 16 */
771 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
772 stack_size = (stack_size + 15) & ~15;
774 cinfo->stack_usage = stack_size;
780 * Set var information according to the calling convention. ppc version.
781 * The locals var stuff should most likely be split in another method.
784 mono_arch_allocate_vars (MonoCompile *m)
786 MonoMethodSignature *sig;
787 MonoMethodHeader *header;
789 int i, offset, size, align, curinst;
790 int frame_reg = ppc_sp;
792 m->flags |= MONO_CFG_HAS_SPILLUP;
794 /* allow room for the vararg method args: void* and long/double */
795 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
796 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
797 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
798 * call convs needs to be handled this way.
800 if (m->flags & MONO_CFG_HAS_VARARGS)
801 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
802 /* gtk-sharp and other broken code will dllimport vararg functions even with
803 * non-varargs signatures. Since there is little hope people will get this right
804 * we assume they won't.
806 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
807 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
809 header = mono_method_get_header (m->method);
812 * We use the frame register also for any method that has
813 * exception clauses. This way, when the handlers are called,
814 * the code will reference local variables using the frame reg instead of
815 * the stack pointer: if we had to restore the stack pointer, we'd
816 * corrupt the method frames that are already on the stack (since
817 * filters get called before stack unwinding happens) when the filter
818 * code would call any method (this also applies to finally etc.).
820 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
822 m->frame_reg = frame_reg;
823 if (frame_reg != ppc_sp) {
824 m->used_int_regs |= 1 << frame_reg;
827 sig = mono_method_signature (m->method);
831 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
832 m->ret->opcode = OP_REGVAR;
833 m->ret->inst_c0 = ppc_r3;
835 /* FIXME: handle long and FP values */
836 switch (mono_type_get_underlying_type (sig->ret)->type) {
840 m->ret->opcode = OP_REGVAR;
841 m->ret->inst_c0 = ppc_r3;
845 /* local vars are at a positive offset from the stack pointer */
847 * also note that if the function uses alloca, we use ppc_r31
848 * to point at the local variables.
850 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
851 /* align the offset to 16 bytes: not sure this is needed here */
853 //offset &= ~(16 - 1);
855 /* add parameter area size for called functions */
856 offset += m->param_area;
860 /* allow room to save the return value */
861 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
864 /* the MonoLMF structure is stored just below the stack pointer */
867 /* this stuff should not be needed on ppc and the new jit,
868 * because a call on ppc to the handlers doesn't change the
869 * stack pointer and the jist doesn't manipulate the stack pointer
870 * for operations involving valuetypes.
872 /* reserve space to store the esp */
873 offset += sizeof (gpointer);
875 /* this is a global constant */
876 mono_exc_esp_offset = offset;
878 if (sig->call_convention == MONO_CALL_VARARG) {
879 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
882 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
884 offset += sizeof(gpointer) - 1;
885 offset &= ~(sizeof(gpointer) - 1);
886 inst->inst_offset = offset;
887 inst->opcode = OP_REGOFFSET;
888 inst->inst_basereg = frame_reg;
889 offset += sizeof(gpointer);
890 if (sig->call_convention == MONO_CALL_VARARG)
891 m->sig_cookie += sizeof (gpointer);
894 curinst = m->locals_start;
895 for (i = curinst; i < m->num_varinfo; ++i) {
896 inst = m->varinfo [i];
897 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
900 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
901 * pinvoke wrappers when they call functions returning structure */
902 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
903 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
905 size = mono_type_size (inst->inst_vtype, &align);
908 offset &= ~(align - 1);
909 inst->inst_offset = offset;
910 inst->opcode = OP_REGOFFSET;
911 inst->inst_basereg = frame_reg;
913 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
918 inst = m->args [curinst];
919 if (inst->opcode != OP_REGVAR) {
920 inst->opcode = OP_REGOFFSET;
921 inst->inst_basereg = frame_reg;
922 offset += sizeof (gpointer) - 1;
923 offset &= ~(sizeof (gpointer) - 1);
924 inst->inst_offset = offset;
925 offset += sizeof (gpointer);
926 if (sig->call_convention == MONO_CALL_VARARG)
927 m->sig_cookie += sizeof (gpointer);
932 for (i = 0; i < sig->param_count; ++i) {
933 inst = m->args [curinst];
934 if (inst->opcode != OP_REGVAR) {
935 inst->opcode = OP_REGOFFSET;
936 inst->inst_basereg = frame_reg;
937 size = mono_type_size (sig->params [i], &align);
939 offset &= ~(align - 1);
940 inst->inst_offset = offset;
942 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
943 m->sig_cookie += size;
948 /* align the offset to 16 bytes */
953 m->stack_offset = offset;
957 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
958 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
962 * take the arguments and generate the arch-specific
963 * instructions to properly call the function in call.
964 * This includes pushing, moving arguments to the right register
966 * Issue: who does the spilling if needed, and when?
969 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
971 MonoMethodSignature *sig;
976 sig = call->signature;
977 n = sig->param_count + sig->hasthis;
979 cinfo = calculate_sizes (sig, sig->pinvoke);
980 if (cinfo->struct_ret)
981 call->used_iregs |= 1 << cinfo->struct_ret;
983 for (i = 0; i < n; ++i) {
984 ainfo = cinfo->args + i;
985 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
987 cfg->disable_aot = TRUE;
989 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
990 sig_arg->inst_p0 = call->signature;
992 MONO_INST_NEW (cfg, arg, OP_OUTARG);
993 arg->inst_imm = cinfo->sig_cookie.offset;
994 arg->inst_left = sig_arg;
996 /* prepend, so they get reversed */
997 arg->next = call->out_args;
998 call->out_args = arg;
1000 if (is_virtual && i == 0) {
1001 /* the argument will be attached to the call instrucion */
1002 in = call->args [i];
1003 call->used_iregs |= 1 << ainfo->reg;
1005 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1006 in = call->args [i];
1007 arg->cil_code = in->cil_code;
1008 arg->inst_left = in;
1009 arg->inst_call = call;
1010 arg->type = in->type;
1011 /* prepend, we'll need to reverse them later */
1012 arg->next = call->out_args;
1013 call->out_args = arg;
1014 if (ainfo->regtype == RegTypeGeneral) {
1015 arg->backend.reg3 = ainfo->reg;
1016 call->used_iregs |= 1 << ainfo->reg;
1017 if (arg->type == STACK_I8)
1018 call->used_iregs |= 1 << (ainfo->reg + 1);
1019 } else if (ainfo->regtype == RegTypeStructByAddr) {
1020 if (ainfo->offset) {
1021 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1022 arg->opcode = OP_OUTARG_MEMBASE;
1023 ai->reg = ainfo->reg;
1024 ai->size = sizeof (gpointer);
1025 ai->offset = ainfo->offset;
1026 arg->backend.data = ai;
1028 arg->backend.reg3 = ainfo->reg;
1029 call->used_iregs |= 1 << ainfo->reg;
1031 } else if (ainfo->regtype == RegTypeStructByVal) {
1033 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1034 /* mark the used regs */
1035 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1036 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1038 arg->opcode = OP_OUTARG_VT;
1039 ai->reg = ainfo->reg;
1040 ai->size = ainfo->size;
1041 ai->vtsize = ainfo->vtsize;
1042 ai->offset = ainfo->offset;
1043 arg->backend.data = ai;
1044 } else if (ainfo->regtype == RegTypeBase) {
1045 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1046 arg->opcode = OP_OUTARG_MEMBASE;
1047 ai->reg = ainfo->reg;
1048 ai->size = ainfo->size;
1049 ai->offset = ainfo->offset;
1050 arg->backend.data = ai;
1051 } else if (ainfo->regtype == RegTypeFP) {
1052 arg->opcode = OP_OUTARG_R8;
1053 arg->backend.reg3 = ainfo->reg;
1054 call->used_fregs |= 1 << ainfo->reg;
1055 if (ainfo->size == 4) {
1056 arg->opcode = OP_OUTARG_R8;
1057 /* we reduce the precision */
1059 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1060 conv->inst_left = arg->inst_left;
1061 arg->inst_left = conv;*/
1064 g_assert_not_reached ();
1069 * Reverse the call->out_args list.
1072 MonoInst *prev = NULL, *list = call->out_args, *next;
1079 call->out_args = prev;
1081 call->stack_usage = cinfo->stack_usage;
1082 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1083 cfg->flags |= MONO_CFG_HAS_CALLS;
1085 * should set more info in call, such as the stack space
1086 * used by the args that needs to be added back to esp
1094 * Allow tracing to work with this interface (with an optional argument)
1098 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1102 ppc_load (code, ppc_r3, cfg->method);
1103 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1104 ppc_load (code, ppc_r0, func);
1105 ppc_mtlr (code, ppc_r0);
1119 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1122 int save_mode = SAVE_NONE;
1124 MonoMethod *method = cfg->method;
1125 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1126 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1130 offset = code - cfg->native_code;
1131 /* we need about 16 instructions */
1132 if (offset > (cfg->code_size - 16 * 4)) {
1133 cfg->code_size *= 2;
1134 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1135 code = cfg->native_code + offset;
1139 case MONO_TYPE_VOID:
1140 /* special case string .ctor icall */
1141 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1142 save_mode = SAVE_ONE;
1144 save_mode = SAVE_NONE;
1148 save_mode = SAVE_TWO;
1152 save_mode = SAVE_FP;
1154 case MONO_TYPE_VALUETYPE:
1155 save_mode = SAVE_STRUCT;
1158 save_mode = SAVE_ONE;
1162 switch (save_mode) {
1164 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1165 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1166 if (enable_arguments) {
1167 ppc_mr (code, ppc_r5, ppc_r4);
1168 ppc_mr (code, ppc_r4, ppc_r3);
1172 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1173 if (enable_arguments) {
1174 ppc_mr (code, ppc_r4, ppc_r3);
1178 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1179 if (enable_arguments) {
1180 /* FIXME: what reg? */
1181 ppc_fmr (code, ppc_f3, ppc_f1);
1182 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1183 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1187 if (enable_arguments) {
1188 /* FIXME: get the actual address */
1189 ppc_mr (code, ppc_r4, ppc_r3);
1197 ppc_load (code, ppc_r3, cfg->method);
1198 ppc_load (code, ppc_r0, func);
1199 ppc_mtlr (code, ppc_r0);
1202 switch (save_mode) {
1204 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1205 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1208 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1211 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1221 * Conditional branches have a small offset, so if it is likely overflowed,
1222 * we do a branch to the end of the method (uncond branches have much larger
1223 * offsets) where we perform the conditional and jump back unconditionally.
1224 * It's slightly slower, since we add two uncond branches, but it's very simple
1225 * with the current patch implementation and such large methods are likely not
1226 * going to be perf critical anyway.
1231 const char *exception;
1238 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1239 if (ins->flags & MONO_INST_BRLABEL) { \
1240 if (0 && ins->inst_i0->inst_c0) { \
1241 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1243 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1244 ppc_bc (code, (b0), (b1), 0); \
1247 if (0 && ins->inst_true_bb->native_offset) { \
1248 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1250 int br_disp = ins->inst_true_bb->max_offset - offset; \
1251 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1252 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1253 ovfj->data.bb = ins->inst_true_bb; \
1254 ovfj->ip_offset = 0; \
1255 ovfj->b0_cond = (b0); \
1256 ovfj->b1_cond = (b1); \
1257 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1260 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1261 ppc_bc (code, (b0), (b1), 0); \
1266 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1268 /* emit an exception if condition is fail
1270 * We assign the extra code used to throw the implicit exceptions
1271 * to cfg->bb_exit as far as the big branch handling is concerned
1273 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1275 int br_disp = cfg->bb_exit->max_offset - offset; \
1276 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1277 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1278 ovfj->data.exception = (exc_name); \
1279 ovfj->ip_offset = code - cfg->native_code; \
1280 ovfj->b0_cond = (b0); \
1281 ovfj->b1_cond = (b1); \
1282 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1284 cfg->bb_exit->max_offset += 24; \
1286 mono_add_patch_info (cfg, code - cfg->native_code, \
1287 MONO_PATCH_INFO_EXC, exc_name); \
1288 ppc_bcl (code, (b0), (b1), 0); \
1292 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1295 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1297 MonoInst *ins, *last_ins = NULL;
1302 switch (ins->opcode) {
1304 /* remove unnecessary multiplication with 1 */
1305 if (ins->inst_imm == 1) {
1306 if (ins->dreg != ins->sreg1) {
1307 ins->opcode = OP_MOVE;
1309 last_ins->next = ins->next;
1314 int power2 = mono_is_power_of_two (ins->inst_imm);
1316 ins->opcode = OP_SHL_IMM;
1317 ins->inst_imm = power2;
1321 case OP_LOAD_MEMBASE:
1322 case OP_LOADI4_MEMBASE:
1324 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1325 * OP_LOAD_MEMBASE offset(basereg), reg
1327 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1328 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1329 ins->inst_basereg == last_ins->inst_destbasereg &&
1330 ins->inst_offset == last_ins->inst_offset) {
1331 if (ins->dreg == last_ins->sreg1) {
1332 last_ins->next = ins->next;
1336 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1337 ins->opcode = OP_MOVE;
1338 ins->sreg1 = last_ins->sreg1;
1342 * Note: reg1 must be different from the basereg in the second load
1343 * OP_LOAD_MEMBASE offset(basereg), reg1
1344 * OP_LOAD_MEMBASE offset(basereg), reg2
1346 * OP_LOAD_MEMBASE offset(basereg), reg1
1347 * OP_MOVE reg1, reg2
1349 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1350 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1351 ins->inst_basereg != last_ins->dreg &&
1352 ins->inst_basereg == last_ins->inst_basereg &&
1353 ins->inst_offset == last_ins->inst_offset) {
1355 if (ins->dreg == last_ins->dreg) {
1356 last_ins->next = ins->next;
1360 ins->opcode = OP_MOVE;
1361 ins->sreg1 = last_ins->dreg;
1364 //g_assert_not_reached ();
1368 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1369 * OP_LOAD_MEMBASE offset(basereg), reg
1371 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1372 * OP_ICONST reg, imm
1374 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1375 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1376 ins->inst_basereg == last_ins->inst_destbasereg &&
1377 ins->inst_offset == last_ins->inst_offset) {
1378 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1379 ins->opcode = OP_ICONST;
1380 ins->inst_c0 = last_ins->inst_imm;
1381 g_assert_not_reached (); // check this rule
1385 case OP_LOADU1_MEMBASE:
1386 case OP_LOADI1_MEMBASE:
1387 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1388 ins->inst_basereg == last_ins->inst_destbasereg &&
1389 ins->inst_offset == last_ins->inst_offset) {
1390 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1391 ins->sreg1 = last_ins->sreg1;
1394 case OP_LOADU2_MEMBASE:
1395 case OP_LOADI2_MEMBASE:
1396 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1397 ins->inst_basereg == last_ins->inst_destbasereg &&
1398 ins->inst_offset == last_ins->inst_offset) {
1399 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1400 ins->sreg1 = last_ins->sreg1;
1407 ins->opcode = OP_MOVE;
1411 if (ins->dreg == ins->sreg1) {
1413 last_ins->next = ins->next;
1418 * OP_MOVE sreg, dreg
1419 * OP_MOVE dreg, sreg
1421 if (last_ins && last_ins->opcode == OP_MOVE &&
1422 ins->sreg1 == last_ins->dreg &&
1423 ins->dreg == last_ins->sreg1) {
1424 last_ins->next = ins->next;
1433 bb->last_ins = last_ins;
1437 * the branch_b0_table should maintain the order of these
1451 branch_b0_table [] = {
1466 branch_b1_table [] = {
1481 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1485 bb->code = to_insert;
1486 to_insert->next = ins;
1488 to_insert->next = ins->next;
1489 ins->next = to_insert;
1493 #define NEW_INS(cfg,dest,op) do { \
1494 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1495 (dest)->opcode = (op); \
1496 insert_after_ins (bb, last_ins, (dest)); \
1500 map_to_reg_reg_op (int op)
1509 case OP_COMPARE_IMM:
1525 case OP_LOAD_MEMBASE:
1526 return OP_LOAD_MEMINDEX;
1527 case OP_LOADI4_MEMBASE:
1528 return OP_LOADI4_MEMINDEX;
1529 case OP_LOADU4_MEMBASE:
1530 return OP_LOADU4_MEMINDEX;
1531 case OP_LOADU1_MEMBASE:
1532 return OP_LOADU1_MEMINDEX;
1533 case OP_LOADI2_MEMBASE:
1534 return OP_LOADI2_MEMINDEX;
1535 case OP_LOADU2_MEMBASE:
1536 return OP_LOADU2_MEMINDEX;
1537 case OP_LOADI1_MEMBASE:
1538 return OP_LOADI1_MEMINDEX;
1539 case OP_LOADR4_MEMBASE:
1540 return OP_LOADR4_MEMINDEX;
1541 case OP_LOADR8_MEMBASE:
1542 return OP_LOADR8_MEMINDEX;
1543 case OP_STOREI1_MEMBASE_REG:
1544 return OP_STOREI1_MEMINDEX;
1545 case OP_STOREI2_MEMBASE_REG:
1546 return OP_STOREI2_MEMINDEX;
1547 case OP_STOREI4_MEMBASE_REG:
1548 return OP_STOREI4_MEMINDEX;
1549 case OP_STORE_MEMBASE_REG:
1550 return OP_STORE_MEMINDEX;
1551 case OP_STORER4_MEMBASE_REG:
1552 return OP_STORER4_MEMINDEX;
1553 case OP_STORER8_MEMBASE_REG:
1554 return OP_STORER8_MEMINDEX;
1555 case OP_STORE_MEMBASE_IMM:
1556 return OP_STORE_MEMBASE_REG;
1557 case OP_STOREI1_MEMBASE_IMM:
1558 return OP_STOREI1_MEMBASE_REG;
1559 case OP_STOREI2_MEMBASE_IMM:
1560 return OP_STOREI2_MEMBASE_REG;
1561 case OP_STOREI4_MEMBASE_IMM:
1562 return OP_STOREI4_MEMBASE_REG;
1564 g_assert_not_reached ();
1567 #define compare_opcode_is_unsigned(opcode) \
1568 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1569 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1570 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1572 * Remove from the instruction list the instructions that can't be
1573 * represented with very simple instructions with no register
1577 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1579 MonoInst *ins, *next, *temp, *last_ins = NULL;
1582 /* setup the virtual reg allocator */
1583 if (bb->max_vreg > cfg->rs->next_vreg)
1584 cfg->rs->next_vreg = bb->max_vreg;
1589 switch (ins->opcode) {
1592 if (!ppc_is_imm16 (ins->inst_imm)) {
1593 NEW_INS (cfg, temp, OP_ICONST);
1594 temp->inst_c0 = ins->inst_imm;
1595 temp->dreg = mono_regstate_next_int (cfg->rs);
1596 ins->sreg2 = temp->dreg;
1597 ins->opcode = map_to_reg_reg_op (ins->opcode);
1601 if (!ppc_is_imm16 (-ins->inst_imm)) {
1602 NEW_INS (cfg, temp, OP_ICONST);
1603 temp->inst_c0 = ins->inst_imm;
1604 temp->dreg = mono_regstate_next_int (cfg->rs);
1605 ins->sreg2 = temp->dreg;
1606 ins->opcode = map_to_reg_reg_op (ins->opcode);
1612 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1613 NEW_INS (cfg, temp, OP_ICONST);
1614 temp->inst_c0 = ins->inst_imm;
1615 temp->dreg = mono_regstate_next_int (cfg->rs);
1616 ins->sreg2 = temp->dreg;
1617 ins->opcode = map_to_reg_reg_op (ins->opcode);
1623 NEW_INS (cfg, temp, OP_ICONST);
1624 temp->inst_c0 = ins->inst_imm;
1625 temp->dreg = mono_regstate_next_int (cfg->rs);
1626 ins->sreg2 = temp->dreg;
1627 ins->opcode = map_to_reg_reg_op (ins->opcode);
1629 case OP_COMPARE_IMM:
1630 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1631 if (!ppc_is_uimm16 (ins->inst_imm)) {
1632 NEW_INS (cfg, temp, OP_ICONST);
1633 temp->inst_c0 = ins->inst_imm;
1634 temp->dreg = mono_regstate_next_int (cfg->rs);
1635 ins->sreg2 = temp->dreg;
1636 ins->opcode = map_to_reg_reg_op (ins->opcode);
1639 if (!ppc_is_imm16 (ins->inst_imm)) {
1640 NEW_INS (cfg, temp, OP_ICONST);
1641 temp->inst_c0 = ins->inst_imm;
1642 temp->dreg = mono_regstate_next_int (cfg->rs);
1643 ins->sreg2 = temp->dreg;
1644 ins->opcode = map_to_reg_reg_op (ins->opcode);
1649 if (ins->inst_imm == 1) {
1650 ins->opcode = OP_MOVE;
1653 if (ins->inst_imm == 0) {
1654 ins->opcode = OP_ICONST;
1658 imm = mono_is_power_of_two (ins->inst_imm);
1660 ins->opcode = OP_SHL_IMM;
1661 ins->inst_imm = imm;
1664 if (!ppc_is_imm16 (ins->inst_imm)) {
1665 NEW_INS (cfg, temp, OP_ICONST);
1666 temp->inst_c0 = ins->inst_imm;
1667 temp->dreg = mono_regstate_next_int (cfg->rs);
1668 ins->sreg2 = temp->dreg;
1669 ins->opcode = map_to_reg_reg_op (ins->opcode);
1672 case OP_LOAD_MEMBASE:
1673 case OP_LOADI4_MEMBASE:
1674 case OP_LOADU4_MEMBASE:
1675 case OP_LOADI2_MEMBASE:
1676 case OP_LOADU2_MEMBASE:
1677 case OP_LOADI1_MEMBASE:
1678 case OP_LOADU1_MEMBASE:
1679 case OP_LOADR4_MEMBASE:
1680 case OP_LOADR8_MEMBASE:
1681 case OP_STORE_MEMBASE_REG:
1682 case OP_STOREI4_MEMBASE_REG:
1683 case OP_STOREI2_MEMBASE_REG:
1684 case OP_STOREI1_MEMBASE_REG:
1685 case OP_STORER4_MEMBASE_REG:
1686 case OP_STORER8_MEMBASE_REG:
1687 /* we can do two things: load the immed in a register
1688 * and use an indexed load, or see if the immed can be
1689 * represented as an ad_imm + a load with a smaller offset
1690 * that fits. We just do the first for now, optimize later.
1692 if (ppc_is_imm16 (ins->inst_offset))
1694 NEW_INS (cfg, temp, OP_ICONST);
1695 temp->inst_c0 = ins->inst_offset;
1696 temp->dreg = mono_regstate_next_int (cfg->rs);
1697 ins->sreg2 = temp->dreg;
1698 ins->opcode = map_to_reg_reg_op (ins->opcode);
1700 case OP_STORE_MEMBASE_IMM:
1701 case OP_STOREI1_MEMBASE_IMM:
1702 case OP_STOREI2_MEMBASE_IMM:
1703 case OP_STOREI4_MEMBASE_IMM:
1704 NEW_INS (cfg, temp, OP_ICONST);
1705 temp->inst_c0 = ins->inst_imm;
1706 temp->dreg = mono_regstate_next_int (cfg->rs);
1707 ins->sreg1 = temp->dreg;
1708 ins->opcode = map_to_reg_reg_op (ins->opcode);
1710 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1715 bb->last_ins = last_ins;
1716 bb->max_vreg = cfg->rs->next_vreg;
1721 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1725 mono_arch_lowering_pass (cfg, bb);
1726 mono_local_regalloc (cfg, bb);
1730 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1732 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1733 ppc_fctiwz (code, ppc_f0, sreg);
1734 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1735 ppc_lwz (code, dreg, -4, ppc_sp);
1738 ppc_andid (code, dreg, dreg, 0xff);
1740 ppc_andid (code, dreg, dreg, 0xffff);
1743 ppc_extsb (code, dreg, dreg);
1745 ppc_extsh (code, dreg, dreg);
1750 static unsigned char*
1751 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1754 int sreg = tree->sreg1;
1755 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1756 if (tree->flags & MONO_INST_INIT) {
1758 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1759 x86_push_reg (code, X86_EAX);
1762 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1763 x86_push_reg (code, X86_ECX);
1766 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1767 x86_push_reg (code, X86_EDI);
1771 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1772 if (sreg != X86_ECX)
1773 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1774 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1776 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1778 x86_prefix (code, X86_REP_PREFIX);
1781 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1782 x86_pop_reg (code, X86_EDI);
1783 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1784 x86_pop_reg (code, X86_ECX);
1785 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1786 x86_pop_reg (code, X86_EAX);
1799 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1802 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1803 PatchData *pdata = (PatchData*)user_data;
1804 guchar *code = data;
1805 guint32 *thunks = data;
1806 guint32 *endthunks = (guint32*)(code + bsize);
1810 int difflow, diffhigh;
1812 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1813 difflow = (char*)pdata->code - (char*)thunks;
1814 diffhigh = (char*)pdata->code - (char*)endthunks;
1815 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1818 templ = (guchar*)load;
1819 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1820 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1822 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1823 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1824 while (thunks < endthunks) {
1825 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1826 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1827 ppc_patch (pdata->code, (guchar*)thunks);
1828 mono_arch_flush_icache (pdata->code, 4);
1831 static int num_thunks = 0;
1833 if ((num_thunks % 20) == 0)
1834 g_print ("num_thunks lookup: %d\n", num_thunks);
1837 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1838 /* found a free slot instead: emit thunk */
1839 code = (guchar*)thunks;
1840 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1841 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1842 ppc_mtctr (code, ppc_r0);
1843 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1844 mono_arch_flush_icache ((guchar*)thunks, 16);
1846 ppc_patch (pdata->code, (guchar*)thunks);
1847 mono_arch_flush_icache (pdata->code, 4);
1850 static int num_thunks = 0;
1852 if ((num_thunks % 20) == 0)
1853 g_print ("num_thunks: %d\n", num_thunks);
1857 /* skip 16 bytes, the size of the thunk */
1861 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1867 handle_thunk (int absolute, guchar *code, guchar *target) {
1868 MonoDomain *domain = mono_domain_get ();
1872 pdata.target = target;
1873 pdata.absolute = absolute;
1876 mono_domain_lock (domain);
1877 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1880 /* this uses the first available slot */
1882 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1884 mono_domain_unlock (domain);
1886 if (pdata.found != 1)
1887 g_print ("thunk failed for %p from %p\n", target, code);
1888 g_assert (pdata.found == 1);
1892 ppc_patch (guchar *code, guchar *target)
1894 guint32 ins = *(guint32*)code;
1895 guint32 prim = ins >> 26;
1898 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1900 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1901 gint diff = target - code;
1903 if (diff <= 33554431){
1904 ins = (18 << 26) | (diff) | (ins & 1);
1905 *(guint32*)code = ins;
1909 /* diff between 0 and -33554432 */
1910 if (diff >= -33554432){
1911 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1912 *(guint32*)code = ins;
1917 if ((glong)target >= 0){
1918 if ((glong)target <= 33554431){
1919 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1920 *(guint32*)code = ins;
1924 if ((glong)target >= -33554432){
1925 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1926 *(guint32*)code = ins;
1931 handle_thunk (TRUE, code, target);
1934 g_assert_not_reached ();
1941 guint32 li = (guint32)target;
1942 ins = (ins & 0xffff0000) | (ins & 3);
1943 ovf = li & 0xffff0000;
1944 if (ovf != 0 && ovf != 0xffff0000)
1945 g_assert_not_reached ();
1948 // FIXME: assert the top bits of li are 0
1950 gint diff = target - code;
1951 ins = (ins & 0xffff0000) | (ins & 3);
1952 ovf = diff & 0xffff0000;
1953 if (ovf != 0 && ovf != 0xffff0000)
1954 g_assert_not_reached ();
1958 *(guint32*)code = ins;
1962 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
1964 /* the trampoline code will try to patch the blrl, blr, bcctr */
1965 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
1968 /* this is the lis/ori/mtlr/blrl sequence */
1969 seq = (guint32*)code;
1970 g_assert ((seq [0] >> 26) == 15);
1971 g_assert ((seq [1] >> 26) == 24);
1972 g_assert ((seq [2] >> 26) == 31);
1973 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
1974 /* FIXME: make this thread safe */
1975 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
1976 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
1977 mono_arch_flush_icache (code - 8, 8);
1979 g_assert_not_reached ();
1981 // g_print ("patched with 0x%08x\n", ins);
1985 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1990 guint8 *code = cfg->native_code + cfg->code_len;
1991 MonoInst *last_ins = NULL;
1992 guint last_offset = 0;
1995 if (cfg->opt & MONO_OPT_PEEPHOLE)
1996 peephole_pass (cfg, bb);
1998 /* we don't align basic blocks of loops on ppc */
2000 if (cfg->verbose_level > 2)
2001 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2003 cpos = bb->max_offset;
2005 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2006 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2007 //g_assert (!mono_compile_aot);
2010 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2011 /* this is not thread save, but good enough */
2012 /* fixme: howto handle overflows? */
2013 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2018 offset = code - cfg->native_code;
2020 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2022 if (offset > (cfg->code_size - max_len - 16)) {
2023 cfg->code_size *= 2;
2024 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2025 code = cfg->native_code + offset;
2027 // if (ins->cil_code)
2028 // g_print ("cil code\n");
2029 mono_debug_record_line_number (cfg, ins, offset);
2031 switch (ins->opcode) {
2033 emit_tls_access (code, ins->dreg, ins->inst_offset);
2036 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2037 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2038 ppc_mr (code, ppc_r4, ppc_r0);
2041 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2042 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2043 ppc_mr (code, ppc_r4, ppc_r0);
2045 case OP_MEMORY_BARRIER:
2048 case OP_STOREI1_MEMBASE_REG:
2049 if (ppc_is_imm16 (ins->inst_offset)) {
2050 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2052 g_assert_not_reached ();
2055 case OP_STOREI2_MEMBASE_REG:
2056 if (ppc_is_imm16 (ins->inst_offset)) {
2057 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2059 g_assert_not_reached ();
2062 case OP_STORE_MEMBASE_REG:
2063 case OP_STOREI4_MEMBASE_REG:
2064 if (ppc_is_imm16 (ins->inst_offset)) {
2065 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2067 g_assert_not_reached ();
2070 case OP_STOREI1_MEMINDEX:
2071 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2073 case OP_STOREI2_MEMINDEX:
2074 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2076 case OP_STORE_MEMINDEX:
2077 case OP_STOREI4_MEMINDEX:
2078 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2083 g_assert_not_reached ();
2084 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2087 g_assert_not_reached ();
2089 case OP_LOAD_MEMBASE:
2090 case OP_LOADI4_MEMBASE:
2091 case OP_LOADU4_MEMBASE:
2092 if (ppc_is_imm16 (ins->inst_offset)) {
2093 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2095 g_assert_not_reached ();
2098 case OP_LOADI1_MEMBASE:
2099 case OP_LOADU1_MEMBASE:
2100 if (ppc_is_imm16 (ins->inst_offset)) {
2101 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2103 g_assert_not_reached ();
2105 if (ins->opcode == OP_LOADI1_MEMBASE)
2106 ppc_extsb (code, ins->dreg, ins->dreg);
2108 case OP_LOADU2_MEMBASE:
2109 if (ppc_is_imm16 (ins->inst_offset)) {
2110 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2112 g_assert_not_reached ();
2115 case OP_LOADI2_MEMBASE:
2116 if (ppc_is_imm16 (ins->inst_offset)) {
2117 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2119 g_assert_not_reached ();
2122 case OP_LOAD_MEMINDEX:
2123 case OP_LOADI4_MEMINDEX:
2124 case OP_LOADU4_MEMINDEX:
2125 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2127 case OP_LOADU2_MEMINDEX:
2128 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2130 case OP_LOADI2_MEMINDEX:
2131 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2133 case OP_LOADU1_MEMINDEX:
2134 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2136 case OP_LOADI1_MEMINDEX:
2137 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2138 ppc_extsb (code, ins->dreg, ins->dreg);
2141 ppc_extsb (code, ins->dreg, ins->sreg1);
2144 ppc_extsh (code, ins->dreg, ins->sreg1);
2147 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2150 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2153 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2154 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2156 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2158 case OP_COMPARE_IMM:
2159 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2160 if (ppc_is_uimm16 (ins->inst_imm)) {
2161 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2163 g_assert_not_reached ();
2166 if (ppc_is_imm16 (ins->inst_imm)) {
2167 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2169 g_assert_not_reached ();
2177 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2180 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2183 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2186 if (ppc_is_imm16 (ins->inst_imm)) {
2187 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2189 g_assert_not_reached ();
2193 if (ppc_is_imm16 (ins->inst_imm)) {
2194 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2196 g_assert_not_reached ();
2200 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2202 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2203 ppc_mfspr (code, ppc_r0, ppc_xer);
2204 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2205 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2207 case CEE_ADD_OVF_UN:
2208 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2210 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2211 ppc_mfspr (code, ppc_r0, ppc_xer);
2212 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2213 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2216 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2218 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2219 ppc_mfspr (code, ppc_r0, ppc_xer);
2220 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2221 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2223 case CEE_SUB_OVF_UN:
2224 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2226 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2227 ppc_mfspr (code, ppc_r0, ppc_xer);
2228 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2229 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2231 case OP_ADD_OVF_CARRY:
2232 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2234 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2235 ppc_mfspr (code, ppc_r0, ppc_xer);
2236 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2237 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2239 case OP_ADD_OVF_UN_CARRY:
2240 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2242 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2243 ppc_mfspr (code, ppc_r0, ppc_xer);
2244 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2245 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2247 case OP_SUB_OVF_CARRY:
2248 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2250 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2251 ppc_mfspr (code, ppc_r0, ppc_xer);
2252 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2253 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2255 case OP_SUB_OVF_UN_CARRY:
2256 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2258 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2259 ppc_mfspr (code, ppc_r0, ppc_xer);
2260 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2261 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2264 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2267 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2270 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2273 // we add the negated value
2274 if (ppc_is_imm16 (-ins->inst_imm))
2275 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2277 g_assert_not_reached ();
2281 g_assert (ppc_is_imm16 (ins->inst_imm));
2282 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2285 ppc_subfze (code, ins->dreg, ins->sreg1);
2288 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2289 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2292 if (!(ins->inst_imm & 0xffff0000)) {
2293 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2294 } else if (!(ins->inst_imm & 0xffff)) {
2295 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2297 g_assert_not_reached ();
2301 guint32 *divisor_is_m1;
2302 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2304 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2305 divisor_is_m1 = code;
2306 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2307 ppc_lis (code, ppc_r11, 0x8000);
2308 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2309 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2310 ppc_patch (divisor_is_m1, code);
2311 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2313 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2314 ppc_mfspr (code, ppc_r0, ppc_xer);
2315 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2316 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2320 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2321 ppc_mfspr (code, ppc_r0, ppc_xer);
2322 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2323 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2326 g_assert_not_reached ();
2328 ppc_load (code, ppc_r11, ins->inst_imm);
2329 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2330 ppc_mfspr (code, ppc_r0, ppc_xer);
2331 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2332 /* FIXME: use OverflowException for 0x80000000/-1 */
2333 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2337 guint32 *divisor_is_m1;
2338 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2339 divisor_is_m1 = code;
2340 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2341 ppc_lis (code, ppc_r11, 0x8000);
2342 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2343 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2344 ppc_patch (divisor_is_m1, code);
2345 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2346 ppc_mfspr (code, ppc_r0, ppc_xer);
2347 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2348 /* FIXME: use OverflowException for 0x80000000/-1 */
2349 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2350 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2351 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2355 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2356 ppc_mfspr (code, ppc_r0, ppc_xer);
2357 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2358 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2359 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2360 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2363 g_assert_not_reached ();
2365 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2368 if (!(ins->inst_imm & 0xffff0000)) {
2369 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2370 } else if (!(ins->inst_imm & 0xffff)) {
2371 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2373 g_assert_not_reached ();
2377 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2380 if (!(ins->inst_imm & 0xffff0000)) {
2381 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2382 } else if (!(ins->inst_imm & 0xffff)) {
2383 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2385 g_assert_not_reached ();
2389 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2392 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2395 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2398 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2402 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2404 ppc_mr (code, ins->dreg, ins->sreg1);
2407 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2410 ppc_not (code, ins->dreg, ins->sreg1);
2413 ppc_neg (code, ins->dreg, ins->sreg1);
2416 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2419 if (ppc_is_imm16 (ins->inst_imm)) {
2420 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2422 g_assert_not_reached ();
2426 /* we annot use mcrxr, since it's not implemented on some processors
2427 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2429 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2430 ppc_mfspr (code, ppc_r0, ppc_xer);
2431 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2432 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2434 case CEE_MUL_OVF_UN:
2435 /* we first multiply to get the high word and compare to 0
2436 * to set the flags, then the result is discarded and then
2437 * we multiply to get the lower * bits result
2439 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2440 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2441 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2442 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2446 ppc_load (code, ins->dreg, ins->inst_c0);
2449 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2450 ppc_lis (code, ins->dreg, 0);
2451 ppc_ori (code, ins->dreg, ins->dreg, 0);
2457 ppc_mr (code, ins->dreg, ins->sreg1);
2460 int saved = ins->sreg1;
2461 if (ins->sreg1 == ppc_r3) {
2462 ppc_mr (code, ppc_r0, ins->sreg1);
2465 if (ins->sreg2 != ppc_r3)
2466 ppc_mr (code, ppc_r3, ins->sreg2);
2467 if (saved != ppc_r4)
2468 ppc_mr (code, ppc_r4, saved);
2473 ppc_fmr (code, ins->dreg, ins->sreg1);
2475 case OP_FCONV_TO_R4:
2476 ppc_frsp (code, ins->dreg, ins->sreg1);
2482 * Keep in sync with mono_arch_emit_epilog
2484 g_assert (!cfg->method->save_lmf);
2485 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2486 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2487 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2489 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2490 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2492 ppc_mtlr (code, ppc_r0);
2494 if (ppc_is_imm16 (cfg->stack_usage)) {
2495 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2497 ppc_load (code, ppc_r11, cfg->stack_usage);
2498 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2500 if (!cfg->method->save_lmf) {
2501 /*for (i = 31; i >= 14; --i) {
2502 if (cfg->used_float_regs & (1 << i)) {
2503 pos += sizeof (double);
2504 ppc_lfd (code, i, -pos, cfg->frame_reg);
2507 for (i = 31; i >= 13; --i) {
2508 if (cfg->used_int_regs & (1 << i)) {
2509 pos += sizeof (gulong);
2510 ppc_lwz (code, i, -pos, cfg->frame_reg);
2514 /* FIXME restore from MonoLMF: though this can't happen yet */
2516 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2521 /* ensure ins->sreg1 is not NULL */
2522 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2525 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2526 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2528 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2529 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2531 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2539 call = (MonoCallInst*)ins;
2540 if (ins->flags & MONO_INST_HAS_METHOD)
2541 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2543 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2544 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2545 ppc_lis (code, ppc_r0, 0);
2546 ppc_ori (code, ppc_r0, ppc_r0, 0);
2547 ppc_mtlr (code, ppc_r0);
2556 case OP_VOIDCALL_REG:
2558 ppc_mtlr (code, ins->sreg1);
2561 case OP_FCALL_MEMBASE:
2562 case OP_LCALL_MEMBASE:
2563 case OP_VCALL_MEMBASE:
2564 case OP_VOIDCALL_MEMBASE:
2565 case OP_CALL_MEMBASE:
2566 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2567 ppc_mtlr (code, ppc_r0);
2571 g_assert_not_reached ();
2574 guint32 * zero_loop_jump, * zero_loop_start;
2575 /* keep alignment */
2576 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2577 int area_offset = alloca_waste;
2579 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2580 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2581 /* use ctr to store the number of words to 0 if needed */
2582 if (ins->flags & MONO_INST_INIT) {
2583 /* we zero 4 bytes at a time:
2584 * we add 7 instead of 3 so that we set the counter to
2585 * at least 1, otherwise the bdnz instruction will make
2586 * it negative and iterate billions of times.
2588 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2589 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2590 ppc_mtctr (code, ppc_r0);
2592 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2593 ppc_neg (code, ppc_r11, ppc_r11);
2594 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2596 if (ins->flags & MONO_INST_INIT) {
2597 /* adjust the dest reg by -4 so we can use stwu */
2598 /* we actually adjust -8 because we let the loop
2601 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2602 ppc_li (code, ppc_r11, 0);
2603 zero_loop_start = code;
2604 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2605 zero_loop_jump = code;
2606 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2607 ppc_patch (zero_loop_jump, zero_loop_start);
2609 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2617 ppc_mr (code, ppc_r3, ins->sreg1);
2618 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2619 (gpointer)"mono_arch_throw_exception");
2620 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2621 ppc_lis (code, ppc_r0, 0);
2622 ppc_ori (code, ppc_r0, ppc_r0, 0);
2623 ppc_mtlr (code, ppc_r0);
2632 ppc_mr (code, ppc_r3, ins->sreg1);
2633 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2634 (gpointer)"mono_arch_rethrow_exception");
2635 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2636 ppc_lis (code, ppc_r0, 0);
2637 ppc_ori (code, ppc_r0, ppc_r0, 0);
2638 ppc_mtlr (code, ppc_r0);
2645 case OP_START_HANDLER:
2646 ppc_mflr (code, ppc_r0);
2647 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2648 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2650 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2651 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2655 if (ins->sreg1 != ppc_r3)
2656 ppc_mr (code, ppc_r3, ins->sreg1);
2657 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2658 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2660 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2661 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2663 ppc_mtlr (code, ppc_r0);
2667 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2668 ppc_mtlr (code, ppc_r0);
2671 case OP_CALL_HANDLER:
2672 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2676 ins->inst_c0 = code - cfg->native_code;
2679 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2680 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2682 if (ins->flags & MONO_INST_BRLABEL) {
2683 /*if (ins->inst_i0->inst_c0) {
2685 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2687 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2691 /*if (ins->inst_target_bb->native_offset) {
2693 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2695 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2701 ppc_mtctr (code, ins->sreg1);
2702 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2705 ppc_li (code, ins->dreg, 0);
2706 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2707 ppc_li (code, ins->dreg, 1);
2711 ppc_li (code, ins->dreg, 1);
2712 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2713 ppc_li (code, ins->dreg, 0);
2717 ppc_li (code, ins->dreg, 1);
2718 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2719 ppc_li (code, ins->dreg, 0);
2721 case OP_COND_EXC_EQ:
2722 case OP_COND_EXC_NE_UN:
2723 case OP_COND_EXC_LT:
2724 case OP_COND_EXC_LT_UN:
2725 case OP_COND_EXC_GT:
2726 case OP_COND_EXC_GT_UN:
2727 case OP_COND_EXC_GE:
2728 case OP_COND_EXC_GE_UN:
2729 case OP_COND_EXC_LE:
2730 case OP_COND_EXC_LE_UN:
2731 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2734 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2736 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2737 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2738 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2740 case OP_COND_EXC_OV:
2741 /*ppc_mcrxr (code, 0);
2742 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2744 case OP_COND_EXC_NC:
2745 case OP_COND_EXC_NO:
2746 g_assert_not_reached ();
2758 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2761 /* floating point opcodes */
2763 ppc_load (code, ppc_r11, ins->inst_p0);
2764 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2767 ppc_load (code, ppc_r11, ins->inst_p0);
2768 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2770 case OP_STORER8_MEMBASE_REG:
2771 if (ppc_is_imm16 (ins->inst_offset)) {
2772 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2774 g_assert_not_reached ();
2777 case OP_LOADR8_MEMBASE:
2778 if (ppc_is_imm16 (ins->inst_offset)) {
2779 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2781 g_assert_not_reached ();
2784 case OP_STORER4_MEMBASE_REG:
2785 ppc_frsp (code, ins->sreg1, ins->sreg1);
2786 if (ppc_is_imm16 (ins->inst_offset)) {
2787 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2789 g_assert_not_reached ();
2792 case OP_LOADR4_MEMBASE:
2793 if (ppc_is_imm16 (ins->inst_offset)) {
2794 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2796 g_assert_not_reached ();
2799 case OP_LOADR4_MEMINDEX:
2800 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2802 case OP_LOADR8_MEMINDEX:
2803 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2805 case OP_STORER4_MEMINDEX:
2806 ppc_frsp (code, ins->sreg1, ins->sreg1);
2807 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2809 case OP_STORER8_MEMINDEX:
2810 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2812 case CEE_CONV_R_UN: {
2813 static const guint64 adjust_val = 0x4330000000000000ULL;
2814 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2815 ppc_stw (code, ppc_r0, -8, ppc_sp);
2816 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2817 ppc_load (code, ppc_r11, &adjust_val);
2818 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2819 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2820 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2823 case CEE_CONV_R4: /* FIXME: change precision */
2825 static const guint64 adjust_val = 0x4330000080000000ULL;
2826 // addis is special for ppc_r0
2827 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2828 ppc_stw (code, ppc_r0, -8, ppc_sp);
2829 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2830 ppc_stw (code, ppc_r11, -4, ppc_sp);
2831 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2832 ppc_load (code, ppc_r11, &adjust_val);
2833 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2834 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2837 case OP_FCONV_TO_I1:
2838 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2840 case OP_FCONV_TO_U1:
2841 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2843 case OP_FCONV_TO_I2:
2844 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2846 case OP_FCONV_TO_U2:
2847 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2849 case OP_FCONV_TO_I4:
2851 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2853 case OP_FCONV_TO_U4:
2855 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2857 case OP_FCONV_TO_I8:
2858 case OP_FCONV_TO_U8:
2859 g_assert_not_reached ();
2860 /* Implemented as helper calls */
2862 case OP_LCONV_TO_R_UN:
2863 g_assert_not_reached ();
2864 /* Implemented as helper calls */
2866 case OP_LCONV_TO_OVF_I: {
2867 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2868 // Check if its negative
2869 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2870 negative_branch = code;
2871 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2872 // Its positive msword == 0
2873 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2874 msword_positive_branch = code;
2875 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2877 ovf_ex_target = code;
2878 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2880 ppc_patch (negative_branch, code);
2881 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2882 msword_negative_branch = code;
2883 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2884 ppc_patch (msword_negative_branch, ovf_ex_target);
2886 ppc_patch (msword_positive_branch, code);
2887 if (ins->dreg != ins->sreg1)
2888 ppc_mr (code, ins->dreg, ins->sreg1);
2892 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2895 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2898 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2901 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2904 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2907 ppc_fneg (code, ins->dreg, ins->sreg1);
2911 g_assert_not_reached ();
2914 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2917 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2918 ppc_li (code, ins->dreg, 0);
2919 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2920 ppc_li (code, ins->dreg, 1);
2923 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2924 ppc_li (code, ins->dreg, 1);
2925 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2926 ppc_li (code, ins->dreg, 0);
2929 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2930 ppc_li (code, ins->dreg, 1);
2931 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2932 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2933 ppc_li (code, ins->dreg, 0);
2936 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2937 ppc_li (code, ins->dreg, 1);
2938 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2939 ppc_li (code, ins->dreg, 0);
2942 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2943 ppc_li (code, ins->dreg, 1);
2944 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2945 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2946 ppc_li (code, ins->dreg, 0);
2949 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2952 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2955 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2956 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2959 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2960 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2963 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2964 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2967 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2968 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2971 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2972 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2975 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2978 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2979 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2982 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2985 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2986 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2987 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2988 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2989 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2990 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2994 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2995 g_assert_not_reached ();
2998 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2999 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3000 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3001 g_assert_not_reached ();
3007 last_offset = offset;
3012 cfg->code_len = code - cfg->native_code;
3016 mono_arch_register_lowlevel_calls (void)
3020 #define patch_lis_ori(ip,val) do {\
3021 guint16 *__lis_ori = (guint16*)(ip); \
3022 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3023 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3027 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3029 MonoJumpInfo *patch_info;
3031 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3032 unsigned char *ip = patch_info->ip.i + code;
3033 const unsigned char *target;
3035 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3037 switch (patch_info->type) {
3038 case MONO_PATCH_INFO_IP:
3039 patch_lis_ori (ip, ip);
3041 case MONO_PATCH_INFO_METHOD_REL:
3042 g_assert_not_reached ();
3043 *((gpointer *)(ip)) = code + patch_info->data.offset;
3045 case MONO_PATCH_INFO_SWITCH: {
3046 gpointer *table = (gpointer *)patch_info->data.table->table;
3049 patch_lis_ori (ip, table);
3051 for (i = 0; i < patch_info->data.table->table_size; i++) {
3052 table [i] = (int)patch_info->data.table->table [i] + code;
3054 /* we put into the table the absolute address, no need for ppc_patch in this case */
3057 case MONO_PATCH_INFO_METHODCONST:
3058 case MONO_PATCH_INFO_CLASS:
3059 case MONO_PATCH_INFO_IMAGE:
3060 case MONO_PATCH_INFO_FIELD:
3061 case MONO_PATCH_INFO_VTABLE:
3062 case MONO_PATCH_INFO_IID:
3063 case MONO_PATCH_INFO_SFLDA:
3064 case MONO_PATCH_INFO_LDSTR:
3065 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3066 case MONO_PATCH_INFO_LDTOKEN:
3067 /* from OP_AOTCONST : lis + ori */
3068 patch_lis_ori (ip, target);
3070 case MONO_PATCH_INFO_R4:
3071 case MONO_PATCH_INFO_R8:
3072 g_assert_not_reached ();
3073 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3075 case MONO_PATCH_INFO_EXC_NAME:
3076 g_assert_not_reached ();
3077 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3079 case MONO_PATCH_INFO_NONE:
3080 case MONO_PATCH_INFO_BB_OVF:
3081 case MONO_PATCH_INFO_EXC_OVF:
3082 /* everything is dealt with at epilog output time */
3087 ppc_patch (ip, target);
3092 * Stack frame layout:
3094 * ------------------- sp
3095 * MonoLMF structure or saved registers
3096 * -------------------
3098 * -------------------
3100 * -------------------
3101 * optional 8 bytes for tracing
3102 * -------------------
3103 * param area size is cfg->param_area
3104 * -------------------
3105 * linkage area size is PPC_STACK_PARAM_OFFSET
3106 * ------------------- sp
3110 mono_arch_emit_prolog (MonoCompile *cfg)
3112 MonoMethod *method = cfg->method;
3114 MonoMethodSignature *sig;
3116 int alloc_size, pos, max_offset, i;
3122 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3125 sig = mono_method_signature (method);
3126 cfg->code_size = 256 + sig->param_count * 20;
3127 code = cfg->native_code = g_malloc (cfg->code_size);
3129 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3130 ppc_mflr (code, ppc_r0);
3131 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3134 alloc_size = cfg->stack_offset;
3137 if (!method->save_lmf) {
3138 /*for (i = 31; i >= 14; --i) {
3139 if (cfg->used_float_regs & (1 << i)) {
3140 pos += sizeof (gdouble);
3141 ppc_stfd (code, i, -pos, ppc_sp);
3144 for (i = 31; i >= 13; --i) {
3145 if (cfg->used_int_regs & (1 << i)) {
3146 pos += sizeof (gulong);
3147 ppc_stw (code, i, -pos, ppc_sp);
3152 pos += sizeof (MonoLMF);
3154 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3155 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3156 for (i = 14; i < 32; i++) {
3157 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3161 // align to PPC_STACK_ALIGNMENT bytes
3162 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3163 alloc_size += PPC_STACK_ALIGNMENT - 1;
3164 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3167 cfg->stack_usage = alloc_size;
3168 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3170 if (ppc_is_imm16 (-alloc_size)) {
3171 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3173 ppc_load (code, ppc_r11, -alloc_size);
3174 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3177 if (cfg->frame_reg != ppc_sp)
3178 ppc_mr (code, cfg->frame_reg, ppc_sp);
3180 /* compute max_offset in order to use short forward jumps
3181 * we always do it on ppc because the immediate displacement
3182 * for jumps is too small
3185 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3186 MonoInst *ins = bb->code;
3187 bb->max_offset = max_offset;
3189 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3193 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3198 /* load arguments allocated to register from the stack */
3201 cinfo = calculate_sizes (sig, sig->pinvoke);
3203 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3204 ArgInfo *ainfo = &cinfo->ret;
3206 if (ppc_is_imm16 (inst->inst_offset)) {
3207 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3209 ppc_load (code, ppc_r11, inst->inst_offset);
3210 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3213 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3214 ArgInfo *ainfo = cinfo->args + i;
3215 inst = cfg->args [pos];
3217 if (cfg->verbose_level > 2)
3218 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3219 if (inst->opcode == OP_REGVAR) {
3220 if (ainfo->regtype == RegTypeGeneral)
3221 ppc_mr (code, inst->dreg, ainfo->reg);
3222 else if (ainfo->regtype == RegTypeFP)
3223 ppc_fmr (code, inst->dreg, ainfo->reg);
3224 else if (ainfo->regtype == RegTypeBase) {
3225 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3226 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3228 g_assert_not_reached ();
3230 if (cfg->verbose_level > 2)
3231 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3233 /* the argument should be put on the stack: FIXME handle size != word */
3234 if (ainfo->regtype == RegTypeGeneral) {
3235 switch (ainfo->size) {
3237 if (ppc_is_imm16 (inst->inst_offset)) {
3238 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3240 ppc_load (code, ppc_r11, inst->inst_offset);
3241 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3245 if (ppc_is_imm16 (inst->inst_offset)) {
3246 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3248 ppc_load (code, ppc_r11, inst->inst_offset);
3249 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3253 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3254 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3255 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3257 ppc_load (code, ppc_r11, inst->inst_offset);
3258 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3259 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3260 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3264 if (ppc_is_imm16 (inst->inst_offset)) {
3265 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3267 ppc_load (code, ppc_r11, inst->inst_offset);
3268 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3272 } else if (ainfo->regtype == RegTypeBase) {
3273 /* load the previous stack pointer in r11 */
3274 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3275 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3276 switch (ainfo->size) {
3278 if (ppc_is_imm16 (inst->inst_offset)) {
3279 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3281 ppc_load (code, ppc_r11, inst->inst_offset);
3282 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3286 if (ppc_is_imm16 (inst->inst_offset)) {
3287 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3289 ppc_load (code, ppc_r11, inst->inst_offset);
3290 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3294 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3295 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3296 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3297 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3300 g_assert_not_reached ();
3304 if (ppc_is_imm16 (inst->inst_offset)) {
3305 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3307 ppc_load (code, ppc_r11, inst->inst_offset);
3308 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3312 } else if (ainfo->regtype == RegTypeFP) {
3313 g_assert (ppc_is_imm16 (inst->inst_offset));
3314 if (ainfo->size == 8)
3315 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3316 else if (ainfo->size == 4)
3317 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3319 g_assert_not_reached ();
3320 } else if (ainfo->regtype == RegTypeStructByVal) {
3321 int doffset = inst->inst_offset;
3325 g_assert (ppc_is_imm16 (inst->inst_offset));
3326 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3327 if (mono_class_from_mono_type (inst->inst_vtype))
3328 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3329 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3331 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3332 register. Should this case include linux/ppc?
3336 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3338 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3341 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3342 soffset += sizeof (gpointer);
3343 doffset += sizeof (gpointer);
3345 if (ainfo->vtsize) {
3346 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3347 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3348 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3349 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3351 } else if (ainfo->regtype == RegTypeStructByAddr) {
3352 /* if it was originally a RegTypeBase */
3353 if (ainfo->offset) {
3354 /* load the previous stack pointer in r11 */
3355 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3356 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3358 ppc_mr (code, ppc_r11, ainfo->reg);
3360 g_assert (ppc_is_imm16 (inst->inst_offset));
3361 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3362 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3364 g_assert_not_reached ();
3369 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3370 ppc_load (code, ppc_r3, cfg->domain);
3371 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3372 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3373 ppc_lis (code, ppc_r0, 0);
3374 ppc_ori (code, ppc_r0, ppc_r0, 0);
3375 ppc_mtlr (code, ppc_r0);
3382 if (method->save_lmf) {
3383 if (lmf_pthread_key != -1) {
3384 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3385 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3386 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3388 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3389 (gpointer)"mono_get_lmf_addr");
3390 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3391 ppc_lis (code, ppc_r0, 0);
3392 ppc_ori (code, ppc_r0, ppc_r0, 0);
3393 ppc_mtlr (code, ppc_r0);
3399 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3400 /* lmf_offset is the offset from the previous stack pointer,
3401 * alloc_size is the total stack space allocated, so the offset
3402 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3403 * The pointer to the struct is put in ppc_r11 (new_lmf).
3404 * The callee-saved registers are already in the MonoLMF structure
3406 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3407 /* ppc_r3 is the result from mono_get_lmf_addr () */
3408 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3409 /* new_lmf->previous_lmf = *lmf_addr */
3410 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3411 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3412 /* *(lmf_addr) = r11 */
3413 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3414 /* save method info */
3415 ppc_load (code, ppc_r0, method);
3416 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3417 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3418 /* save the current IP */
3419 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3420 ppc_load (code, ppc_r0, 0x01010101);
3421 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3425 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3427 cfg->code_len = code - cfg->native_code;
3428 g_assert (cfg->code_len < cfg->code_size);
3435 mono_arch_emit_epilog (MonoCompile *cfg)
3437 MonoJumpInfo *patch_info;
3438 MonoMethod *method = cfg->method;
3440 int max_epilog_size = 16 + 20*4;
3443 if (cfg->method->save_lmf)
3444 max_epilog_size += 128;
3446 if (mono_jit_trace_calls != NULL)
3447 max_epilog_size += 50;
3449 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3450 max_epilog_size += 50;
3452 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3453 cfg->code_size *= 2;
3454 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3455 mono_jit_stats.code_reallocs++;
3459 * Keep in sync with OP_JMP
3461 code = cfg->native_code + cfg->code_len;
3463 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3464 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3468 if (method->save_lmf) {
3470 pos += sizeof (MonoLMF);
3472 /* save the frame reg in r8 */
3473 ppc_mr (code, ppc_r8, cfg->frame_reg);
3474 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3475 /* r5 = previous_lmf */
3476 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3478 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3479 /* *(lmf_addr) = previous_lmf */
3480 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3481 /* FIXME: speedup: there is no actual need to restore the registers if
3482 * we didn't actually change them (idea from Zoltan).
3485 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3487 /*for (i = 14; i < 32; i++) {
3488 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3490 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3491 /* use the saved copy of the frame reg in r8 */
3492 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3493 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3494 ppc_mtlr (code, ppc_r0);
3496 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3498 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3499 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3500 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3502 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3503 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3505 ppc_mtlr (code, ppc_r0);
3507 if (ppc_is_imm16 (cfg->stack_usage)) {
3508 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3510 ppc_load (code, ppc_r11, cfg->stack_usage);
3511 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3514 /*for (i = 31; i >= 14; --i) {
3515 if (cfg->used_float_regs & (1 << i)) {
3516 pos += sizeof (double);
3517 ppc_lfd (code, i, -pos, ppc_sp);
3520 for (i = 31; i >= 13; --i) {
3521 if (cfg->used_int_regs & (1 << i)) {
3522 pos += sizeof (gulong);
3523 ppc_lwz (code, i, -pos, ppc_sp);
3529 cfg->code_len = code - cfg->native_code;
3531 g_assert (cfg->code_len < cfg->code_size);
3535 /* remove once throw_exception_by_name is eliminated */
3537 exception_id_by_name (const char *name)
3539 if (strcmp (name, "IndexOutOfRangeException") == 0)
3540 return MONO_EXC_INDEX_OUT_OF_RANGE;
3541 if (strcmp (name, "OverflowException") == 0)
3542 return MONO_EXC_OVERFLOW;
3543 if (strcmp (name, "ArithmeticException") == 0)
3544 return MONO_EXC_ARITHMETIC;
3545 if (strcmp (name, "DivideByZeroException") == 0)
3546 return MONO_EXC_DIVIDE_BY_ZERO;
3547 if (strcmp (name, "InvalidCastException") == 0)
3548 return MONO_EXC_INVALID_CAST;
3549 if (strcmp (name, "NullReferenceException") == 0)
3550 return MONO_EXC_NULL_REF;
3551 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3552 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3553 g_error ("Unknown intrinsic exception %s\n", name);
3558 mono_arch_emit_exceptions (MonoCompile *cfg)
3560 MonoJumpInfo *patch_info;
3563 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3564 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3567 int max_epilog_size = 50;
3569 /* count the number of exception infos */
3572 * make sure we have enough space for exceptions
3573 * 24 is the simulated call to throw_exception_by_name
3575 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3576 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3577 i = exception_id_by_name (patch_info->data.target);
3578 if (!exc_throw_found [i]) {
3579 max_epilog_size += 24;
3580 exc_throw_found [i] = TRUE;
3582 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3583 max_epilog_size += 12;
3584 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3585 MonoOvfJump *ovfj = patch_info->data.target;
3586 i = exception_id_by_name (ovfj->data.exception);
3587 if (!exc_throw_found [i]) {
3588 max_epilog_size += 24;
3589 exc_throw_found [i] = TRUE;
3591 max_epilog_size += 8;
3595 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3596 cfg->code_size *= 2;
3597 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3598 mono_jit_stats.code_reallocs++;
3601 code = cfg->native_code + cfg->code_len;
3603 /* add code to raise exceptions */
3604 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3605 switch (patch_info->type) {
3606 case MONO_PATCH_INFO_BB_OVF: {
3607 MonoOvfJump *ovfj = patch_info->data.target;
3608 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3609 /* patch the initial jump */
3610 ppc_patch (ip, code);
3611 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3613 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3614 /* jump back to the true target */
3616 ip = ovfj->data.bb->native_offset + cfg->native_code;
3617 ppc_patch (code - 4, ip);
3620 case MONO_PATCH_INFO_EXC_OVF: {
3621 MonoOvfJump *ovfj = patch_info->data.target;
3622 MonoJumpInfo *newji;
3623 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3624 unsigned char *bcl = code;
3625 /* patch the initial jump: we arrived here with a call */
3626 ppc_patch (ip, code);
3627 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3629 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3630 /* patch the conditional jump to the right handler */
3631 /* make it processed next */
3632 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3633 newji->type = MONO_PATCH_INFO_EXC;
3634 newji->ip.i = bcl - cfg->native_code;
3635 newji->data.target = ovfj->data.exception;
3636 newji->next = patch_info->next;
3637 patch_info->next = newji;
3640 case MONO_PATCH_INFO_EXC: {
3641 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3642 i = exception_id_by_name (patch_info->data.target);
3643 if (exc_throw_pos [i]) {
3644 ppc_patch (ip, exc_throw_pos [i]);
3645 patch_info->type = MONO_PATCH_INFO_NONE;
3648 exc_throw_pos [i] = code;
3650 ppc_patch (ip, code);
3651 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3652 ppc_load (code, ppc_r3, patch_info->data.target);
3653 /* we got here from a conditional call, so the calling ip is set in lr already */
3654 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3655 patch_info->data.name = "mono_arch_throw_exception_by_name";
3656 patch_info->ip.i = code - cfg->native_code;
3657 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3658 ppc_lis (code, ppc_r0, 0);
3659 ppc_ori (code, ppc_r0, ppc_r0, 0);
3660 ppc_mtctr (code, ppc_r0);
3661 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3673 cfg->code_len = code - cfg->native_code;
3675 g_assert (cfg->code_len < cfg->code_size);
3680 try_offset_access (void *value, guint32 idx)
3682 register void* me __asm__ ("r2");
3683 void ***p = (void***)((char*)me + 284);
3684 int idx1 = idx / 32;
3685 int idx2 = idx % 32;
3688 if (value != p[idx1][idx2])
3694 setup_tls_access (void)
3697 guint32 *ins, *code;
3698 guint32 cmplwi_1023, li_0x48, blr_ins;
3699 if (tls_mode == TLS_MODE_FAILED)
3702 if (g_getenv ("MONO_NO_TLS")) {
3703 tls_mode = TLS_MODE_FAILED;
3707 if (tls_mode == TLS_MODE_DETECT) {
3708 ins = (guint32*)pthread_getspecific;
3709 /* uncond branch to the real method */
3710 if ((*ins >> 26) == 18) {
3712 val = (*ins & ~3) << 6;
3716 ins = (guint32*)val;
3718 ins = (guint32*) ((char*)ins + val);
3721 code = &cmplwi_1023;
3722 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3724 ppc_li (code, ppc_r4, 0x48);
3727 if (*ins == cmplwi_1023) {
3728 int found_lwz_284 = 0;
3729 for (ptk = 0; ptk < 20; ++ptk) {
3731 if (!*ins || *ins == blr_ins)
3733 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3738 if (!found_lwz_284) {
3739 tls_mode = TLS_MODE_FAILED;
3742 tls_mode = TLS_MODE_LTHREADS;
3743 } else if (*ins == li_0x48) {
3745 /* uncond branch to the real method */
3746 if ((*ins >> 26) == 18) {
3748 val = (*ins & ~3) << 6;
3752 ins = (guint32*)val;
3754 ins = (guint32*) ((char*)ins + val);
3757 ppc_li (code, ppc_r0, 0x7FF2);
3758 if (ins [1] == val) {
3759 /* Darwin on G4, implement */
3760 tls_mode = TLS_MODE_FAILED;
3764 ppc_mfspr (code, ppc_r3, 104);
3765 if (ins [1] != val) {
3766 tls_mode = TLS_MODE_FAILED;
3769 tls_mode = TLS_MODE_DARWIN_G5;
3772 tls_mode = TLS_MODE_FAILED;
3776 tls_mode = TLS_MODE_FAILED;
3780 if (monodomain_key == -1) {
3781 ptk = mono_domain_get_tls_key ();
3783 ptk = mono_pthread_key_for_tls (ptk);
3785 monodomain_key = ptk;
3789 if (lmf_pthread_key == -1) {
3790 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3792 /*g_print ("MonoLMF at: %d\n", ptk);*/
3793 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3794 init_tls_failed = 1;
3797 lmf_pthread_key = ptk;
3800 if (monothread_key == -1) {
3801 ptk = mono_thread_get_tls_key ();
3803 ptk = mono_pthread_key_for_tls (ptk);
3805 monothread_key = ptk;
3806 /*g_print ("thread inited: %d\n", ptk);*/
3809 /*g_print ("thread not inited yet %d\n", ptk);*/
3815 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3817 setup_tls_access ();
3821 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3826 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3828 int this_dreg = ppc_r3;
3833 /* add the this argument */
3834 if (this_reg != -1) {
3836 MONO_INST_NEW (cfg, this, OP_SETREG);
3837 this->type = this_type;
3838 this->sreg1 = this_reg;
3839 this->dreg = mono_regstate_next_int (cfg->rs);
3840 mono_bblock_add_inst (cfg->cbb, this);
3841 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3846 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3847 vtarg->type = STACK_MP;
3848 vtarg->sreg1 = vt_reg;
3849 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3850 mono_bblock_add_inst (cfg->cbb, vtarg);
3851 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3856 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3858 MonoInst *ins = NULL;
3860 if (cmethod->klass == mono_defaults.thread_class &&
3861 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3862 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3864 /*if (cmethod->klass == mono_defaults.math_class) {
3865 if (strcmp (cmethod->name, "Sqrt") == 0) {
3866 MONO_INST_NEW (cfg, ins, OP_SQRT);
3867 ins->inst_i0 = args [0];
3874 mono_arch_print_tree (MonoInst *tree, int arity)
3879 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3883 setup_tls_access ();
3884 if (monodomain_key == -1)
3887 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3888 ins->inst_offset = monodomain_key;
3893 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3897 setup_tls_access ();
3898 if (monothread_key == -1)
3901 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3902 ins->inst_offset = monothread_key;