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>
33 int mono_exc_esp_offset = 0;
34 static int tls_mode = TLS_MODE_DETECT;
35 static int lmf_pthread_key = -1;
36 static int monothread_key = -1;
37 static int monodomain_key = -1;
40 offsets_from_pthread_key (guint32 key, int *offset2)
44 *offset2 = idx2 * sizeof (gpointer);
45 return 284 + idx1 * sizeof (gpointer);
48 #define emit_linuxthreads_tls(code,dreg,key) do {\
50 off1 = offsets_from_pthread_key ((key), &off2); \
51 ppc_lwz ((code), (dreg), off1, ppc_r2); \
52 ppc_lwz ((code), (dreg), off2, (dreg)); \
55 #define emit_darwing5_tls(code,dreg,key) do {\
56 int off1 = 0x48 + key * sizeof (gpointer); \
57 ppc_mfspr ((code), (dreg), 104); \
58 ppc_lwz ((code), (dreg), off1, (dreg)); \
61 /* FIXME: ensure the sc call preserves all but r3 */
62 #define emit_darwing4_tls(code,dreg,key) do {\
63 int off1 = 0x48 + key * sizeof (gpointer); \
64 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
65 ppc_li ((code), ppc_r0, 0x7FF2); \
67 ppc_lwz ((code), (dreg), off1, ppc_r3); \
68 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
71 #define emit_tls_access(code,dreg,key) do { \
73 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
74 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
75 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
76 default: g_assert_not_reached (); \
81 mono_arch_regname (int reg) {
82 static const char rnames[][4] = {
83 "r0", "sp", "r2", "r3", "r4",
84 "r5", "r6", "r7", "r8", "r9",
85 "r10", "r11", "r12", "r13", "r14",
86 "r15", "r16", "r17", "r18", "r19",
87 "r20", "r21", "r22", "r23", "r24",
88 "r25", "r26", "r27", "r28", "r29",
91 if (reg >= 0 && reg < 32)
97 mono_arch_fregname (int reg) {
98 static const char rnames[][4] = {
99 "f0", "f1", "f2", "f3", "f4",
100 "f5", "f6", "f7", "f8", "f9",
101 "f10", "f11", "f12", "f13", "f14",
102 "f15", "f16", "f17", "f18", "f19",
103 "f20", "f21", "f22", "f23", "f24",
104 "f25", "f26", "f27", "f28", "f29",
107 if (reg >= 0 && reg < 32)
112 /* this function overwrites r0, r11, r12 */
114 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
116 /* unrolled, use the counter in big */
117 if (size > sizeof (gpointer) * 5) {
118 int shifted = size >> 2;
119 guint8 *copy_loop_start, *copy_loop_jump;
121 ppc_load (code, ppc_r0, shifted);
122 ppc_mtctr (code, ppc_r0);
123 g_assert (sreg == ppc_r11);
124 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
125 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
126 copy_loop_start = code;
127 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
128 ppc_stwu (code, ppc_r0, 4, ppc_r12);
129 copy_loop_jump = code;
130 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
131 ppc_patch (copy_loop_jump, copy_loop_start);
133 doffset = soffset = 0;
137 ppc_lwz (code, ppc_r0, soffset, sreg);
138 ppc_stw (code, ppc_r0, doffset, dreg);
144 ppc_lhz (code, ppc_r0, soffset, sreg);
145 ppc_sth (code, ppc_r0, doffset, dreg);
151 ppc_lbz (code, ppc_r0, soffset, sreg);
152 ppc_stb (code, ppc_r0, doffset, dreg);
161 * mono_arch_get_argument_info:
162 * @csig: a method signature
163 * @param_count: the number of parameters to consider
164 * @arg_info: an array to store the result infos
166 * Gathers information on parameters such as size, alignment and
167 * padding. arg_info should be large enought to hold param_count + 1 entries.
169 * Returns the size of the activation frame.
172 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
174 int k, frame_size = 0;
175 int size, align, pad;
178 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
179 frame_size += sizeof (gpointer);
183 arg_info [0].offset = offset;
186 frame_size += sizeof (gpointer);
190 arg_info [0].size = frame_size;
192 for (k = 0; k < param_count; k++) {
195 size = mono_type_native_stack_size (csig->params [k], &align);
197 size = mono_type_stack_size (csig->params [k], &align);
199 /* ignore alignment for now */
202 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
203 arg_info [k].pad = pad;
205 arg_info [k + 1].pad = 0;
206 arg_info [k + 1].size = size;
208 arg_info [k + 1].offset = offset;
212 align = MONO_ARCH_FRAME_ALIGNMENT;
213 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
214 arg_info [k].pad = pad;
220 * Initialize the cpu to execute managed code.
223 mono_arch_cpu_init (void)
228 * This function returns the optimizations supported on this cpu.
231 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
235 /* no ppc-specific optimizations yet */
241 is_regsize_var (MonoType *t) {
244 t = mono_type_get_underlying_type (t);
251 case MONO_TYPE_FNPTR:
253 case MONO_TYPE_OBJECT:
254 case MONO_TYPE_STRING:
255 case MONO_TYPE_CLASS:
256 case MONO_TYPE_SZARRAY:
257 case MONO_TYPE_ARRAY:
259 case MONO_TYPE_GENERICINST:
260 if (!mono_type_generic_inst_is_valuetype (t))
263 case MONO_TYPE_VALUETYPE:
270 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
275 for (i = 0; i < cfg->num_varinfo; i++) {
276 MonoInst *ins = cfg->varinfo [i];
277 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
280 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
283 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
286 /* we can only allocate 32 bit values */
287 if (is_regsize_var (ins->inst_vtype)) {
288 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
289 g_assert (i == vmv->idx);
290 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
298 mono_arch_get_global_int_regs (MonoCompile *cfg)
302 if (cfg->frame_reg != ppc_sp)
304 for (i = 13; i < top; ++i)
305 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
311 * mono_arch_regalloc_cost:
313 * Return the cost, in number of memory references, of the action of
314 * allocating the variable VMV into a register during global register
318 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
330 mono_arch_flush_icache (guint8 *code, gint size)
332 guint8 *p, *endp, *start;
333 static int cachelinesize = 0;
334 static int cachelineinc = 16;
336 if (!cachelinesize) {
340 mib [1] = HW_CACHELINE;
341 len = sizeof (cachelinesize);
342 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
346 cachelineinc = cachelinesize;
347 /*g_print ("setting cl size to %d\n", cachelinesize);*/
349 #elif defined(__linux__)
350 /* sadly this will work only with 2.6 kernels... */
351 FILE* f = fopen ("/proc/self/auxv", "rb");
354 while (fread (&vec, sizeof (vec), 1, f) == 1) {
355 if (vec.type == 19) {
356 cachelinesize = vec.value;
365 #warning Need a way to get cache line size
371 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
372 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
374 for (p = start; p < endp; p += cachelineinc) {
375 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
378 for (p = start; p < endp; p += cachelineinc) {
379 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
384 for (p = start; p < endp; p += cachelineinc) {
385 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
391 #define NOT_IMPLEMENTED(x) \
392 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
395 #define ALWAYS_ON_STACK(s) s
396 #define FP_ALSO_IN_REG(s) s
398 #define ALWAYS_ON_STACK(s)
399 #define FP_ALSO_IN_REG(s)
400 #define ALIGN_DOUBLES
413 guint16 vtsize; /* in param area */
415 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
416 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
431 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
434 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
435 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
436 ainfo->reg = ppc_sp; /* in the caller */
437 ainfo->regtype = RegTypeBase;
440 ALWAYS_ON_STACK (*stack_size += 4);
444 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
446 //*stack_size += (*stack_size % 8);
448 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
449 ainfo->reg = ppc_sp; /* in the caller */
450 ainfo->regtype = RegTypeBase;
457 ALWAYS_ON_STACK (*stack_size += 8);
466 /* size == 4 is checked already */
468 has_only_a_r4_field (MonoClass *klass)
473 while ((f = mono_class_get_fields (klass, &iter))) {
474 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
475 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
485 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
488 int n = sig->hasthis + sig->param_count;
490 guint32 stack_size = 0;
491 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
493 fr = PPC_FIRST_FPARG_REG;
494 gr = PPC_FIRST_ARG_REG;
496 /* FIXME: handle returning a struct */
497 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
498 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
499 cinfo->struct_ret = PPC_FIRST_ARG_REG;
504 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
507 DEBUG(printf("params: %d\n", sig->param_count));
508 for (i = 0; i < sig->param_count; ++i) {
509 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
510 /* Prevent implicit arguments and sig_cookie from
511 being passed in registers */
512 gr = PPC_LAST_ARG_REG + 1;
513 /* Emit the signature cookie just before the implicit arguments */
514 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
516 DEBUG(printf("param %d: ", i));
517 if (sig->params [i]->byref) {
518 DEBUG(printf("byref\n"));
519 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
523 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
524 switch (simpletype) {
525 case MONO_TYPE_BOOLEAN:
528 cinfo->args [n].size = 1;
529 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
535 cinfo->args [n].size = 2;
536 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
541 cinfo->args [n].size = 4;
542 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
548 case MONO_TYPE_FNPTR:
549 case MONO_TYPE_CLASS:
550 case MONO_TYPE_OBJECT:
551 case MONO_TYPE_STRING:
552 case MONO_TYPE_SZARRAY:
553 case MONO_TYPE_ARRAY:
554 cinfo->args [n].size = sizeof (gpointer);
555 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
558 case MONO_TYPE_GENERICINST:
559 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
560 cinfo->args [n].size = sizeof (gpointer);
561 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
566 case MONO_TYPE_VALUETYPE: {
569 klass = mono_class_from_mono_type (sig->params [i]);
571 size = mono_class_native_size (klass, NULL);
573 size = mono_class_value_size (klass, NULL);
575 if (size == 4 && has_only_a_r4_field (klass)) {
576 cinfo->args [n].size = 4;
578 /* It was 7, now it is 8 in LinuxPPC */
579 if (fr <= PPC_LAST_FPARG_REG) {
580 cinfo->args [n].regtype = RegTypeFP;
581 cinfo->args [n].reg = fr;
583 FP_ALSO_IN_REG (gr ++);
584 ALWAYS_ON_STACK (stack_size += 4);
586 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
587 cinfo->args [n].regtype = RegTypeBase;
588 cinfo->args [n].reg = ppc_sp; /* in the caller*/
595 DEBUG(printf ("load %d bytes struct\n",
596 mono_class_native_size (sig->params [i]->data.klass, NULL)));
597 #if PPC_PASS_STRUCTS_BY_VALUE
599 int align_size = size;
601 align_size += (sizeof (gpointer) - 1);
602 align_size &= ~(sizeof (gpointer) - 1);
603 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
604 cinfo->args [n].regtype = RegTypeStructByVal;
605 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
606 cinfo->args [n].size = 0;
607 cinfo->args [n].vtsize = nwords;
609 int rest = PPC_LAST_ARG_REG - gr + 1;
610 int n_in_regs = rest >= nwords? nwords: rest;
611 cinfo->args [n].size = n_in_regs;
612 cinfo->args [n].vtsize = nwords - n_in_regs;
613 cinfo->args [n].reg = gr;
616 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
617 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
618 stack_size += nwords * sizeof (gpointer);
621 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
622 cinfo->args [n].regtype = RegTypeStructByAddr;
627 case MONO_TYPE_TYPEDBYREF: {
628 int size = sizeof (MonoTypedRef);
629 /* keep in sync or merge with the valuetype case */
630 #if PPC_PASS_STRUCTS_BY_VALUE
632 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
633 cinfo->args [n].regtype = RegTypeStructByVal;
634 if (gr <= PPC_LAST_ARG_REG) {
635 int rest = PPC_LAST_ARG_REG - gr + 1;
636 int n_in_regs = rest >= nwords? nwords: rest;
637 cinfo->args [n].size = n_in_regs;
638 cinfo->args [n].vtsize = nwords - n_in_regs;
639 cinfo->args [n].reg = gr;
642 cinfo->args [n].size = 0;
643 cinfo->args [n].vtsize = nwords;
645 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
646 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
647 stack_size += nwords * sizeof (gpointer);
650 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
651 cinfo->args [n].regtype = RegTypeStructByAddr;
658 cinfo->args [n].size = 8;
659 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
663 cinfo->args [n].size = 4;
665 /* It was 7, now it is 8 in LinuxPPC */
666 if (fr <= PPC_LAST_FPARG_REG) {
667 cinfo->args [n].regtype = RegTypeFP;
668 cinfo->args [n].reg = fr;
670 FP_ALSO_IN_REG (gr ++);
671 ALWAYS_ON_STACK (stack_size += 4);
673 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
674 cinfo->args [n].regtype = RegTypeBase;
675 cinfo->args [n].reg = ppc_sp; /* in the caller*/
681 cinfo->args [n].size = 8;
682 /* It was 7, now it is 8 in LinuxPPC */
683 if (fr <= PPC_LAST_FPARG_REG) {
684 cinfo->args [n].regtype = RegTypeFP;
685 cinfo->args [n].reg = fr;
687 FP_ALSO_IN_REG (gr += 2);
688 ALWAYS_ON_STACK (stack_size += 8);
690 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
691 cinfo->args [n].regtype = RegTypeBase;
692 cinfo->args [n].reg = ppc_sp; /* in the caller*/
698 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
703 simpletype = mono_type_get_underlying_type (sig->ret)->type;
704 switch (simpletype) {
705 case MONO_TYPE_BOOLEAN:
716 case MONO_TYPE_FNPTR:
717 case MONO_TYPE_CLASS:
718 case MONO_TYPE_OBJECT:
719 case MONO_TYPE_SZARRAY:
720 case MONO_TYPE_ARRAY:
721 case MONO_TYPE_STRING:
722 cinfo->ret.reg = ppc_r3;
726 cinfo->ret.reg = ppc_r3;
730 cinfo->ret.reg = ppc_f1;
731 cinfo->ret.regtype = RegTypeFP;
733 case MONO_TYPE_GENERICINST:
734 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
735 cinfo->ret.reg = ppc_r3;
739 case MONO_TYPE_VALUETYPE:
741 case MONO_TYPE_TYPEDBYREF:
745 g_error ("Can't handle as return value 0x%x", sig->ret->type);
749 /* align stack size to 16 */
750 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
751 stack_size = (stack_size + 15) & ~15;
753 cinfo->stack_usage = stack_size;
759 * Set var information according to the calling convention. ppc version.
760 * The locals var stuff should most likely be split in another method.
763 mono_arch_allocate_vars (MonoCompile *m)
765 MonoMethodSignature *sig;
766 MonoMethodHeader *header;
768 int i, offset, size, align, curinst;
769 int frame_reg = ppc_sp;
771 m->flags |= MONO_CFG_HAS_SPILLUP;
773 /* allow room for the vararg method args: void* and long/double */
774 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
775 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
776 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
777 * call convs needs to be handled this way.
779 if (m->flags & MONO_CFG_HAS_VARARGS)
780 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
781 /* gtk-sharp and other broken code will dllimport vararg functions even with
782 * non-varargs signatures. Since there is little hope people will get this right
783 * we assume they won't.
785 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
786 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
788 header = mono_method_get_header (m->method);
791 * We use the frame register also for any method that has
792 * exception clauses. This way, when the handlers are called,
793 * the code will reference local variables using the frame reg instead of
794 * the stack pointer: if we had to restore the stack pointer, we'd
795 * corrupt the method frames that are already on the stack (since
796 * filters get called before stack unwinding happens) when the filter
797 * code would call any method (this also applies to finally etc.).
799 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
801 m->frame_reg = frame_reg;
802 if (frame_reg != ppc_sp) {
803 m->used_int_regs |= 1 << frame_reg;
806 sig = mono_method_signature (m->method);
810 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
811 m->ret->opcode = OP_REGVAR;
812 m->ret->inst_c0 = ppc_r3;
814 /* FIXME: handle long and FP values */
815 switch (mono_type_get_underlying_type (sig->ret)->type) {
819 m->ret->opcode = OP_REGVAR;
820 m->ret->inst_c0 = ppc_r3;
824 /* local vars are at a positive offset from the stack pointer */
826 * also note that if the function uses alloca, we use ppc_r31
827 * to point at the local variables.
829 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
830 /* align the offset to 16 bytes: not sure this is needed here */
832 //offset &= ~(16 - 1);
834 /* add parameter area size for called functions */
835 offset += m->param_area;
839 /* allow room to save the return value */
840 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
843 /* the MonoLMF structure is stored just below the stack pointer */
846 /* this stuff should not be needed on ppc and the new jit,
847 * because a call on ppc to the handlers doesn't change the
848 * stack pointer and the jist doesn't manipulate the stack pointer
849 * for operations involving valuetypes.
851 /* reserve space to store the esp */
852 offset += sizeof (gpointer);
854 /* this is a global constant */
855 mono_exc_esp_offset = offset;
857 if (sig->call_convention == MONO_CALL_VARARG) {
858 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
861 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
863 offset += sizeof(gpointer) - 1;
864 offset &= ~(sizeof(gpointer) - 1);
865 inst->inst_offset = offset;
866 inst->opcode = OP_REGOFFSET;
867 inst->inst_basereg = frame_reg;
868 offset += sizeof(gpointer);
869 if (sig->call_convention == MONO_CALL_VARARG)
870 m->sig_cookie += sizeof (gpointer);
873 curinst = m->locals_start;
874 for (i = curinst; i < m->num_varinfo; ++i) {
875 inst = m->varinfo [i];
876 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
879 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
880 * pinvoke wrappers when they call functions returning structure */
881 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
882 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
884 size = mono_type_size (inst->inst_vtype, &align);
887 offset &= ~(align - 1);
888 inst->inst_offset = offset;
889 inst->opcode = OP_REGOFFSET;
890 inst->inst_basereg = frame_reg;
892 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
897 inst = m->varinfo [curinst];
898 if (inst->opcode != OP_REGVAR) {
899 inst->opcode = OP_REGOFFSET;
900 inst->inst_basereg = frame_reg;
901 offset += sizeof (gpointer) - 1;
902 offset &= ~(sizeof (gpointer) - 1);
903 inst->inst_offset = offset;
904 offset += sizeof (gpointer);
905 if (sig->call_convention == MONO_CALL_VARARG)
906 m->sig_cookie += sizeof (gpointer);
911 for (i = 0; i < sig->param_count; ++i) {
912 inst = m->varinfo [curinst];
913 if (inst->opcode != OP_REGVAR) {
914 inst->opcode = OP_REGOFFSET;
915 inst->inst_basereg = frame_reg;
916 size = mono_type_size (sig->params [i], &align);
918 offset &= ~(align - 1);
919 inst->inst_offset = offset;
921 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
922 m->sig_cookie += size;
927 /* align the offset to 16 bytes */
932 m->stack_offset = offset;
936 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
937 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
941 * take the arguments and generate the arch-specific
942 * instructions to properly call the function in call.
943 * This includes pushing, moving arguments to the right register
945 * Issue: who does the spilling if needed, and when?
948 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
950 MonoMethodSignature *sig;
955 sig = call->signature;
956 n = sig->param_count + sig->hasthis;
958 cinfo = calculate_sizes (sig, sig->pinvoke);
959 if (cinfo->struct_ret)
960 call->used_iregs |= 1 << cinfo->struct_ret;
962 for (i = 0; i < n; ++i) {
963 ainfo = cinfo->args + i;
964 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
966 cfg->disable_aot = TRUE;
968 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
969 sig_arg->inst_p0 = call->signature;
971 MONO_INST_NEW (cfg, arg, OP_OUTARG);
972 arg->inst_imm = cinfo->sig_cookie.offset;
973 arg->inst_left = sig_arg;
975 /* prepend, so they get reversed */
976 arg->next = call->out_args;
977 call->out_args = arg;
979 if (is_virtual && i == 0) {
980 /* the argument will be attached to the call instrucion */
982 call->used_iregs |= 1 << ainfo->reg;
984 MONO_INST_NEW (cfg, arg, OP_OUTARG);
986 arg->cil_code = in->cil_code;
988 arg->inst_call = call;
989 arg->type = in->type;
990 /* prepend, we'll need to reverse them later */
991 arg->next = call->out_args;
992 call->out_args = arg;
993 if (ainfo->regtype == RegTypeGeneral) {
994 arg->backend.reg3 = ainfo->reg;
995 call->used_iregs |= 1 << ainfo->reg;
996 if (arg->type == STACK_I8)
997 call->used_iregs |= 1 << (ainfo->reg + 1);
998 } else if (ainfo->regtype == RegTypeStructByAddr) {
999 /* FIXME: where si the data allocated? */
1000 arg->backend.reg3 = ainfo->reg;
1001 call->used_iregs |= 1 << ainfo->reg;
1002 } else if (ainfo->regtype == RegTypeStructByVal) {
1004 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1005 /* mark the used regs */
1006 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1007 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1009 arg->opcode = OP_OUTARG_VT;
1010 ai->reg = ainfo->reg;
1011 ai->size = ainfo->size;
1012 ai->vtsize = ainfo->vtsize;
1013 ai->offset = ainfo->offset;
1014 arg->backend.data = ai;
1015 } else if (ainfo->regtype == RegTypeBase) {
1016 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1017 arg->opcode = OP_OUTARG_MEMBASE;
1018 ai->reg = ainfo->reg;
1019 ai->size = ainfo->size;
1020 ai->offset = ainfo->offset;
1021 arg->backend.data = ai;
1022 } else if (ainfo->regtype == RegTypeFP) {
1023 arg->opcode = OP_OUTARG_R8;
1024 arg->backend.reg3 = ainfo->reg;
1025 call->used_fregs |= 1 << ainfo->reg;
1026 if (ainfo->size == 4) {
1027 arg->opcode = OP_OUTARG_R8;
1028 /* we reduce the precision */
1030 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1031 conv->inst_left = arg->inst_left;
1032 arg->inst_left = conv;*/
1035 g_assert_not_reached ();
1040 * Reverse the call->out_args list.
1043 MonoInst *prev = NULL, *list = call->out_args, *next;
1050 call->out_args = prev;
1052 call->stack_usage = cinfo->stack_usage;
1053 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1054 cfg->flags |= MONO_CFG_HAS_CALLS;
1056 * should set more info in call, such as the stack space
1057 * used by the args that needs to be added back to esp
1065 * Allow tracing to work with this interface (with an optional argument)
1069 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1073 ppc_load (code, ppc_r3, cfg->method);
1074 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1075 ppc_load (code, ppc_r0, func);
1076 ppc_mtlr (code, ppc_r0);
1090 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1093 int save_mode = SAVE_NONE;
1095 MonoMethod *method = cfg->method;
1096 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1097 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1101 offset = code - cfg->native_code;
1102 /* we need about 16 instructions */
1103 if (offset > (cfg->code_size - 16 * 4)) {
1104 cfg->code_size *= 2;
1105 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1106 code = cfg->native_code + offset;
1110 case MONO_TYPE_VOID:
1111 /* special case string .ctor icall */
1112 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1113 save_mode = SAVE_ONE;
1115 save_mode = SAVE_NONE;
1119 save_mode = SAVE_TWO;
1123 save_mode = SAVE_FP;
1125 case MONO_TYPE_VALUETYPE:
1126 save_mode = SAVE_STRUCT;
1129 save_mode = SAVE_ONE;
1133 switch (save_mode) {
1135 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1136 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1137 if (enable_arguments) {
1138 ppc_mr (code, ppc_r5, ppc_r4);
1139 ppc_mr (code, ppc_r4, ppc_r3);
1143 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1144 if (enable_arguments) {
1145 ppc_mr (code, ppc_r4, ppc_r3);
1149 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1150 if (enable_arguments) {
1151 /* FIXME: what reg? */
1152 ppc_fmr (code, ppc_f3, ppc_f1);
1153 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1154 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1158 if (enable_arguments) {
1159 /* FIXME: get the actual address */
1160 ppc_mr (code, ppc_r4, ppc_r3);
1168 ppc_load (code, ppc_r3, cfg->method);
1169 ppc_load (code, ppc_r0, func);
1170 ppc_mtlr (code, ppc_r0);
1173 switch (save_mode) {
1175 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1176 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1179 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1182 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1192 * Conditional branches have a small offset, so if it is likely overflowed,
1193 * we do a branch to the end of the method (uncond branches have much larger
1194 * offsets) where we perform the conditional and jump back unconditionally.
1195 * It's slightly slower, since we add two uncond branches, but it's very simple
1196 * with the current patch implementation and such large methods are likely not
1197 * going to be perf critical anyway.
1202 const char *exception;
1209 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1210 if (ins->flags & MONO_INST_BRLABEL) { \
1211 if (0 && ins->inst_i0->inst_c0) { \
1212 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1214 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1215 ppc_bc (code, (b0), (b1), 0); \
1218 if (0 && ins->inst_true_bb->native_offset) { \
1219 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1221 int br_disp = ins->inst_true_bb->max_offset - offset; \
1222 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1223 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1224 ovfj->data.bb = ins->inst_true_bb; \
1225 ovfj->ip_offset = 0; \
1226 ovfj->b0_cond = (b0); \
1227 ovfj->b1_cond = (b1); \
1228 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1231 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1232 ppc_bc (code, (b0), (b1), 0); \
1237 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1239 /* emit an exception if condition is fail
1241 * We assign the extra code used to throw the implicit exceptions
1242 * to cfg->bb_exit as far as the big branch handling is concerned
1244 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1246 int br_disp = cfg->bb_exit->max_offset - offset; \
1247 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1248 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1249 ovfj->data.exception = (exc_name); \
1250 ovfj->ip_offset = code - cfg->native_code; \
1251 ovfj->b0_cond = (b0); \
1252 ovfj->b1_cond = (b1); \
1253 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1255 cfg->bb_exit->max_offset += 24; \
1257 mono_add_patch_info (cfg, code - cfg->native_code, \
1258 MONO_PATCH_INFO_EXC, exc_name); \
1259 ppc_bcl (code, (b0), (b1), 0); \
1263 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1266 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1268 MonoInst *ins, *last_ins = NULL;
1273 switch (ins->opcode) {
1275 /* remove unnecessary multiplication with 1 */
1276 if (ins->inst_imm == 1) {
1277 if (ins->dreg != ins->sreg1) {
1278 ins->opcode = OP_MOVE;
1280 last_ins->next = ins->next;
1285 int power2 = mono_is_power_of_two (ins->inst_imm);
1287 ins->opcode = OP_SHL_IMM;
1288 ins->inst_imm = power2;
1292 case OP_LOAD_MEMBASE:
1293 case OP_LOADI4_MEMBASE:
1295 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1296 * OP_LOAD_MEMBASE offset(basereg), reg
1298 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1299 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1300 ins->inst_basereg == last_ins->inst_destbasereg &&
1301 ins->inst_offset == last_ins->inst_offset) {
1302 if (ins->dreg == last_ins->sreg1) {
1303 last_ins->next = ins->next;
1307 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1308 ins->opcode = OP_MOVE;
1309 ins->sreg1 = last_ins->sreg1;
1313 * Note: reg1 must be different from the basereg in the second load
1314 * OP_LOAD_MEMBASE offset(basereg), reg1
1315 * OP_LOAD_MEMBASE offset(basereg), reg2
1317 * OP_LOAD_MEMBASE offset(basereg), reg1
1318 * OP_MOVE reg1, reg2
1320 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1321 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1322 ins->inst_basereg != last_ins->dreg &&
1323 ins->inst_basereg == last_ins->inst_basereg &&
1324 ins->inst_offset == last_ins->inst_offset) {
1326 if (ins->dreg == last_ins->dreg) {
1327 last_ins->next = ins->next;
1331 ins->opcode = OP_MOVE;
1332 ins->sreg1 = last_ins->dreg;
1335 //g_assert_not_reached ();
1339 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1340 * OP_LOAD_MEMBASE offset(basereg), reg
1342 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1343 * OP_ICONST reg, imm
1345 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1346 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1347 ins->inst_basereg == last_ins->inst_destbasereg &&
1348 ins->inst_offset == last_ins->inst_offset) {
1349 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1350 ins->opcode = OP_ICONST;
1351 ins->inst_c0 = last_ins->inst_imm;
1352 g_assert_not_reached (); // check this rule
1356 case OP_LOADU1_MEMBASE:
1357 case OP_LOADI1_MEMBASE:
1358 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1359 ins->inst_basereg == last_ins->inst_destbasereg &&
1360 ins->inst_offset == last_ins->inst_offset) {
1361 if (ins->dreg == last_ins->sreg1) {
1362 last_ins->next = ins->next;
1366 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1367 ins->opcode = OP_MOVE;
1368 ins->sreg1 = last_ins->sreg1;
1372 case OP_LOADU2_MEMBASE:
1373 case OP_LOADI2_MEMBASE:
1374 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1375 ins->inst_basereg == last_ins->inst_destbasereg &&
1376 ins->inst_offset == last_ins->inst_offset) {
1377 if (ins->dreg == last_ins->sreg1) {
1378 last_ins->next = ins->next;
1382 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1383 ins->opcode = OP_MOVE;
1384 ins->sreg1 = last_ins->sreg1;
1392 ins->opcode = OP_MOVE;
1396 if (ins->dreg == ins->sreg1) {
1398 last_ins->next = ins->next;
1403 * OP_MOVE sreg, dreg
1404 * OP_MOVE dreg, sreg
1406 if (last_ins && last_ins->opcode == OP_MOVE &&
1407 ins->sreg1 == last_ins->dreg &&
1408 ins->dreg == last_ins->sreg1) {
1409 last_ins->next = ins->next;
1418 bb->last_ins = last_ins;
1422 * the branch_b0_table should maintain the order of these
1436 branch_b0_table [] = {
1451 branch_b1_table [] = {
1465 static const char*const * ins_spec = ppcg4;
1468 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1472 bb->code = to_insert;
1473 to_insert->next = ins;
1475 to_insert->next = ins->next;
1476 ins->next = to_insert;
1480 #define NEW_INS(cfg,dest,op) do { \
1481 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1482 (dest)->opcode = (op); \
1483 insert_after_ins (bb, last_ins, (dest)); \
1487 map_to_reg_reg_op (int op)
1496 case OP_COMPARE_IMM:
1512 case OP_LOAD_MEMBASE:
1513 return OP_LOAD_MEMINDEX;
1514 case OP_LOADI4_MEMBASE:
1515 return OP_LOADI4_MEMINDEX;
1516 case OP_LOADU4_MEMBASE:
1517 return OP_LOADU4_MEMINDEX;
1518 case OP_LOADU1_MEMBASE:
1519 return OP_LOADU1_MEMINDEX;
1520 case OP_LOADI2_MEMBASE:
1521 return OP_LOADI2_MEMINDEX;
1522 case OP_LOADU2_MEMBASE:
1523 return OP_LOADU2_MEMINDEX;
1524 case OP_LOADI1_MEMBASE:
1525 return OP_LOADI1_MEMINDEX;
1526 case OP_LOADR4_MEMBASE:
1527 return OP_LOADR4_MEMINDEX;
1528 case OP_LOADR8_MEMBASE:
1529 return OP_LOADR8_MEMINDEX;
1530 case OP_STOREI1_MEMBASE_REG:
1531 return OP_STOREI1_MEMINDEX;
1532 case OP_STOREI2_MEMBASE_REG:
1533 return OP_STOREI2_MEMINDEX;
1534 case OP_STOREI4_MEMBASE_REG:
1535 return OP_STOREI4_MEMINDEX;
1536 case OP_STORE_MEMBASE_REG:
1537 return OP_STORE_MEMINDEX;
1538 case OP_STORER4_MEMBASE_REG:
1539 return OP_STORER4_MEMINDEX;
1540 case OP_STORER8_MEMBASE_REG:
1541 return OP_STORER8_MEMINDEX;
1542 case OP_STORE_MEMBASE_IMM:
1543 return OP_STORE_MEMBASE_REG;
1544 case OP_STOREI1_MEMBASE_IMM:
1545 return OP_STOREI1_MEMBASE_REG;
1546 case OP_STOREI2_MEMBASE_IMM:
1547 return OP_STOREI2_MEMBASE_REG;
1548 case OP_STOREI4_MEMBASE_IMM:
1549 return OP_STOREI4_MEMBASE_REG;
1551 g_assert_not_reached ();
1554 #define compare_opcode_is_unsigned(opcode) \
1555 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1556 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1557 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1559 * Remove from the instruction list the instructions that can't be
1560 * represented with very simple instructions with no register
1564 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1566 MonoInst *ins, *next, *temp, *last_ins = NULL;
1569 /* setup the virtual reg allocator */
1570 if (bb->max_ireg > cfg->rs->next_vireg)
1571 cfg->rs->next_vireg = bb->max_ireg;
1576 switch (ins->opcode) {
1579 if (!ppc_is_imm16 (ins->inst_imm)) {
1580 NEW_INS (cfg, temp, OP_ICONST);
1581 temp->inst_c0 = ins->inst_imm;
1582 temp->dreg = mono_regstate_next_int (cfg->rs);
1583 ins->sreg2 = temp->dreg;
1584 ins->opcode = map_to_reg_reg_op (ins->opcode);
1588 if (!ppc_is_imm16 (-ins->inst_imm)) {
1589 NEW_INS (cfg, temp, OP_ICONST);
1590 temp->inst_c0 = ins->inst_imm;
1591 temp->dreg = mono_regstate_next_int (cfg->rs);
1592 ins->sreg2 = temp->dreg;
1593 ins->opcode = map_to_reg_reg_op (ins->opcode);
1599 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1600 NEW_INS (cfg, temp, OP_ICONST);
1601 temp->inst_c0 = ins->inst_imm;
1602 temp->dreg = mono_regstate_next_int (cfg->rs);
1603 ins->sreg2 = temp->dreg;
1604 ins->opcode = map_to_reg_reg_op (ins->opcode);
1610 NEW_INS (cfg, temp, OP_ICONST);
1611 temp->inst_c0 = ins->inst_imm;
1612 temp->dreg = mono_regstate_next_int (cfg->rs);
1613 ins->sreg2 = temp->dreg;
1614 ins->opcode = map_to_reg_reg_op (ins->opcode);
1616 case OP_COMPARE_IMM:
1617 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1618 if (!ppc_is_uimm16 (ins->inst_imm)) {
1619 NEW_INS (cfg, temp, OP_ICONST);
1620 temp->inst_c0 = ins->inst_imm;
1621 temp->dreg = mono_regstate_next_int (cfg->rs);
1622 ins->sreg2 = temp->dreg;
1623 ins->opcode = map_to_reg_reg_op (ins->opcode);
1626 if (!ppc_is_imm16 (ins->inst_imm)) {
1627 NEW_INS (cfg, temp, OP_ICONST);
1628 temp->inst_c0 = ins->inst_imm;
1629 temp->dreg = mono_regstate_next_int (cfg->rs);
1630 ins->sreg2 = temp->dreg;
1631 ins->opcode = map_to_reg_reg_op (ins->opcode);
1636 if (ins->inst_imm == 1) {
1637 ins->opcode = OP_MOVE;
1640 if (ins->inst_imm == 0) {
1641 ins->opcode = OP_ICONST;
1645 imm = mono_is_power_of_two (ins->inst_imm);
1647 ins->opcode = OP_SHL_IMM;
1648 ins->inst_imm = imm;
1651 if (!ppc_is_imm16 (ins->inst_imm)) {
1652 NEW_INS (cfg, temp, OP_ICONST);
1653 temp->inst_c0 = ins->inst_imm;
1654 temp->dreg = mono_regstate_next_int (cfg->rs);
1655 ins->sreg2 = temp->dreg;
1656 ins->opcode = map_to_reg_reg_op (ins->opcode);
1659 case OP_LOAD_MEMBASE:
1660 case OP_LOADI4_MEMBASE:
1661 case OP_LOADU4_MEMBASE:
1662 case OP_LOADI2_MEMBASE:
1663 case OP_LOADU2_MEMBASE:
1664 case OP_LOADI1_MEMBASE:
1665 case OP_LOADU1_MEMBASE:
1666 case OP_LOADR4_MEMBASE:
1667 case OP_LOADR8_MEMBASE:
1668 case OP_STORE_MEMBASE_REG:
1669 case OP_STOREI4_MEMBASE_REG:
1670 case OP_STOREI2_MEMBASE_REG:
1671 case OP_STOREI1_MEMBASE_REG:
1672 case OP_STORER4_MEMBASE_REG:
1673 case OP_STORER8_MEMBASE_REG:
1674 /* we can do two things: load the immed in a register
1675 * and use an indexed load, or see if the immed can be
1676 * represented as an ad_imm + a load with a smaller offset
1677 * that fits. We just do the first for now, optimize later.
1679 if (ppc_is_imm16 (ins->inst_offset))
1681 NEW_INS (cfg, temp, OP_ICONST);
1682 temp->inst_c0 = ins->inst_offset;
1683 temp->dreg = mono_regstate_next_int (cfg->rs);
1684 ins->sreg2 = temp->dreg;
1685 ins->opcode = map_to_reg_reg_op (ins->opcode);
1687 case OP_STORE_MEMBASE_IMM:
1688 case OP_STOREI1_MEMBASE_IMM:
1689 case OP_STOREI2_MEMBASE_IMM:
1690 case OP_STOREI4_MEMBASE_IMM:
1691 NEW_INS (cfg, temp, OP_ICONST);
1692 temp->inst_c0 = ins->inst_imm;
1693 temp->dreg = mono_regstate_next_int (cfg->rs);
1694 ins->sreg1 = temp->dreg;
1695 ins->opcode = map_to_reg_reg_op (ins->opcode);
1697 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1702 bb->last_ins = last_ins;
1703 bb->max_ireg = cfg->rs->next_vireg;
1708 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1712 mono_arch_lowering_pass (cfg, bb);
1713 mono_local_regalloc (cfg, bb);
1717 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1719 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1720 ppc_fctiwz (code, ppc_f0, sreg);
1721 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1722 ppc_lwz (code, dreg, -4, ppc_sp);
1725 ppc_andid (code, dreg, dreg, 0xff);
1727 ppc_andid (code, dreg, dreg, 0xffff);
1730 ppc_extsb (code, dreg, dreg);
1732 ppc_extsh (code, dreg, dreg);
1737 static unsigned char*
1738 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1741 int sreg = tree->sreg1;
1742 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1743 if (tree->flags & MONO_INST_INIT) {
1745 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1746 x86_push_reg (code, X86_EAX);
1749 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1750 x86_push_reg (code, X86_ECX);
1753 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1754 x86_push_reg (code, X86_EDI);
1758 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1759 if (sreg != X86_ECX)
1760 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1761 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1763 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1765 x86_prefix (code, X86_REP_PREFIX);
1768 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1769 x86_pop_reg (code, X86_EDI);
1770 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1771 x86_pop_reg (code, X86_ECX);
1772 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1773 x86_pop_reg (code, X86_EAX);
1786 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1789 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1790 PatchData *pdata = (PatchData*)user_data;
1791 guchar *code = data;
1792 guint32 *thunks = data;
1793 guint32 *endthunks = (guint32*)(code + bsize);
1797 int difflow, diffhigh;
1799 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1800 difflow = (char*)pdata->code - (char*)thunks;
1801 diffhigh = (char*)pdata->code - (char*)endthunks;
1802 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1805 templ = (guchar*)load;
1806 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1807 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1809 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1810 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1811 while (thunks < endthunks) {
1812 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1813 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1814 ppc_patch (pdata->code, (guchar*)thunks);
1815 mono_arch_flush_icache (pdata->code, 4);
1818 static int num_thunks = 0;
1820 if ((num_thunks % 20) == 0)
1821 g_print ("num_thunks lookup: %d\n", num_thunks);
1824 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1825 /* found a free slot instead: emit thunk */
1826 code = (guchar*)thunks;
1827 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1828 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1829 ppc_mtctr (code, ppc_r0);
1830 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1831 mono_arch_flush_icache ((guchar*)thunks, 16);
1833 ppc_patch (pdata->code, (guchar*)thunks);
1834 mono_arch_flush_icache (pdata->code, 4);
1837 static int num_thunks = 0;
1839 if ((num_thunks % 20) == 0)
1840 g_print ("num_thunks: %d\n", num_thunks);
1844 /* skip 16 bytes, the size of the thunk */
1848 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1854 handle_thunk (int absolute, guchar *code, guchar *target) {
1855 MonoDomain *domain = mono_domain_get ();
1859 pdata.target = target;
1860 pdata.absolute = absolute;
1863 mono_domain_lock (domain);
1864 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1867 /* this uses the first available slot */
1869 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1871 mono_domain_unlock (domain);
1873 if (pdata.found != 1)
1874 g_print ("thunk failed for %p from %p\n", target, code);
1875 g_assert (pdata.found == 1);
1879 ppc_patch (guchar *code, guchar *target)
1881 guint32 ins = *(guint32*)code;
1882 guint32 prim = ins >> 26;
1885 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1887 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1888 gint diff = target - code;
1890 if (diff <= 33554431){
1891 ins = (18 << 26) | (diff) | (ins & 1);
1892 *(guint32*)code = ins;
1896 /* diff between 0 and -33554432 */
1897 if (diff >= -33554432){
1898 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1899 *(guint32*)code = ins;
1904 if ((glong)target >= 0){
1905 if ((glong)target <= 33554431){
1906 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1907 *(guint32*)code = ins;
1911 if ((glong)target >= -33554432){
1912 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1913 *(guint32*)code = ins;
1918 handle_thunk (TRUE, code, target);
1921 g_assert_not_reached ();
1928 guint32 li = (guint32)target;
1929 ins = (ins & 0xffff0000) | (ins & 3);
1930 ovf = li & 0xffff0000;
1931 if (ovf != 0 && ovf != 0xffff0000)
1932 g_assert_not_reached ();
1935 // FIXME: assert the top bits of li are 0
1937 gint diff = target - code;
1938 ins = (ins & 0xffff0000) | (ins & 3);
1939 ovf = diff & 0xffff0000;
1940 if (ovf != 0 && ovf != 0xffff0000)
1941 g_assert_not_reached ();
1945 *(guint32*)code = ins;
1949 if (prim == 15 || ins == 0x4e800021) {
1951 /* the trampoline code will try to patch the blrl */
1952 if (ins == 0x4e800021) {
1955 /* this is the lis/ori/mtlr/blrl sequence */
1956 seq = (guint32*)code;
1957 g_assert ((seq [0] >> 26) == 15);
1958 g_assert ((seq [1] >> 26) == 24);
1959 g_assert ((seq [2] >> 26) == 31);
1960 g_assert (seq [3] == 0x4e800021);
1961 /* FIXME: make this thread safe */
1962 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
1963 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
1964 mono_arch_flush_icache (code - 8, 8);
1966 g_assert_not_reached ();
1968 // g_print ("patched with 0x%08x\n", ins);
1972 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1977 guint8 *code = cfg->native_code + cfg->code_len;
1978 MonoInst *last_ins = NULL;
1979 guint last_offset = 0;
1982 if (cfg->opt & MONO_OPT_PEEPHOLE)
1983 peephole_pass (cfg, bb);
1985 /* we don't align basic blocks of loops on ppc */
1987 if (cfg->verbose_level > 2)
1988 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1990 cpos = bb->max_offset;
1992 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1993 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1994 //g_assert (!mono_compile_aot);
1997 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1998 /* this is not thread save, but good enough */
1999 /* fixme: howto handle overflows? */
2000 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2005 offset = code - cfg->native_code;
2007 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2009 if (offset > (cfg->code_size - max_len - 16)) {
2010 cfg->code_size *= 2;
2011 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2012 code = cfg->native_code + offset;
2014 // if (ins->cil_code)
2015 // g_print ("cil code\n");
2016 mono_debug_record_line_number (cfg, ins, offset);
2018 switch (ins->opcode) {
2020 emit_tls_access (code, ins->dreg, ins->inst_offset);
2023 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2024 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2025 ppc_mr (code, ppc_r4, ppc_r0);
2028 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2029 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2030 ppc_mr (code, ppc_r4, ppc_r0);
2032 case OP_MEMORY_BARRIER:
2035 case OP_STOREI1_MEMBASE_REG:
2036 if (ppc_is_imm16 (ins->inst_offset)) {
2037 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2039 g_assert_not_reached ();
2042 case OP_STOREI2_MEMBASE_REG:
2043 if (ppc_is_imm16 (ins->inst_offset)) {
2044 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2046 g_assert_not_reached ();
2049 case OP_STORE_MEMBASE_REG:
2050 case OP_STOREI4_MEMBASE_REG:
2051 if (ppc_is_imm16 (ins->inst_offset)) {
2052 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2054 g_assert_not_reached ();
2057 case OP_STOREI1_MEMINDEX:
2058 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2060 case OP_STOREI2_MEMINDEX:
2061 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2063 case OP_STORE_MEMINDEX:
2064 case OP_STOREI4_MEMINDEX:
2065 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2070 g_assert_not_reached ();
2071 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2074 g_assert_not_reached ();
2076 case OP_LOAD_MEMBASE:
2077 case OP_LOADI4_MEMBASE:
2078 case OP_LOADU4_MEMBASE:
2079 if (ppc_is_imm16 (ins->inst_offset)) {
2080 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2082 g_assert_not_reached ();
2085 case OP_LOADI1_MEMBASE:
2086 case OP_LOADU1_MEMBASE:
2087 if (ppc_is_imm16 (ins->inst_offset)) {
2088 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2090 g_assert_not_reached ();
2092 if (ins->opcode == OP_LOADI1_MEMBASE)
2093 ppc_extsb (code, ins->dreg, ins->dreg);
2095 case OP_LOADU2_MEMBASE:
2096 if (ppc_is_imm16 (ins->inst_offset)) {
2097 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2099 g_assert_not_reached ();
2102 case OP_LOADI2_MEMBASE:
2103 if (ppc_is_imm16 (ins->inst_offset)) {
2104 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2106 g_assert_not_reached ();
2109 case OP_LOAD_MEMINDEX:
2110 case OP_LOADI4_MEMINDEX:
2111 case OP_LOADU4_MEMINDEX:
2112 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2114 case OP_LOADU2_MEMINDEX:
2115 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2117 case OP_LOADI2_MEMINDEX:
2118 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2120 case OP_LOADU1_MEMINDEX:
2121 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2123 case OP_LOADI1_MEMINDEX:
2124 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2125 ppc_extsb (code, ins->dreg, ins->dreg);
2128 ppc_extsb (code, ins->dreg, ins->sreg1);
2131 ppc_extsh (code, ins->dreg, ins->sreg1);
2134 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2137 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2140 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2141 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2143 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2145 case OP_COMPARE_IMM:
2146 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2147 if (ppc_is_uimm16 (ins->inst_imm)) {
2148 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2150 g_assert_not_reached ();
2153 if (ppc_is_imm16 (ins->inst_imm)) {
2154 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2156 g_assert_not_reached ();
2164 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2167 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2170 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2173 if (ppc_is_imm16 (ins->inst_imm)) {
2174 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2176 g_assert_not_reached ();
2180 if (ppc_is_imm16 (ins->inst_imm)) {
2181 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2183 g_assert_not_reached ();
2187 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2189 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2190 ppc_mfspr (code, ppc_r0, ppc_xer);
2191 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2192 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2194 case CEE_ADD_OVF_UN:
2195 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2197 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2198 ppc_mfspr (code, ppc_r0, ppc_xer);
2199 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2200 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2203 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2205 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2206 ppc_mfspr (code, ppc_r0, ppc_xer);
2207 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2208 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2210 case CEE_SUB_OVF_UN:
2211 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2213 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2214 ppc_mfspr (code, ppc_r0, ppc_xer);
2215 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2216 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2218 case OP_ADD_OVF_CARRY:
2219 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2221 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2222 ppc_mfspr (code, ppc_r0, ppc_xer);
2223 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2224 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2226 case OP_ADD_OVF_UN_CARRY:
2227 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2229 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2230 ppc_mfspr (code, ppc_r0, ppc_xer);
2231 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2232 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2234 case OP_SUB_OVF_CARRY:
2235 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2237 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2238 ppc_mfspr (code, ppc_r0, ppc_xer);
2239 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2240 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2242 case OP_SUB_OVF_UN_CARRY:
2243 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2245 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2246 ppc_mfspr (code, ppc_r0, ppc_xer);
2247 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2248 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2251 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2254 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2257 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2260 // we add the negated value
2261 if (ppc_is_imm16 (-ins->inst_imm))
2262 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2264 g_assert_not_reached ();
2268 g_assert (ppc_is_imm16 (ins->inst_imm));
2269 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2272 ppc_subfze (code, ins->dreg, ins->sreg1);
2275 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2276 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2279 if (!(ins->inst_imm & 0xffff0000)) {
2280 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2281 } else if (!(ins->inst_imm & 0xffff)) {
2282 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2284 g_assert_not_reached ();
2288 guint32 *divisor_is_m1;
2289 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2291 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2292 divisor_is_m1 = code;
2293 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2294 ppc_lis (code, ppc_r11, 0x8000);
2295 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2296 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2297 ppc_patch (divisor_is_m1, code);
2298 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2300 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2301 ppc_mfspr (code, ppc_r0, ppc_xer);
2302 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2303 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2307 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2308 ppc_mfspr (code, ppc_r0, ppc_xer);
2309 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2310 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2313 g_assert_not_reached ();
2315 ppc_load (code, ppc_r11, ins->inst_imm);
2316 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2317 ppc_mfspr (code, ppc_r0, ppc_xer);
2318 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2319 /* FIXME: use OverflowException for 0x80000000/-1 */
2320 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2324 guint32 *divisor_is_m1;
2325 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2326 divisor_is_m1 = code;
2327 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2328 ppc_lis (code, ppc_r11, 0x8000);
2329 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2330 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2331 ppc_patch (divisor_is_m1, code);
2332 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2333 ppc_mfspr (code, ppc_r0, ppc_xer);
2334 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2335 /* FIXME: use OverflowException for 0x80000000/-1 */
2336 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2337 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2338 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2342 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2343 ppc_mfspr (code, ppc_r0, ppc_xer);
2344 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2345 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2346 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2347 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2350 g_assert_not_reached ();
2352 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2355 if (!(ins->inst_imm & 0xffff0000)) {
2356 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2357 } else if (!(ins->inst_imm & 0xffff)) {
2358 ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2360 g_assert_not_reached ();
2364 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2367 if (!(ins->inst_imm & 0xffff0000)) {
2368 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2369 } else if (!(ins->inst_imm & 0xffff)) {
2370 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2372 g_assert_not_reached ();
2376 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2379 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2382 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2385 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2388 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2391 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2394 ppc_not (code, ins->dreg, ins->sreg1);
2397 ppc_neg (code, ins->dreg, ins->sreg1);
2400 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2403 if (ppc_is_imm16 (ins->inst_imm)) {
2404 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2406 g_assert_not_reached ();
2410 /* we annot use mcrxr, since it's not implemented on some processors
2411 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2413 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2414 ppc_mfspr (code, ppc_r0, ppc_xer);
2415 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2416 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2418 case CEE_MUL_OVF_UN:
2419 /* we first multiply to get the high word and compare to 0
2420 * to set the flags, then the result is discarded and then
2421 * we multiply to get the lower * bits result
2423 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2424 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2425 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2426 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2430 ppc_load (code, ins->dreg, ins->inst_c0);
2433 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2434 ppc_lis (code, ins->dreg, 0);
2435 ppc_ori (code, ins->dreg, ins->dreg, 0);
2441 ppc_mr (code, ins->dreg, ins->sreg1);
2444 int saved = ins->sreg1;
2445 if (ins->sreg1 == ppc_r3) {
2446 ppc_mr (code, ppc_r0, ins->sreg1);
2449 if (ins->sreg2 != ppc_r3)
2450 ppc_mr (code, ppc_r3, ins->sreg2);
2451 if (saved != ppc_r4)
2452 ppc_mr (code, ppc_r4, saved);
2457 ppc_fmr (code, ins->dreg, ins->sreg1);
2459 case OP_FCONV_TO_R4:
2460 ppc_frsp (code, ins->dreg, ins->sreg1);
2466 * Keep in sync with mono_arch_emit_epilog
2468 g_assert (!cfg->method->save_lmf);
2469 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2470 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2471 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2473 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2474 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2476 ppc_mtlr (code, ppc_r0);
2478 if (ppc_is_imm16 (cfg->stack_usage)) {
2479 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2481 ppc_load (code, ppc_r11, cfg->stack_usage);
2482 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2484 if (!cfg->method->save_lmf) {
2485 /*for (i = 31; i >= 14; --i) {
2486 if (cfg->used_float_regs & (1 << i)) {
2487 pos += sizeof (double);
2488 ppc_lfd (code, i, -pos, cfg->frame_reg);
2491 for (i = 31; i >= 13; --i) {
2492 if (cfg->used_int_regs & (1 << i)) {
2493 pos += sizeof (gulong);
2494 ppc_lwz (code, i, -pos, cfg->frame_reg);
2498 /* FIXME restore from MonoLMF: though this can't happen yet */
2500 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2505 /* ensure ins->sreg1 is not NULL */
2506 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2509 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2510 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2512 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2513 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2515 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2523 call = (MonoCallInst*)ins;
2524 if (ins->flags & MONO_INST_HAS_METHOD)
2525 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2527 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2528 if (cfg->method->dynamic) {
2529 ppc_lis (code, ppc_r0, 0);
2530 ppc_ori (code, ppc_r0, ppc_r0, 0);
2531 ppc_mtlr (code, ppc_r0);
2540 case OP_VOIDCALL_REG:
2542 ppc_mtlr (code, ins->sreg1);
2545 case OP_FCALL_MEMBASE:
2546 case OP_LCALL_MEMBASE:
2547 case OP_VCALL_MEMBASE:
2548 case OP_VOIDCALL_MEMBASE:
2549 case OP_CALL_MEMBASE:
2550 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2551 ppc_mtlr (code, ppc_r0);
2555 g_assert_not_reached ();
2558 guint32 * zero_loop_jump, * zero_loop_start;
2559 /* keep alignment */
2560 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2561 int area_offset = alloca_waste;
2563 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2564 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2565 /* use ctr to store the number of words to 0 if needed */
2566 if (ins->flags & MONO_INST_INIT) {
2567 /* we zero 4 bytes at a time */
2568 ppc_addi (code, ppc_r0, ins->sreg1, 3);
2569 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2570 ppc_mtctr (code, ppc_r0);
2572 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2573 ppc_neg (code, ppc_r11, ppc_r11);
2574 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2576 if (ins->flags & MONO_INST_INIT) {
2577 /* adjust the dest reg by -4 so we can use stwu */
2578 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
2579 ppc_li (code, ppc_r11, 0);
2580 zero_loop_start = code;
2581 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2582 zero_loop_jump = code;
2583 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2584 ppc_patch (zero_loop_jump, zero_loop_start);
2586 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2594 ppc_mr (code, ppc_r3, ins->sreg1);
2595 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2596 (gpointer)"mono_arch_throw_exception");
2597 if (cfg->method->dynamic) {
2598 ppc_lis (code, ppc_r0, 0);
2599 ppc_ori (code, ppc_r0, ppc_r0, 0);
2600 ppc_mtlr (code, ppc_r0);
2609 ppc_mr (code, ppc_r3, ins->sreg1);
2610 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2611 (gpointer)"mono_arch_rethrow_exception");
2612 if (cfg->method->dynamic) {
2613 ppc_lis (code, ppc_r0, 0);
2614 ppc_ori (code, ppc_r0, ppc_r0, 0);
2615 ppc_mtlr (code, ppc_r0);
2622 case OP_START_HANDLER:
2623 ppc_mflr (code, ppc_r0);
2624 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2625 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2627 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2628 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2632 if (ins->sreg1 != ppc_r3)
2633 ppc_mr (code, ppc_r3, ins->sreg1);
2634 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2635 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2637 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2638 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2640 ppc_mtlr (code, ppc_r0);
2643 case CEE_ENDFINALLY:
2644 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2645 ppc_mtlr (code, ppc_r0);
2648 case OP_CALL_HANDLER:
2649 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2653 ins->inst_c0 = code - cfg->native_code;
2656 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2657 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2659 if (ins->flags & MONO_INST_BRLABEL) {
2660 /*if (ins->inst_i0->inst_c0) {
2662 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2664 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2668 /*if (ins->inst_target_bb->native_offset) {
2670 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2672 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2678 ppc_mtctr (code, ins->sreg1);
2679 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2682 ppc_li (code, ins->dreg, 0);
2683 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2684 ppc_li (code, ins->dreg, 1);
2688 ppc_li (code, ins->dreg, 1);
2689 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2690 ppc_li (code, ins->dreg, 0);
2694 ppc_li (code, ins->dreg, 1);
2695 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2696 ppc_li (code, ins->dreg, 0);
2698 case OP_COND_EXC_EQ:
2699 case OP_COND_EXC_NE_UN:
2700 case OP_COND_EXC_LT:
2701 case OP_COND_EXC_LT_UN:
2702 case OP_COND_EXC_GT:
2703 case OP_COND_EXC_GT_UN:
2704 case OP_COND_EXC_GE:
2705 case OP_COND_EXC_GE_UN:
2706 case OP_COND_EXC_LE:
2707 case OP_COND_EXC_LE_UN:
2708 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2711 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2713 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2714 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2715 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2717 case OP_COND_EXC_OV:
2718 /*ppc_mcrxr (code, 0);
2719 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2721 case OP_COND_EXC_NC:
2722 case OP_COND_EXC_NO:
2723 g_assert_not_reached ();
2735 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2738 /* floating point opcodes */
2740 ppc_load (code, ppc_r11, ins->inst_p0);
2741 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2744 ppc_load (code, ppc_r11, ins->inst_p0);
2745 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2747 case OP_STORER8_MEMBASE_REG:
2748 if (ppc_is_imm16 (ins->inst_offset)) {
2749 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2751 g_assert_not_reached ();
2754 case OP_LOADR8_MEMBASE:
2755 if (ppc_is_imm16 (ins->inst_offset)) {
2756 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2758 g_assert_not_reached ();
2761 case OP_STORER4_MEMBASE_REG:
2762 ppc_frsp (code, ins->sreg1, ins->sreg1);
2763 if (ppc_is_imm16 (ins->inst_offset)) {
2764 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2766 g_assert_not_reached ();
2769 case OP_LOADR4_MEMBASE:
2770 if (ppc_is_imm16 (ins->inst_offset)) {
2771 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2773 g_assert_not_reached ();
2776 case OP_LOADR4_MEMINDEX:
2777 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2779 case OP_LOADR8_MEMINDEX:
2780 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2782 case OP_STORER4_MEMINDEX:
2783 ppc_frsp (code, ins->sreg1, ins->sreg1);
2784 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2786 case OP_STORER8_MEMINDEX:
2787 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2789 case CEE_CONV_R_UN: {
2790 static const guint64 adjust_val = 0x4330000000000000ULL;
2791 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2792 ppc_stw (code, ppc_r0, -8, ppc_sp);
2793 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2794 ppc_load (code, ppc_r11, &adjust_val);
2795 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2796 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2797 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2800 case CEE_CONV_R4: /* FIXME: change precision */
2802 static const guint64 adjust_val = 0x4330000080000000ULL;
2803 // addis is special for ppc_r0
2804 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2805 ppc_stw (code, ppc_r0, -8, ppc_sp);
2806 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2807 ppc_stw (code, ppc_r11, -4, ppc_sp);
2808 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2809 ppc_load (code, ppc_r11, &adjust_val);
2810 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2811 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2814 case OP_FCONV_TO_I1:
2815 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2817 case OP_FCONV_TO_U1:
2818 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2820 case OP_FCONV_TO_I2:
2821 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2823 case OP_FCONV_TO_U2:
2824 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2826 case OP_FCONV_TO_I4:
2828 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2830 case OP_FCONV_TO_U4:
2832 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2834 case OP_FCONV_TO_I8:
2835 case OP_FCONV_TO_U8:
2836 g_assert_not_reached ();
2837 /* Implemented as helper calls */
2839 case OP_LCONV_TO_R_UN:
2840 g_assert_not_reached ();
2841 /* Implemented as helper calls */
2843 case OP_LCONV_TO_OVF_I: {
2844 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2845 // Check if its negative
2846 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2847 negative_branch = code;
2848 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2849 // Its positive msword == 0
2850 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2851 msword_positive_branch = code;
2852 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2854 ovf_ex_target = code;
2855 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2857 ppc_patch (negative_branch, code);
2858 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2859 msword_negative_branch = code;
2860 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2861 ppc_patch (msword_negative_branch, ovf_ex_target);
2863 ppc_patch (msword_positive_branch, code);
2864 if (ins->dreg != ins->sreg1)
2865 ppc_mr (code, ins->dreg, ins->sreg1);
2869 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2872 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2875 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2878 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2881 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2884 ppc_fneg (code, ins->dreg, ins->sreg1);
2888 g_assert_not_reached ();
2891 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2894 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2895 ppc_li (code, ins->dreg, 0);
2896 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2897 ppc_li (code, ins->dreg, 1);
2900 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2901 ppc_li (code, ins->dreg, 1);
2902 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2903 ppc_li (code, ins->dreg, 0);
2906 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2907 ppc_li (code, ins->dreg, 1);
2908 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2909 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2910 ppc_li (code, ins->dreg, 0);
2913 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2914 ppc_li (code, ins->dreg, 1);
2915 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2916 ppc_li (code, ins->dreg, 0);
2919 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2920 ppc_li (code, ins->dreg, 1);
2921 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2922 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2923 ppc_li (code, ins->dreg, 0);
2926 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2929 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2932 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2935 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2936 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2939 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2942 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2943 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2946 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2949 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2952 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2955 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2957 case CEE_CKFINITE: {
2958 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2959 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2960 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2961 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2962 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2963 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2967 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2968 g_assert_not_reached ();
2971 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2972 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2973 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2974 g_assert_not_reached ();
2980 last_offset = offset;
2985 cfg->code_len = code - cfg->native_code;
2989 mono_arch_register_lowlevel_calls (void)
2993 #define patch_lis_ori(ip,val) do {\
2994 guint16 *__lis_ori = (guint16*)(ip); \
2995 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
2996 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3000 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3002 MonoJumpInfo *patch_info;
3004 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3005 unsigned char *ip = patch_info->ip.i + code;
3006 const unsigned char *target;
3008 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3010 switch (patch_info->type) {
3011 case MONO_PATCH_INFO_IP:
3012 patch_lis_ori (ip, ip);
3014 case MONO_PATCH_INFO_METHOD_REL:
3015 g_assert_not_reached ();
3016 *((gpointer *)(ip)) = code + patch_info->data.offset;
3018 case MONO_PATCH_INFO_SWITCH: {
3019 gpointer *table = (gpointer *)patch_info->data.table->table;
3022 patch_lis_ori (ip, table);
3024 for (i = 0; i < patch_info->data.table->table_size; i++) {
3025 table [i] = (int)patch_info->data.table->table [i] + code;
3027 /* we put into the table the absolute address, no need for ppc_patch in this case */
3030 case MONO_PATCH_INFO_METHODCONST:
3031 case MONO_PATCH_INFO_CLASS:
3032 case MONO_PATCH_INFO_IMAGE:
3033 case MONO_PATCH_INFO_FIELD:
3034 case MONO_PATCH_INFO_VTABLE:
3035 case MONO_PATCH_INFO_IID:
3036 case MONO_PATCH_INFO_SFLDA:
3037 case MONO_PATCH_INFO_LDSTR:
3038 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3039 case MONO_PATCH_INFO_LDTOKEN:
3040 /* from OP_AOTCONST : lis + ori */
3041 patch_lis_ori (ip, target);
3043 case MONO_PATCH_INFO_R4:
3044 case MONO_PATCH_INFO_R8:
3045 g_assert_not_reached ();
3046 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3048 case MONO_PATCH_INFO_EXC_NAME:
3049 g_assert_not_reached ();
3050 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3052 case MONO_PATCH_INFO_NONE:
3053 case MONO_PATCH_INFO_BB_OVF:
3054 case MONO_PATCH_INFO_EXC_OVF:
3055 /* everything is dealt with at epilog output time */
3060 ppc_patch (ip, target);
3065 * Stack frame layout:
3067 * ------------------- sp
3068 * MonoLMF structure or saved registers
3069 * -------------------
3071 * -------------------
3073 * -------------------
3074 * optional 8 bytes for tracing
3075 * -------------------
3076 * param area size is cfg->param_area
3077 * -------------------
3078 * linkage area size is PPC_STACK_PARAM_OFFSET
3079 * ------------------- sp
3083 mono_arch_emit_prolog (MonoCompile *cfg)
3085 MonoMethod *method = cfg->method;
3087 MonoMethodSignature *sig;
3089 int alloc_size, pos, max_offset, i;
3095 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3098 sig = mono_method_signature (method);
3099 cfg->code_size = 256 + sig->param_count * 20;
3100 code = cfg->native_code = g_malloc (cfg->code_size);
3102 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3103 ppc_mflr (code, ppc_r0);
3104 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3107 alloc_size = cfg->stack_offset;
3110 if (!method->save_lmf) {
3111 /*for (i = 31; i >= 14; --i) {
3112 if (cfg->used_float_regs & (1 << i)) {
3113 pos += sizeof (gdouble);
3114 ppc_stfd (code, i, -pos, ppc_sp);
3117 for (i = 31; i >= 13; --i) {
3118 if (cfg->used_int_regs & (1 << i)) {
3119 pos += sizeof (gulong);
3120 ppc_stw (code, i, -pos, ppc_sp);
3125 pos += sizeof (MonoLMF);
3127 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3128 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3129 for (i = 14; i < 32; i++) {
3130 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3134 // align to PPC_STACK_ALIGNMENT bytes
3135 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3136 alloc_size += PPC_STACK_ALIGNMENT - 1;
3137 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3140 cfg->stack_usage = alloc_size;
3141 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3143 if (ppc_is_imm16 (-alloc_size)) {
3144 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3146 ppc_load (code, ppc_r11, -alloc_size);
3147 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3150 if (cfg->frame_reg != ppc_sp)
3151 ppc_mr (code, cfg->frame_reg, ppc_sp);
3153 /* compute max_offset in order to use short forward jumps
3154 * we always do it on ppc because the immediate displacement
3155 * for jumps is too small
3158 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3159 MonoInst *ins = bb->code;
3160 bb->max_offset = max_offset;
3162 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3166 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3171 /* load arguments allocated to register from the stack */
3174 cinfo = calculate_sizes (sig, sig->pinvoke);
3176 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3177 ArgInfo *ainfo = &cinfo->ret;
3179 if (ppc_is_imm16 (inst->inst_offset)) {
3180 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3182 ppc_load (code, ppc_r11, inst->inst_offset);
3183 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3186 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3187 ArgInfo *ainfo = cinfo->args + i;
3188 inst = cfg->varinfo [pos];
3190 if (cfg->verbose_level > 2)
3191 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3192 if (inst->opcode == OP_REGVAR) {
3193 if (ainfo->regtype == RegTypeGeneral)
3194 ppc_mr (code, inst->dreg, ainfo->reg);
3195 else if (ainfo->regtype == RegTypeFP)
3196 ppc_fmr (code, inst->dreg, ainfo->reg);
3197 else if (ainfo->regtype == RegTypeBase) {
3198 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3199 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3201 g_assert_not_reached ();
3203 if (cfg->verbose_level > 2)
3204 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3206 /* the argument should be put on the stack: FIXME handle size != word */
3207 if (ainfo->regtype == RegTypeGeneral) {
3208 switch (ainfo->size) {
3210 if (ppc_is_imm16 (inst->inst_offset)) {
3211 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3213 ppc_load (code, ppc_r11, inst->inst_offset);
3214 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3218 if (ppc_is_imm16 (inst->inst_offset)) {
3219 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3221 ppc_load (code, ppc_r11, inst->inst_offset);
3222 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3226 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3227 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3228 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3230 ppc_load (code, ppc_r11, inst->inst_offset);
3231 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3232 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3233 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3237 if (ppc_is_imm16 (inst->inst_offset)) {
3238 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3240 ppc_load (code, ppc_r11, inst->inst_offset);
3241 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3245 } else if (ainfo->regtype == RegTypeBase) {
3246 /* load the previous stack pointer in r11 */
3247 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3248 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3249 switch (ainfo->size) {
3251 if (ppc_is_imm16 (inst->inst_offset)) {
3252 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3254 ppc_load (code, ppc_r11, inst->inst_offset);
3255 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3259 if (ppc_is_imm16 (inst->inst_offset)) {
3260 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3262 ppc_load (code, ppc_r11, inst->inst_offset);
3263 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3267 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3268 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3269 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3270 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3273 g_assert_not_reached ();
3277 if (ppc_is_imm16 (inst->inst_offset)) {
3278 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3280 ppc_load (code, ppc_r11, inst->inst_offset);
3281 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3285 } else if (ainfo->regtype == RegTypeFP) {
3286 g_assert (ppc_is_imm16 (inst->inst_offset));
3287 if (ainfo->size == 8)
3288 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3289 else if (ainfo->size == 4)
3290 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3292 g_assert_not_reached ();
3293 } else if (ainfo->regtype == RegTypeStructByVal) {
3294 int doffset = inst->inst_offset;
3298 g_assert (ppc_is_imm16 (inst->inst_offset));
3299 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3300 if (mono_class_from_mono_type (inst->inst_vtype))
3301 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3302 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3304 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3305 register. Should this case include linux/ppc?
3309 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3311 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3314 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3315 soffset += sizeof (gpointer);
3316 doffset += sizeof (gpointer);
3318 if (ainfo->vtsize) {
3319 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3320 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3321 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3322 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3324 } else if (ainfo->regtype == RegTypeStructByAddr) {
3325 g_assert (ppc_is_imm16 (inst->inst_offset));
3326 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3327 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3329 g_assert_not_reached ();
3334 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3335 ppc_load (code, ppc_r3, cfg->domain);
3336 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3340 if (method->save_lmf) {
3341 if (lmf_pthread_key != -1) {
3342 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3343 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3344 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3346 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3347 (gpointer)"mono_get_lmf_addr");
3348 if (cfg->method->dynamic) {
3349 ppc_lis (code, ppc_r0, 0);
3350 ppc_ori (code, ppc_r0, ppc_r0, 0);
3351 ppc_mtlr (code, ppc_r0);
3357 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3358 /* lmf_offset is the offset from the previous stack pointer,
3359 * alloc_size is the total stack space allocated, so the offset
3360 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3361 * The pointer to the struct is put in ppc_r11 (new_lmf).
3362 * The callee-saved registers are already in the MonoLMF structure
3364 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3365 /* ppc_r3 is the result from mono_get_lmf_addr () */
3366 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3367 /* new_lmf->previous_lmf = *lmf_addr */
3368 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3369 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3370 /* *(lmf_addr) = r11 */
3371 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3372 /* save method info */
3373 ppc_load (code, ppc_r0, method);
3374 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3375 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3376 /* save the current IP */
3377 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3378 ppc_load (code, ppc_r0, 0x01010101);
3379 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3383 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3385 cfg->code_len = code - cfg->native_code;
3386 g_assert (cfg->code_len < cfg->code_size);
3393 mono_arch_emit_epilog (MonoCompile *cfg)
3395 MonoJumpInfo *patch_info;
3396 MonoMethod *method = cfg->method;
3398 int max_epilog_size = 16 + 20*4;
3401 if (cfg->method->save_lmf)
3402 max_epilog_size += 128;
3404 if (mono_jit_trace_calls != NULL)
3405 max_epilog_size += 50;
3407 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3408 max_epilog_size += 50;
3410 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3411 cfg->code_size *= 2;
3412 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3413 mono_jit_stats.code_reallocs++;
3417 * Keep in sync with CEE_JMP
3419 code = cfg->native_code + cfg->code_len;
3421 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3422 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3426 if (method->save_lmf) {
3428 pos += sizeof (MonoLMF);
3430 /* save the frame reg in r8 */
3431 ppc_mr (code, ppc_r8, cfg->frame_reg);
3432 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3433 /* r5 = previous_lmf */
3434 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3436 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3437 /* *(lmf_addr) = previous_lmf */
3438 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3439 /* FIXME: speedup: there is no actual need to restore the registers if
3440 * we didn't actually change them (idea from Zoltan).
3443 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3445 /*for (i = 14; i < 32; i++) {
3446 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3448 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3449 /* use the saved copy of the frame reg in r8 */
3450 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3451 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3452 ppc_mtlr (code, ppc_r0);
3454 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3456 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3457 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3458 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3460 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3461 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3463 ppc_mtlr (code, ppc_r0);
3465 if (ppc_is_imm16 (cfg->stack_usage)) {
3466 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3468 ppc_load (code, ppc_r11, cfg->stack_usage);
3469 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3472 /*for (i = 31; i >= 14; --i) {
3473 if (cfg->used_float_regs & (1 << i)) {
3474 pos += sizeof (double);
3475 ppc_lfd (code, i, -pos, ppc_sp);
3478 for (i = 31; i >= 13; --i) {
3479 if (cfg->used_int_regs & (1 << i)) {
3480 pos += sizeof (gulong);
3481 ppc_lwz (code, i, -pos, ppc_sp);
3487 cfg->code_len = code - cfg->native_code;
3489 g_assert (cfg->code_len < cfg->code_size);
3493 /* remove once throw_exception_by_name is eliminated */
3495 exception_id_by_name (const char *name)
3497 if (strcmp (name, "IndexOutOfRangeException") == 0)
3498 return MONO_EXC_INDEX_OUT_OF_RANGE;
3499 if (strcmp (name, "OverflowException") == 0)
3500 return MONO_EXC_OVERFLOW;
3501 if (strcmp (name, "ArithmeticException") == 0)
3502 return MONO_EXC_ARITHMETIC;
3503 if (strcmp (name, "DivideByZeroException") == 0)
3504 return MONO_EXC_DIVIDE_BY_ZERO;
3505 if (strcmp (name, "InvalidCastException") == 0)
3506 return MONO_EXC_INVALID_CAST;
3507 if (strcmp (name, "NullReferenceException") == 0)
3508 return MONO_EXC_NULL_REF;
3509 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3510 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3511 g_error ("Unknown intrinsic exception %s\n", name);
3516 mono_arch_emit_exceptions (MonoCompile *cfg)
3518 MonoJumpInfo *patch_info;
3521 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3522 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3525 int max_epilog_size = 50;
3527 /* count the number of exception infos */
3530 * make sure we have enough space for exceptions
3531 * 24 is the simulated call to throw_exception_by_name
3533 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3534 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3535 i = exception_id_by_name (patch_info->data.target);
3536 if (!exc_throw_found [i]) {
3537 max_epilog_size += 12;
3538 exc_throw_found [i] = TRUE;
3540 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3541 max_epilog_size += 12;
3542 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3543 MonoOvfJump *ovfj = patch_info->data.target;
3544 i = exception_id_by_name (ovfj->data.exception);
3545 if (!exc_throw_found [i]) {
3546 max_epilog_size += 12;
3547 exc_throw_found [i] = TRUE;
3549 max_epilog_size += 8;
3553 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3554 cfg->code_size *= 2;
3555 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3556 mono_jit_stats.code_reallocs++;
3559 code = cfg->native_code + cfg->code_len;
3561 /* add code to raise exceptions */
3562 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3563 switch (patch_info->type) {
3564 case MONO_PATCH_INFO_BB_OVF: {
3565 MonoOvfJump *ovfj = patch_info->data.target;
3566 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3567 /* patch the initial jump */
3568 ppc_patch (ip, code);
3569 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3571 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3572 /* jump back to the true target */
3574 ip = ovfj->data.bb->native_offset + cfg->native_code;
3575 ppc_patch (code - 4, ip);
3578 case MONO_PATCH_INFO_EXC_OVF: {
3579 MonoOvfJump *ovfj = patch_info->data.target;
3580 MonoJumpInfo *newji;
3581 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3582 unsigned char *bcl = code;
3583 /* patch the initial jump: we arrived here with a call */
3584 ppc_patch (ip, code);
3585 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3587 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3588 /* patch the conditional jump to the right handler */
3589 /* make it processed next */
3590 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3591 newji->type = MONO_PATCH_INFO_EXC;
3592 newji->ip.i = bcl - cfg->native_code;
3593 newji->data.target = ovfj->data.exception;
3594 newji->next = patch_info->next;
3595 patch_info->next = newji;
3598 case MONO_PATCH_INFO_EXC: {
3599 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3600 i = exception_id_by_name (patch_info->data.target);
3601 if (exc_throw_pos [i]) {
3602 ppc_patch (ip, exc_throw_pos [i]);
3603 patch_info->type = MONO_PATCH_INFO_NONE;
3606 exc_throw_pos [i] = code;
3608 ppc_patch (ip, code);
3609 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3610 ppc_load (code, ppc_r3, patch_info->data.target);
3611 /* we got here from a conditional call, so the calling ip is set in lr already */
3612 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3613 patch_info->data.name = "mono_arch_throw_exception_by_name";
3614 patch_info->ip.i = code - cfg->native_code;
3624 cfg->code_len = code - cfg->native_code;
3626 g_assert (cfg->code_len < cfg->code_size);
3631 try_offset_access (void *value, guint32 idx)
3633 register void* me __asm__ ("r2");
3634 void ***p = (void***)((char*)me + 284);
3635 int idx1 = idx / 32;
3636 int idx2 = idx % 32;
3639 if (value != p[idx1][idx2])
3645 setup_tls_access (void)
3648 guint32 *ins, *code;
3649 guint32 cmplwi_1023, li_0x48, blr_ins;
3650 if (tls_mode == TLS_MODE_FAILED)
3653 if (g_getenv ("MONO_NO_TLS")) {
3654 tls_mode = TLS_MODE_FAILED;
3658 if (tls_mode == TLS_MODE_DETECT) {
3659 ins = (guint32*)pthread_getspecific;
3660 /* uncond branch to the real method */
3661 if ((*ins >> 26) == 18) {
3663 val = (*ins & ~3) << 6;
3667 ins = (guint32*)val;
3669 ins = (guint32*) ((char*)ins + val);
3672 code = &cmplwi_1023;
3673 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3675 ppc_li (code, ppc_r4, 0x48);
3678 if (*ins == cmplwi_1023) {
3679 int found_lwz_284 = 0;
3680 for (ptk = 0; ptk < 20; ++ptk) {
3682 if (!*ins || *ins == blr_ins)
3684 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3689 if (!found_lwz_284) {
3690 tls_mode = TLS_MODE_FAILED;
3693 tls_mode = TLS_MODE_LTHREADS;
3694 } else if (*ins == li_0x48) {
3696 /* uncond branch to the real method */
3697 if ((*ins >> 26) == 18) {
3699 val = (*ins & ~3) << 6;
3703 ins = (guint32*)val;
3705 ins = (guint32*) ((char*)ins + val);
3708 ppc_li (code, ppc_r0, 0x7FF2);
3709 if (ins [1] == val) {
3710 /* Darwin on G4, implement */
3711 tls_mode = TLS_MODE_FAILED;
3715 ppc_mfspr (code, ppc_r3, 104);
3716 if (ins [1] != val) {
3717 tls_mode = TLS_MODE_FAILED;
3720 tls_mode = TLS_MODE_DARWIN_G5;
3723 tls_mode = TLS_MODE_FAILED;
3727 tls_mode = TLS_MODE_FAILED;
3731 if (monodomain_key == -1) {
3732 ptk = mono_domain_get_tls_key ();
3734 ptk = mono_pthread_key_for_tls (ptk);
3736 monodomain_key = ptk;
3740 if (lmf_pthread_key == -1) {
3741 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3743 /*g_print ("MonoLMF at: %d\n", ptk);*/
3744 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3745 init_tls_failed = 1;
3748 lmf_pthread_key = ptk;
3751 if (monothread_key == -1) {
3752 ptk = mono_thread_get_tls_key ();
3754 ptk = mono_pthread_key_for_tls (ptk);
3756 monothread_key = ptk;
3757 /*g_print ("thread inited: %d\n", ptk);*/
3760 /*g_print ("thread not inited yet %d\n", ptk);*/
3766 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3768 setup_tls_access ();
3772 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3777 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3779 int this_dreg = ppc_r3;
3784 /* add the this argument */
3785 if (this_reg != -1) {
3787 MONO_INST_NEW (cfg, this, OP_SETREG);
3788 this->type = this_type;
3789 this->sreg1 = this_reg;
3790 this->dreg = mono_regstate_next_int (cfg->rs);
3791 mono_bblock_add_inst (cfg->cbb, this);
3792 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3797 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3798 vtarg->type = STACK_MP;
3799 vtarg->sreg1 = vt_reg;
3800 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3801 mono_bblock_add_inst (cfg->cbb, vtarg);
3802 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3807 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3809 MonoInst *ins = NULL;
3811 if (cmethod->klass == mono_defaults.thread_class &&
3812 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3813 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3815 /*if (cmethod->klass == mono_defaults.math_class) {
3816 if (strcmp (cmethod->name, "Sqrt") == 0) {
3817 MONO_INST_NEW (cfg, ins, OP_SQRT);
3818 ins->inst_i0 = args [0];
3825 mono_arch_print_tree (MonoInst *tree, int arity)
3830 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3834 setup_tls_access ();
3835 if (monodomain_key == -1)
3838 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3839 ins->inst_offset = monodomain_key;
3844 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3848 setup_tls_access ();
3849 if (monothread_key == -1)
3852 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3853 ins->inst_offset = monothread_key;