2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 #include <sys/sysctl.h>
24 #define FORCE_INDIR_CALL 1
35 int mono_exc_esp_offset = 0;
36 static int tls_mode = TLS_MODE_DETECT;
37 static int lmf_pthread_key = -1;
38 static int monothread_key = -1;
39 static int monodomain_key = -1;
42 offsets_from_pthread_key (guint32 key, int *offset2)
46 *offset2 = idx2 * sizeof (gpointer);
47 return 284 + idx1 * sizeof (gpointer);
50 #define emit_linuxthreads_tls(code,dreg,key) do {\
52 off1 = offsets_from_pthread_key ((key), &off2); \
53 ppc_lwz ((code), (dreg), off1, ppc_r2); \
54 ppc_lwz ((code), (dreg), off2, (dreg)); \
57 #define emit_darwing5_tls(code,dreg,key) do {\
58 int off1 = 0x48 + key * sizeof (gpointer); \
59 ppc_mfspr ((code), (dreg), 104); \
60 ppc_lwz ((code), (dreg), off1, (dreg)); \
63 /* FIXME: ensure the sc call preserves all but r3 */
64 #define emit_darwing4_tls(code,dreg,key) do {\
65 int off1 = 0x48 + key * sizeof (gpointer); \
66 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
67 ppc_li ((code), ppc_r0, 0x7FF2); \
69 ppc_lwz ((code), (dreg), off1, ppc_r3); \
70 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
73 #define emit_tls_access(code,dreg,key) do { \
75 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
76 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
77 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
78 default: g_assert_not_reached (); \
83 mono_arch_regname (int reg) {
84 static const char rnames[][4] = {
85 "r0", "sp", "r2", "r3", "r4",
86 "r5", "r6", "r7", "r8", "r9",
87 "r10", "r11", "r12", "r13", "r14",
88 "r15", "r16", "r17", "r18", "r19",
89 "r20", "r21", "r22", "r23", "r24",
90 "r25", "r26", "r27", "r28", "r29",
93 if (reg >= 0 && reg < 32)
99 mono_arch_fregname (int reg) {
100 static const char rnames[][4] = {
101 "f0", "f1", "f2", "f3", "f4",
102 "f5", "f6", "f7", "f8", "f9",
103 "f10", "f11", "f12", "f13", "f14",
104 "f15", "f16", "f17", "f18", "f19",
105 "f20", "f21", "f22", "f23", "f24",
106 "f25", "f26", "f27", "f28", "f29",
109 if (reg >= 0 && reg < 32)
114 /* this function overwrites r0, r11, r12 */
116 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
118 /* unrolled, use the counter in big */
119 if (size > sizeof (gpointer) * 5) {
120 int shifted = size >> 2;
121 guint8 *copy_loop_start, *copy_loop_jump;
123 ppc_load (code, ppc_r0, shifted);
124 ppc_mtctr (code, ppc_r0);
125 g_assert (sreg == ppc_r11);
126 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
127 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
128 copy_loop_start = code;
129 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
130 ppc_stwu (code, ppc_r0, 4, ppc_r12);
131 copy_loop_jump = code;
132 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
133 ppc_patch (copy_loop_jump, copy_loop_start);
135 doffset = soffset = 0;
139 ppc_lwz (code, ppc_r0, soffset, sreg);
140 ppc_stw (code, ppc_r0, doffset, dreg);
146 ppc_lhz (code, ppc_r0, soffset, sreg);
147 ppc_sth (code, ppc_r0, doffset, dreg);
153 ppc_lbz (code, ppc_r0, soffset, sreg);
154 ppc_stb (code, ppc_r0, doffset, dreg);
163 * mono_arch_get_argument_info:
164 * @csig: a method signature
165 * @param_count: the number of parameters to consider
166 * @arg_info: an array to store the result infos
168 * Gathers information on parameters such as size, alignment and
169 * padding. arg_info should be large enought to hold param_count + 1 entries.
171 * Returns the size of the activation frame.
174 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
176 int k, frame_size = 0;
177 int size, align, pad;
180 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
181 frame_size += sizeof (gpointer);
185 arg_info [0].offset = offset;
188 frame_size += sizeof (gpointer);
192 arg_info [0].size = frame_size;
194 for (k = 0; k < param_count; k++) {
197 size = mono_type_native_stack_size (csig->params [k], &align);
199 size = mono_type_stack_size (csig->params [k], &align);
201 /* ignore alignment for now */
204 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
205 arg_info [k].pad = pad;
207 arg_info [k + 1].pad = 0;
208 arg_info [k + 1].size = size;
210 arg_info [k + 1].offset = offset;
214 align = MONO_ARCH_FRAME_ALIGNMENT;
215 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
216 arg_info [k].pad = pad;
222 * Initialize the cpu to execute managed code.
225 mono_arch_cpu_init (void)
230 * This function returns the optimizations supported on this cpu.
233 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
237 /* no ppc-specific optimizations yet */
243 is_regsize_var (MonoType *t) {
246 t = mono_type_get_underlying_type (t);
253 case MONO_TYPE_FNPTR:
255 case MONO_TYPE_OBJECT:
256 case MONO_TYPE_STRING:
257 case MONO_TYPE_CLASS:
258 case MONO_TYPE_SZARRAY:
259 case MONO_TYPE_ARRAY:
261 case MONO_TYPE_GENERICINST:
262 if (!mono_type_generic_inst_is_valuetype (t))
265 case MONO_TYPE_VALUETYPE:
272 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
277 for (i = 0; i < cfg->num_varinfo; i++) {
278 MonoInst *ins = cfg->varinfo [i];
279 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
282 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
285 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
288 /* we can only allocate 32 bit values */
289 if (is_regsize_var (ins->inst_vtype)) {
290 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
291 g_assert (i == vmv->idx);
292 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
300 mono_arch_get_global_int_regs (MonoCompile *cfg)
304 if (cfg->frame_reg != ppc_sp)
306 for (i = 13; i < top; ++i)
307 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
313 * mono_arch_regalloc_cost:
315 * Return the cost, in number of memory references, of the action of
316 * allocating the variable VMV into a register during global register
320 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
332 mono_arch_flush_icache (guint8 *code, gint size)
334 guint8 *p, *endp, *start;
335 static int cachelinesize = 0;
336 static int cachelineinc = 16;
338 if (!cachelinesize) {
342 mib [1] = HW_CACHELINE;
343 len = sizeof (cachelinesize);
344 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
348 cachelineinc = cachelinesize;
349 /*g_print ("setting cl size to %d\n", cachelinesize);*/
351 #elif defined(__linux__)
352 /* sadly this will work only with 2.6 kernels... */
353 FILE* f = fopen ("/proc/self/auxv", "rb");
356 while (fread (&vec, sizeof (vec), 1, f) == 1) {
357 if (vec.type == 19) {
358 cachelinesize = vec.value;
367 #warning Need a way to get cache line size
373 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
374 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
376 for (p = start; p < endp; p += cachelineinc) {
377 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
380 for (p = start; p < endp; p += cachelineinc) {
381 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
386 for (p = start; p < endp; p += cachelineinc) {
387 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
393 #define NOT_IMPLEMENTED(x) \
394 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
397 #define ALWAYS_ON_STACK(s) s
398 #define FP_ALSO_IN_REG(s) s
400 #define ALWAYS_ON_STACK(s)
401 #define FP_ALSO_IN_REG(s)
402 #define ALIGN_DOUBLES
415 guint16 vtsize; /* in param area */
417 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
418 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
433 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
436 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
437 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
438 ainfo->reg = ppc_sp; /* in the caller */
439 ainfo->regtype = RegTypeBase;
442 ALWAYS_ON_STACK (*stack_size += 4);
446 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
448 //*stack_size += (*stack_size % 8);
450 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
451 ainfo->reg = ppc_sp; /* in the caller */
452 ainfo->regtype = RegTypeBase;
459 ALWAYS_ON_STACK (*stack_size += 8);
468 /* size == 4 is checked already */
470 has_only_a_r4_field (MonoClass *klass)
475 while ((f = mono_class_get_fields (klass, &iter))) {
476 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
477 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
487 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
490 int n = sig->hasthis + sig->param_count;
492 guint32 stack_size = 0;
493 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
495 fr = PPC_FIRST_FPARG_REG;
496 gr = PPC_FIRST_ARG_REG;
498 /* FIXME: handle returning a struct */
499 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
500 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
501 cinfo->struct_ret = PPC_FIRST_ARG_REG;
506 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
509 DEBUG(printf("params: %d\n", sig->param_count));
510 for (i = 0; i < sig->param_count; ++i) {
511 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
512 /* Prevent implicit arguments and sig_cookie from
513 being passed in registers */
514 gr = PPC_LAST_ARG_REG + 1;
515 /* Emit the signature cookie just before the implicit arguments */
516 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
518 DEBUG(printf("param %d: ", i));
519 if (sig->params [i]->byref) {
520 DEBUG(printf("byref\n"));
521 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
525 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
526 switch (simpletype) {
527 case MONO_TYPE_BOOLEAN:
530 cinfo->args [n].size = 1;
531 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
537 cinfo->args [n].size = 2;
538 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
543 cinfo->args [n].size = 4;
544 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
550 case MONO_TYPE_FNPTR:
551 case MONO_TYPE_CLASS:
552 case MONO_TYPE_OBJECT:
553 case MONO_TYPE_STRING:
554 case MONO_TYPE_SZARRAY:
555 case MONO_TYPE_ARRAY:
556 cinfo->args [n].size = sizeof (gpointer);
557 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
560 case MONO_TYPE_GENERICINST:
561 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
562 cinfo->args [n].size = sizeof (gpointer);
563 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
568 case MONO_TYPE_VALUETYPE: {
571 klass = mono_class_from_mono_type (sig->params [i]);
573 size = mono_class_native_size (klass, NULL);
575 size = mono_class_value_size (klass, NULL);
577 if (size == 4 && has_only_a_r4_field (klass)) {
578 cinfo->args [n].size = 4;
580 /* It was 7, now it is 8 in LinuxPPC */
581 if (fr <= PPC_LAST_FPARG_REG) {
582 cinfo->args [n].regtype = RegTypeFP;
583 cinfo->args [n].reg = fr;
585 FP_ALSO_IN_REG (gr ++);
586 ALWAYS_ON_STACK (stack_size += 4);
588 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
589 cinfo->args [n].regtype = RegTypeBase;
590 cinfo->args [n].reg = ppc_sp; /* in the caller*/
597 DEBUG(printf ("load %d bytes struct\n",
598 mono_class_native_size (sig->params [i]->data.klass, NULL)));
599 #if PPC_PASS_STRUCTS_BY_VALUE
601 int align_size = size;
603 align_size += (sizeof (gpointer) - 1);
604 align_size &= ~(sizeof (gpointer) - 1);
605 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
606 cinfo->args [n].regtype = RegTypeStructByVal;
607 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
608 cinfo->args [n].size = 0;
609 cinfo->args [n].vtsize = nwords;
611 int rest = PPC_LAST_ARG_REG - gr + 1;
612 int n_in_regs = rest >= nwords? nwords: rest;
613 cinfo->args [n].size = n_in_regs;
614 cinfo->args [n].vtsize = nwords - n_in_regs;
615 cinfo->args [n].reg = gr;
618 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
619 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
620 stack_size += nwords * sizeof (gpointer);
623 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
624 cinfo->args [n].regtype = RegTypeStructByAddr;
629 case MONO_TYPE_TYPEDBYREF: {
630 int size = sizeof (MonoTypedRef);
631 /* keep in sync or merge with the valuetype case */
632 #if PPC_PASS_STRUCTS_BY_VALUE
634 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
635 cinfo->args [n].regtype = RegTypeStructByVal;
636 if (gr <= PPC_LAST_ARG_REG) {
637 int rest = PPC_LAST_ARG_REG - gr + 1;
638 int n_in_regs = rest >= nwords? nwords: rest;
639 cinfo->args [n].size = n_in_regs;
640 cinfo->args [n].vtsize = nwords - n_in_regs;
641 cinfo->args [n].reg = gr;
644 cinfo->args [n].size = 0;
645 cinfo->args [n].vtsize = nwords;
647 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
648 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
649 stack_size += nwords * sizeof (gpointer);
652 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
653 cinfo->args [n].regtype = RegTypeStructByAddr;
660 cinfo->args [n].size = 8;
661 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
665 cinfo->args [n].size = 4;
667 /* It was 7, now it is 8 in LinuxPPC */
668 if (fr <= PPC_LAST_FPARG_REG) {
669 cinfo->args [n].regtype = RegTypeFP;
670 cinfo->args [n].reg = fr;
672 FP_ALSO_IN_REG (gr ++);
673 ALWAYS_ON_STACK (stack_size += 4);
675 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
676 cinfo->args [n].regtype = RegTypeBase;
677 cinfo->args [n].reg = ppc_sp; /* in the caller*/
683 cinfo->args [n].size = 8;
684 /* It was 7, now it is 8 in LinuxPPC */
685 if (fr <= PPC_LAST_FPARG_REG) {
686 cinfo->args [n].regtype = RegTypeFP;
687 cinfo->args [n].reg = fr;
689 FP_ALSO_IN_REG (gr += 2);
690 ALWAYS_ON_STACK (stack_size += 8);
692 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
693 cinfo->args [n].regtype = RegTypeBase;
694 cinfo->args [n].reg = ppc_sp; /* in the caller*/
700 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
705 simpletype = mono_type_get_underlying_type (sig->ret)->type;
706 switch (simpletype) {
707 case MONO_TYPE_BOOLEAN:
718 case MONO_TYPE_FNPTR:
719 case MONO_TYPE_CLASS:
720 case MONO_TYPE_OBJECT:
721 case MONO_TYPE_SZARRAY:
722 case MONO_TYPE_ARRAY:
723 case MONO_TYPE_STRING:
724 cinfo->ret.reg = ppc_r3;
728 cinfo->ret.reg = ppc_r3;
732 cinfo->ret.reg = ppc_f1;
733 cinfo->ret.regtype = RegTypeFP;
735 case MONO_TYPE_GENERICINST:
736 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
737 cinfo->ret.reg = ppc_r3;
741 case MONO_TYPE_VALUETYPE:
743 case MONO_TYPE_TYPEDBYREF:
747 g_error ("Can't handle as return value 0x%x", sig->ret->type);
751 /* align stack size to 16 */
752 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
753 stack_size = (stack_size + 15) & ~15;
755 cinfo->stack_usage = stack_size;
761 * Set var information according to the calling convention. ppc version.
762 * The locals var stuff should most likely be split in another method.
765 mono_arch_allocate_vars (MonoCompile *m)
767 MonoMethodSignature *sig;
768 MonoMethodHeader *header;
770 int i, offset, size, align, curinst;
771 int frame_reg = ppc_sp;
773 m->flags |= MONO_CFG_HAS_SPILLUP;
775 /* allow room for the vararg method args: void* and long/double */
776 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
777 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
778 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
779 * call convs needs to be handled this way.
781 if (m->flags & MONO_CFG_HAS_VARARGS)
782 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
783 /* gtk-sharp and other broken code will dllimport vararg functions even with
784 * non-varargs signatures. Since there is little hope people will get this right
785 * we assume they won't.
787 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
788 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
790 header = mono_method_get_header (m->method);
793 * We use the frame register also for any method that has
794 * exception clauses. This way, when the handlers are called,
795 * the code will reference local variables using the frame reg instead of
796 * the stack pointer: if we had to restore the stack pointer, we'd
797 * corrupt the method frames that are already on the stack (since
798 * filters get called before stack unwinding happens) when the filter
799 * code would call any method (this also applies to finally etc.).
801 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
803 m->frame_reg = frame_reg;
804 if (frame_reg != ppc_sp) {
805 m->used_int_regs |= 1 << frame_reg;
808 sig = mono_method_signature (m->method);
812 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
813 m->ret->opcode = OP_REGVAR;
814 m->ret->inst_c0 = ppc_r3;
816 /* FIXME: handle long and FP values */
817 switch (mono_type_get_underlying_type (sig->ret)->type) {
821 m->ret->opcode = OP_REGVAR;
822 m->ret->inst_c0 = ppc_r3;
826 /* local vars are at a positive offset from the stack pointer */
828 * also note that if the function uses alloca, we use ppc_r31
829 * to point at the local variables.
831 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
832 /* align the offset to 16 bytes: not sure this is needed here */
834 //offset &= ~(16 - 1);
836 /* add parameter area size for called functions */
837 offset += m->param_area;
841 /* allow room to save the return value */
842 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
845 /* the MonoLMF structure is stored just below the stack pointer */
848 /* this stuff should not be needed on ppc and the new jit,
849 * because a call on ppc to the handlers doesn't change the
850 * stack pointer and the jist doesn't manipulate the stack pointer
851 * for operations involving valuetypes.
853 /* reserve space to store the esp */
854 offset += sizeof (gpointer);
856 /* this is a global constant */
857 mono_exc_esp_offset = offset;
859 if (sig->call_convention == MONO_CALL_VARARG) {
860 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
863 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
865 offset += sizeof(gpointer) - 1;
866 offset &= ~(sizeof(gpointer) - 1);
867 inst->inst_offset = offset;
868 inst->opcode = OP_REGOFFSET;
869 inst->inst_basereg = frame_reg;
870 offset += sizeof(gpointer);
871 if (sig->call_convention == MONO_CALL_VARARG)
872 m->sig_cookie += sizeof (gpointer);
875 curinst = m->locals_start;
876 for (i = curinst; i < m->num_varinfo; ++i) {
877 inst = m->varinfo [i];
878 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
881 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
882 * pinvoke wrappers when they call functions returning structure */
883 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
884 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
886 size = mono_type_size (inst->inst_vtype, &align);
889 offset &= ~(align - 1);
890 inst->inst_offset = offset;
891 inst->opcode = OP_REGOFFSET;
892 inst->inst_basereg = frame_reg;
894 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
899 inst = m->varinfo [curinst];
900 if (inst->opcode != OP_REGVAR) {
901 inst->opcode = OP_REGOFFSET;
902 inst->inst_basereg = frame_reg;
903 offset += sizeof (gpointer) - 1;
904 offset &= ~(sizeof (gpointer) - 1);
905 inst->inst_offset = offset;
906 offset += sizeof (gpointer);
907 if (sig->call_convention == MONO_CALL_VARARG)
908 m->sig_cookie += sizeof (gpointer);
913 for (i = 0; i < sig->param_count; ++i) {
914 inst = m->varinfo [curinst];
915 if (inst->opcode != OP_REGVAR) {
916 inst->opcode = OP_REGOFFSET;
917 inst->inst_basereg = frame_reg;
918 size = mono_type_size (sig->params [i], &align);
920 offset &= ~(align - 1);
921 inst->inst_offset = offset;
923 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
924 m->sig_cookie += size;
929 /* align the offset to 16 bytes */
934 m->stack_offset = offset;
938 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
939 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
943 * take the arguments and generate the arch-specific
944 * instructions to properly call the function in call.
945 * This includes pushing, moving arguments to the right register
947 * Issue: who does the spilling if needed, and when?
950 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
952 MonoMethodSignature *sig;
957 sig = call->signature;
958 n = sig->param_count + sig->hasthis;
960 cinfo = calculate_sizes (sig, sig->pinvoke);
961 if (cinfo->struct_ret)
962 call->used_iregs |= 1 << cinfo->struct_ret;
964 for (i = 0; i < n; ++i) {
965 ainfo = cinfo->args + i;
966 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
968 cfg->disable_aot = TRUE;
970 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
971 sig_arg->inst_p0 = call->signature;
973 MONO_INST_NEW (cfg, arg, OP_OUTARG);
974 arg->inst_imm = cinfo->sig_cookie.offset;
975 arg->inst_left = sig_arg;
977 /* prepend, so they get reversed */
978 arg->next = call->out_args;
979 call->out_args = arg;
981 if (is_virtual && i == 0) {
982 /* the argument will be attached to the call instrucion */
984 call->used_iregs |= 1 << ainfo->reg;
986 MONO_INST_NEW (cfg, arg, OP_OUTARG);
988 arg->cil_code = in->cil_code;
990 arg->inst_call = call;
991 arg->type = in->type;
992 /* prepend, we'll need to reverse them later */
993 arg->next = call->out_args;
994 call->out_args = arg;
995 if (ainfo->regtype == RegTypeGeneral) {
996 arg->backend.reg3 = ainfo->reg;
997 call->used_iregs |= 1 << ainfo->reg;
998 if (arg->type == STACK_I8)
999 call->used_iregs |= 1 << (ainfo->reg + 1);
1000 } else if (ainfo->regtype == RegTypeStructByAddr) {
1001 /* FIXME: where si the data allocated? */
1002 arg->backend.reg3 = ainfo->reg;
1003 call->used_iregs |= 1 << ainfo->reg;
1004 } else if (ainfo->regtype == RegTypeStructByVal) {
1006 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1007 /* mark the used regs */
1008 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1009 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1011 arg->opcode = OP_OUTARG_VT;
1012 ai->reg = ainfo->reg;
1013 ai->size = ainfo->size;
1014 ai->vtsize = ainfo->vtsize;
1015 ai->offset = ainfo->offset;
1016 arg->backend.data = ai;
1017 } else if (ainfo->regtype == RegTypeBase) {
1018 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1019 arg->opcode = OP_OUTARG_MEMBASE;
1020 ai->reg = ainfo->reg;
1021 ai->size = ainfo->size;
1022 ai->offset = ainfo->offset;
1023 arg->backend.data = ai;
1024 } else if (ainfo->regtype == RegTypeFP) {
1025 arg->opcode = OP_OUTARG_R8;
1026 arg->backend.reg3 = ainfo->reg;
1027 call->used_fregs |= 1 << ainfo->reg;
1028 if (ainfo->size == 4) {
1029 arg->opcode = OP_OUTARG_R8;
1030 /* we reduce the precision */
1032 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1033 conv->inst_left = arg->inst_left;
1034 arg->inst_left = conv;*/
1037 g_assert_not_reached ();
1042 * Reverse the call->out_args list.
1045 MonoInst *prev = NULL, *list = call->out_args, *next;
1052 call->out_args = prev;
1054 call->stack_usage = cinfo->stack_usage;
1055 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1056 cfg->flags |= MONO_CFG_HAS_CALLS;
1058 * should set more info in call, such as the stack space
1059 * used by the args that needs to be added back to esp
1067 * Allow tracing to work with this interface (with an optional argument)
1071 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1075 ppc_load (code, ppc_r3, cfg->method);
1076 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1077 ppc_load (code, ppc_r0, func);
1078 ppc_mtlr (code, ppc_r0);
1092 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1095 int save_mode = SAVE_NONE;
1097 MonoMethod *method = cfg->method;
1098 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1099 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1103 offset = code - cfg->native_code;
1104 /* we need about 16 instructions */
1105 if (offset > (cfg->code_size - 16 * 4)) {
1106 cfg->code_size *= 2;
1107 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1108 code = cfg->native_code + offset;
1112 case MONO_TYPE_VOID:
1113 /* special case string .ctor icall */
1114 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1115 save_mode = SAVE_ONE;
1117 save_mode = SAVE_NONE;
1121 save_mode = SAVE_TWO;
1125 save_mode = SAVE_FP;
1127 case MONO_TYPE_VALUETYPE:
1128 save_mode = SAVE_STRUCT;
1131 save_mode = SAVE_ONE;
1135 switch (save_mode) {
1137 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1138 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1139 if (enable_arguments) {
1140 ppc_mr (code, ppc_r5, ppc_r4);
1141 ppc_mr (code, ppc_r4, ppc_r3);
1145 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1146 if (enable_arguments) {
1147 ppc_mr (code, ppc_r4, ppc_r3);
1151 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1152 if (enable_arguments) {
1153 /* FIXME: what reg? */
1154 ppc_fmr (code, ppc_f3, ppc_f1);
1155 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1156 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1160 if (enable_arguments) {
1161 /* FIXME: get the actual address */
1162 ppc_mr (code, ppc_r4, ppc_r3);
1170 ppc_load (code, ppc_r3, cfg->method);
1171 ppc_load (code, ppc_r0, func);
1172 ppc_mtlr (code, ppc_r0);
1175 switch (save_mode) {
1177 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1178 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1181 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1184 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1194 * Conditional branches have a small offset, so if it is likely overflowed,
1195 * we do a branch to the end of the method (uncond branches have much larger
1196 * offsets) where we perform the conditional and jump back unconditionally.
1197 * It's slightly slower, since we add two uncond branches, but it's very simple
1198 * with the current patch implementation and such large methods are likely not
1199 * going to be perf critical anyway.
1204 const char *exception;
1211 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1212 if (ins->flags & MONO_INST_BRLABEL) { \
1213 if (0 && ins->inst_i0->inst_c0) { \
1214 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1216 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1217 ppc_bc (code, (b0), (b1), 0); \
1220 if (0 && ins->inst_true_bb->native_offset) { \
1221 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1223 int br_disp = ins->inst_true_bb->max_offset - offset; \
1224 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1225 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1226 ovfj->data.bb = ins->inst_true_bb; \
1227 ovfj->ip_offset = 0; \
1228 ovfj->b0_cond = (b0); \
1229 ovfj->b1_cond = (b1); \
1230 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1233 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1234 ppc_bc (code, (b0), (b1), 0); \
1239 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1241 /* emit an exception if condition is fail
1243 * We assign the extra code used to throw the implicit exceptions
1244 * to cfg->bb_exit as far as the big branch handling is concerned
1246 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1248 int br_disp = cfg->bb_exit->max_offset - offset; \
1249 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1250 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1251 ovfj->data.exception = (exc_name); \
1252 ovfj->ip_offset = code - cfg->native_code; \
1253 ovfj->b0_cond = (b0); \
1254 ovfj->b1_cond = (b1); \
1255 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1257 cfg->bb_exit->max_offset += 24; \
1259 mono_add_patch_info (cfg, code - cfg->native_code, \
1260 MONO_PATCH_INFO_EXC, exc_name); \
1261 ppc_bcl (code, (b0), (b1), 0); \
1265 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1268 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1270 MonoInst *ins, *last_ins = NULL;
1275 switch (ins->opcode) {
1277 /* remove unnecessary multiplication with 1 */
1278 if (ins->inst_imm == 1) {
1279 if (ins->dreg != ins->sreg1) {
1280 ins->opcode = OP_MOVE;
1282 last_ins->next = ins->next;
1287 int power2 = mono_is_power_of_two (ins->inst_imm);
1289 ins->opcode = OP_SHL_IMM;
1290 ins->inst_imm = power2;
1294 case OP_LOAD_MEMBASE:
1295 case OP_LOADI4_MEMBASE:
1297 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1298 * OP_LOAD_MEMBASE offset(basereg), reg
1300 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1301 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1302 ins->inst_basereg == last_ins->inst_destbasereg &&
1303 ins->inst_offset == last_ins->inst_offset) {
1304 if (ins->dreg == last_ins->sreg1) {
1305 last_ins->next = ins->next;
1309 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1310 ins->opcode = OP_MOVE;
1311 ins->sreg1 = last_ins->sreg1;
1315 * Note: reg1 must be different from the basereg in the second load
1316 * OP_LOAD_MEMBASE offset(basereg), reg1
1317 * OP_LOAD_MEMBASE offset(basereg), reg2
1319 * OP_LOAD_MEMBASE offset(basereg), reg1
1320 * OP_MOVE reg1, reg2
1322 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1323 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1324 ins->inst_basereg != last_ins->dreg &&
1325 ins->inst_basereg == last_ins->inst_basereg &&
1326 ins->inst_offset == last_ins->inst_offset) {
1328 if (ins->dreg == last_ins->dreg) {
1329 last_ins->next = ins->next;
1333 ins->opcode = OP_MOVE;
1334 ins->sreg1 = last_ins->dreg;
1337 //g_assert_not_reached ();
1341 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1342 * OP_LOAD_MEMBASE offset(basereg), reg
1344 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1345 * OP_ICONST reg, imm
1347 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1348 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1349 ins->inst_basereg == last_ins->inst_destbasereg &&
1350 ins->inst_offset == last_ins->inst_offset) {
1351 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1352 ins->opcode = OP_ICONST;
1353 ins->inst_c0 = last_ins->inst_imm;
1354 g_assert_not_reached (); // check this rule
1358 case OP_LOADU1_MEMBASE:
1359 case OP_LOADI1_MEMBASE:
1360 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1361 ins->inst_basereg == last_ins->inst_destbasereg &&
1362 ins->inst_offset == last_ins->inst_offset) {
1363 if (ins->dreg == last_ins->sreg1) {
1364 last_ins->next = ins->next;
1368 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1369 ins->opcode = OP_MOVE;
1370 ins->sreg1 = last_ins->sreg1;
1374 case OP_LOADU2_MEMBASE:
1375 case OP_LOADI2_MEMBASE:
1376 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1377 ins->inst_basereg == last_ins->inst_destbasereg &&
1378 ins->inst_offset == last_ins->inst_offset) {
1379 if (ins->dreg == last_ins->sreg1) {
1380 last_ins->next = ins->next;
1384 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1385 ins->opcode = OP_MOVE;
1386 ins->sreg1 = last_ins->sreg1;
1394 ins->opcode = OP_MOVE;
1398 if (ins->dreg == ins->sreg1) {
1400 last_ins->next = ins->next;
1405 * OP_MOVE sreg, dreg
1406 * OP_MOVE dreg, sreg
1408 if (last_ins && last_ins->opcode == OP_MOVE &&
1409 ins->sreg1 == last_ins->dreg &&
1410 ins->dreg == last_ins->sreg1) {
1411 last_ins->next = ins->next;
1420 bb->last_ins = last_ins;
1424 * the branch_b0_table should maintain the order of these
1438 branch_b0_table [] = {
1453 branch_b1_table [] = {
1467 static const char*const * ins_spec = ppcg4;
1470 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1474 bb->code = to_insert;
1475 to_insert->next = ins;
1477 to_insert->next = ins->next;
1478 ins->next = to_insert;
1482 #define NEW_INS(cfg,dest,op) do { \
1483 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1484 (dest)->opcode = (op); \
1485 insert_after_ins (bb, last_ins, (dest)); \
1489 map_to_reg_reg_op (int op)
1498 case OP_COMPARE_IMM:
1514 case OP_LOAD_MEMBASE:
1515 return OP_LOAD_MEMINDEX;
1516 case OP_LOADI4_MEMBASE:
1517 return OP_LOADI4_MEMINDEX;
1518 case OP_LOADU4_MEMBASE:
1519 return OP_LOADU4_MEMINDEX;
1520 case OP_LOADU1_MEMBASE:
1521 return OP_LOADU1_MEMINDEX;
1522 case OP_LOADI2_MEMBASE:
1523 return OP_LOADI2_MEMINDEX;
1524 case OP_LOADU2_MEMBASE:
1525 return OP_LOADU2_MEMINDEX;
1526 case OP_LOADI1_MEMBASE:
1527 return OP_LOADI1_MEMINDEX;
1528 case OP_LOADR4_MEMBASE:
1529 return OP_LOADR4_MEMINDEX;
1530 case OP_LOADR8_MEMBASE:
1531 return OP_LOADR8_MEMINDEX;
1532 case OP_STOREI1_MEMBASE_REG:
1533 return OP_STOREI1_MEMINDEX;
1534 case OP_STOREI2_MEMBASE_REG:
1535 return OP_STOREI2_MEMINDEX;
1536 case OP_STOREI4_MEMBASE_REG:
1537 return OP_STOREI4_MEMINDEX;
1538 case OP_STORE_MEMBASE_REG:
1539 return OP_STORE_MEMINDEX;
1540 case OP_STORER4_MEMBASE_REG:
1541 return OP_STORER4_MEMINDEX;
1542 case OP_STORER8_MEMBASE_REG:
1543 return OP_STORER8_MEMINDEX;
1544 case OP_STORE_MEMBASE_IMM:
1545 return OP_STORE_MEMBASE_REG;
1546 case OP_STOREI1_MEMBASE_IMM:
1547 return OP_STOREI1_MEMBASE_REG;
1548 case OP_STOREI2_MEMBASE_IMM:
1549 return OP_STOREI2_MEMBASE_REG;
1550 case OP_STOREI4_MEMBASE_IMM:
1551 return OP_STOREI4_MEMBASE_REG;
1553 g_assert_not_reached ();
1556 #define compare_opcode_is_unsigned(opcode) \
1557 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1558 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1559 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1561 * Remove from the instruction list the instructions that can't be
1562 * represented with very simple instructions with no register
1566 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1568 MonoInst *ins, *next, *temp, *last_ins = NULL;
1571 /* setup the virtual reg allocator */
1572 if (bb->max_ireg > cfg->rs->next_vireg)
1573 cfg->rs->next_vireg = bb->max_ireg;
1578 switch (ins->opcode) {
1581 if (!ppc_is_imm16 (ins->inst_imm)) {
1582 NEW_INS (cfg, temp, OP_ICONST);
1583 temp->inst_c0 = ins->inst_imm;
1584 temp->dreg = mono_regstate_next_int (cfg->rs);
1585 ins->sreg2 = temp->dreg;
1586 ins->opcode = map_to_reg_reg_op (ins->opcode);
1590 if (!ppc_is_imm16 (-ins->inst_imm)) {
1591 NEW_INS (cfg, temp, OP_ICONST);
1592 temp->inst_c0 = ins->inst_imm;
1593 temp->dreg = mono_regstate_next_int (cfg->rs);
1594 ins->sreg2 = temp->dreg;
1595 ins->opcode = map_to_reg_reg_op (ins->opcode);
1601 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1602 NEW_INS (cfg, temp, OP_ICONST);
1603 temp->inst_c0 = ins->inst_imm;
1604 temp->dreg = mono_regstate_next_int (cfg->rs);
1605 ins->sreg2 = temp->dreg;
1606 ins->opcode = map_to_reg_reg_op (ins->opcode);
1612 NEW_INS (cfg, temp, OP_ICONST);
1613 temp->inst_c0 = ins->inst_imm;
1614 temp->dreg = mono_regstate_next_int (cfg->rs);
1615 ins->sreg2 = temp->dreg;
1616 ins->opcode = map_to_reg_reg_op (ins->opcode);
1618 case OP_COMPARE_IMM:
1619 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1620 if (!ppc_is_uimm16 (ins->inst_imm)) {
1621 NEW_INS (cfg, temp, OP_ICONST);
1622 temp->inst_c0 = ins->inst_imm;
1623 temp->dreg = mono_regstate_next_int (cfg->rs);
1624 ins->sreg2 = temp->dreg;
1625 ins->opcode = map_to_reg_reg_op (ins->opcode);
1628 if (!ppc_is_imm16 (ins->inst_imm)) {
1629 NEW_INS (cfg, temp, OP_ICONST);
1630 temp->inst_c0 = ins->inst_imm;
1631 temp->dreg = mono_regstate_next_int (cfg->rs);
1632 ins->sreg2 = temp->dreg;
1633 ins->opcode = map_to_reg_reg_op (ins->opcode);
1638 if (ins->inst_imm == 1) {
1639 ins->opcode = OP_MOVE;
1642 if (ins->inst_imm == 0) {
1643 ins->opcode = OP_ICONST;
1647 imm = mono_is_power_of_two (ins->inst_imm);
1649 ins->opcode = OP_SHL_IMM;
1650 ins->inst_imm = imm;
1653 if (!ppc_is_imm16 (ins->inst_imm)) {
1654 NEW_INS (cfg, temp, OP_ICONST);
1655 temp->inst_c0 = ins->inst_imm;
1656 temp->dreg = mono_regstate_next_int (cfg->rs);
1657 ins->sreg2 = temp->dreg;
1658 ins->opcode = map_to_reg_reg_op (ins->opcode);
1661 case OP_LOAD_MEMBASE:
1662 case OP_LOADI4_MEMBASE:
1663 case OP_LOADU4_MEMBASE:
1664 case OP_LOADI2_MEMBASE:
1665 case OP_LOADU2_MEMBASE:
1666 case OP_LOADI1_MEMBASE:
1667 case OP_LOADU1_MEMBASE:
1668 case OP_LOADR4_MEMBASE:
1669 case OP_LOADR8_MEMBASE:
1670 case OP_STORE_MEMBASE_REG:
1671 case OP_STOREI4_MEMBASE_REG:
1672 case OP_STOREI2_MEMBASE_REG:
1673 case OP_STOREI1_MEMBASE_REG:
1674 case OP_STORER4_MEMBASE_REG:
1675 case OP_STORER8_MEMBASE_REG:
1676 /* we can do two things: load the immed in a register
1677 * and use an indexed load, or see if the immed can be
1678 * represented as an ad_imm + a load with a smaller offset
1679 * that fits. We just do the first for now, optimize later.
1681 if (ppc_is_imm16 (ins->inst_offset))
1683 NEW_INS (cfg, temp, OP_ICONST);
1684 temp->inst_c0 = ins->inst_offset;
1685 temp->dreg = mono_regstate_next_int (cfg->rs);
1686 ins->sreg2 = temp->dreg;
1687 ins->opcode = map_to_reg_reg_op (ins->opcode);
1689 case OP_STORE_MEMBASE_IMM:
1690 case OP_STOREI1_MEMBASE_IMM:
1691 case OP_STOREI2_MEMBASE_IMM:
1692 case OP_STOREI4_MEMBASE_IMM:
1693 NEW_INS (cfg, temp, OP_ICONST);
1694 temp->inst_c0 = ins->inst_imm;
1695 temp->dreg = mono_regstate_next_int (cfg->rs);
1696 ins->sreg1 = temp->dreg;
1697 ins->opcode = map_to_reg_reg_op (ins->opcode);
1699 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1704 bb->last_ins = last_ins;
1705 bb->max_ireg = cfg->rs->next_vireg;
1710 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1714 mono_arch_lowering_pass (cfg, bb);
1715 mono_local_regalloc (cfg, bb);
1719 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1721 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1722 ppc_fctiwz (code, ppc_f0, sreg);
1723 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1724 ppc_lwz (code, dreg, -4, ppc_sp);
1727 ppc_andid (code, dreg, dreg, 0xff);
1729 ppc_andid (code, dreg, dreg, 0xffff);
1732 ppc_extsb (code, dreg, dreg);
1734 ppc_extsh (code, dreg, dreg);
1739 static unsigned char*
1740 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1743 int sreg = tree->sreg1;
1744 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1745 if (tree->flags & MONO_INST_INIT) {
1747 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1748 x86_push_reg (code, X86_EAX);
1751 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1752 x86_push_reg (code, X86_ECX);
1755 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1756 x86_push_reg (code, X86_EDI);
1760 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1761 if (sreg != X86_ECX)
1762 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1763 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1765 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1767 x86_prefix (code, X86_REP_PREFIX);
1770 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1771 x86_pop_reg (code, X86_EDI);
1772 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1773 x86_pop_reg (code, X86_ECX);
1774 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1775 x86_pop_reg (code, X86_EAX);
1788 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1791 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1792 PatchData *pdata = (PatchData*)user_data;
1793 guchar *code = data;
1794 guint32 *thunks = data;
1795 guint32 *endthunks = (guint32*)(code + bsize);
1799 int difflow, diffhigh;
1801 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1802 difflow = (char*)pdata->code - (char*)thunks;
1803 diffhigh = (char*)pdata->code - (char*)endthunks;
1804 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1807 templ = (guchar*)load;
1808 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1809 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1811 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1812 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1813 while (thunks < endthunks) {
1814 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1815 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1816 ppc_patch (pdata->code, (guchar*)thunks);
1817 mono_arch_flush_icache (pdata->code, 4);
1820 static int num_thunks = 0;
1822 if ((num_thunks % 20) == 0)
1823 g_print ("num_thunks lookup: %d\n", num_thunks);
1826 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1827 /* found a free slot instead: emit thunk */
1828 code = (guchar*)thunks;
1829 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1830 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1831 ppc_mtctr (code, ppc_r0);
1832 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1833 mono_arch_flush_icache ((guchar*)thunks, 16);
1835 ppc_patch (pdata->code, (guchar*)thunks);
1836 mono_arch_flush_icache (pdata->code, 4);
1839 static int num_thunks = 0;
1841 if ((num_thunks % 20) == 0)
1842 g_print ("num_thunks: %d\n", num_thunks);
1846 /* skip 16 bytes, the size of the thunk */
1850 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1856 handle_thunk (int absolute, guchar *code, guchar *target) {
1857 MonoDomain *domain = mono_domain_get ();
1861 pdata.target = target;
1862 pdata.absolute = absolute;
1865 mono_domain_lock (domain);
1866 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1869 /* this uses the first available slot */
1871 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1873 mono_domain_unlock (domain);
1875 if (pdata.found != 1)
1876 g_print ("thunk failed for %p from %p\n", target, code);
1877 g_assert (pdata.found == 1);
1881 ppc_patch (guchar *code, guchar *target)
1883 guint32 ins = *(guint32*)code;
1884 guint32 prim = ins >> 26;
1887 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1889 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1890 gint diff = target - code;
1892 if (diff <= 33554431){
1893 ins = (18 << 26) | (diff) | (ins & 1);
1894 *(guint32*)code = ins;
1898 /* diff between 0 and -33554432 */
1899 if (diff >= -33554432){
1900 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1901 *(guint32*)code = ins;
1906 if ((glong)target >= 0){
1907 if ((glong)target <= 33554431){
1908 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1909 *(guint32*)code = ins;
1913 if ((glong)target >= -33554432){
1914 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1915 *(guint32*)code = ins;
1920 handle_thunk (TRUE, code, target);
1923 g_assert_not_reached ();
1930 guint32 li = (guint32)target;
1931 ins = (ins & 0xffff0000) | (ins & 3);
1932 ovf = li & 0xffff0000;
1933 if (ovf != 0 && ovf != 0xffff0000)
1934 g_assert_not_reached ();
1937 // FIXME: assert the top bits of li are 0
1939 gint diff = target - code;
1940 ins = (ins & 0xffff0000) | (ins & 3);
1941 ovf = diff & 0xffff0000;
1942 if (ovf != 0 && ovf != 0xffff0000)
1943 g_assert_not_reached ();
1947 *(guint32*)code = ins;
1951 if (prim == 15 || ins == 0x4e800021) {
1953 /* the trampoline code will try to patch the blrl */
1954 if (ins == 0x4e800021) {
1957 /* this is the lis/ori/mtlr/blrl sequence */
1958 seq = (guint32*)code;
1959 g_assert ((seq [0] >> 26) == 15);
1960 g_assert ((seq [1] >> 26) == 24);
1961 g_assert ((seq [2] >> 26) == 31);
1962 g_assert (seq [3] == 0x4e800021);
1963 /* FIXME: make this thread safe */
1964 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
1965 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
1966 mono_arch_flush_icache (code - 8, 8);
1968 g_assert_not_reached ();
1970 // g_print ("patched with 0x%08x\n", ins);
1974 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1979 guint8 *code = cfg->native_code + cfg->code_len;
1980 MonoInst *last_ins = NULL;
1981 guint last_offset = 0;
1984 if (cfg->opt & MONO_OPT_PEEPHOLE)
1985 peephole_pass (cfg, bb);
1987 /* we don't align basic blocks of loops on ppc */
1989 if (cfg->verbose_level > 2)
1990 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1992 cpos = bb->max_offset;
1994 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1995 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1996 //g_assert (!mono_compile_aot);
1999 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2000 /* this is not thread save, but good enough */
2001 /* fixme: howto handle overflows? */
2002 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2007 offset = code - cfg->native_code;
2009 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2011 if (offset > (cfg->code_size - max_len - 16)) {
2012 cfg->code_size *= 2;
2013 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2014 code = cfg->native_code + offset;
2016 // if (ins->cil_code)
2017 // g_print ("cil code\n");
2018 mono_debug_record_line_number (cfg, ins, offset);
2020 switch (ins->opcode) {
2022 emit_tls_access (code, ins->dreg, ins->inst_offset);
2025 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2026 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2027 ppc_mr (code, ppc_r4, ppc_r0);
2030 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2031 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2032 ppc_mr (code, ppc_r4, ppc_r0);
2034 case OP_MEMORY_BARRIER:
2037 case OP_STOREI1_MEMBASE_REG:
2038 if (ppc_is_imm16 (ins->inst_offset)) {
2039 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2041 g_assert_not_reached ();
2044 case OP_STOREI2_MEMBASE_REG:
2045 if (ppc_is_imm16 (ins->inst_offset)) {
2046 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2048 g_assert_not_reached ();
2051 case OP_STORE_MEMBASE_REG:
2052 case OP_STOREI4_MEMBASE_REG:
2053 if (ppc_is_imm16 (ins->inst_offset)) {
2054 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2056 g_assert_not_reached ();
2059 case OP_STOREI1_MEMINDEX:
2060 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2062 case OP_STOREI2_MEMINDEX:
2063 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2065 case OP_STORE_MEMINDEX:
2066 case OP_STOREI4_MEMINDEX:
2067 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2072 g_assert_not_reached ();
2073 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2076 g_assert_not_reached ();
2078 case OP_LOAD_MEMBASE:
2079 case OP_LOADI4_MEMBASE:
2080 case OP_LOADU4_MEMBASE:
2081 if (ppc_is_imm16 (ins->inst_offset)) {
2082 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2084 g_assert_not_reached ();
2087 case OP_LOADI1_MEMBASE:
2088 case OP_LOADU1_MEMBASE:
2089 if (ppc_is_imm16 (ins->inst_offset)) {
2090 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2092 g_assert_not_reached ();
2094 if (ins->opcode == OP_LOADI1_MEMBASE)
2095 ppc_extsb (code, ins->dreg, ins->dreg);
2097 case OP_LOADU2_MEMBASE:
2098 if (ppc_is_imm16 (ins->inst_offset)) {
2099 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2101 g_assert_not_reached ();
2104 case OP_LOADI2_MEMBASE:
2105 if (ppc_is_imm16 (ins->inst_offset)) {
2106 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2108 g_assert_not_reached ();
2111 case OP_LOAD_MEMINDEX:
2112 case OP_LOADI4_MEMINDEX:
2113 case OP_LOADU4_MEMINDEX:
2114 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2116 case OP_LOADU2_MEMINDEX:
2117 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2119 case OP_LOADI2_MEMINDEX:
2120 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2122 case OP_LOADU1_MEMINDEX:
2123 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2125 case OP_LOADI1_MEMINDEX:
2126 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2127 ppc_extsb (code, ins->dreg, ins->dreg);
2130 ppc_extsb (code, ins->dreg, ins->sreg1);
2133 ppc_extsh (code, ins->dreg, ins->sreg1);
2136 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2139 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2142 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2143 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2145 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2147 case OP_COMPARE_IMM:
2148 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2149 if (ppc_is_uimm16 (ins->inst_imm)) {
2150 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2152 g_assert_not_reached ();
2155 if (ppc_is_imm16 (ins->inst_imm)) {
2156 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2158 g_assert_not_reached ();
2166 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2169 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2172 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2175 if (ppc_is_imm16 (ins->inst_imm)) {
2176 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2178 g_assert_not_reached ();
2182 if (ppc_is_imm16 (ins->inst_imm)) {
2183 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2185 g_assert_not_reached ();
2189 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2191 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2192 ppc_mfspr (code, ppc_r0, ppc_xer);
2193 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2194 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2196 case CEE_ADD_OVF_UN:
2197 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2199 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2200 ppc_mfspr (code, ppc_r0, ppc_xer);
2201 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2202 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2205 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2207 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2208 ppc_mfspr (code, ppc_r0, ppc_xer);
2209 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2210 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2212 case CEE_SUB_OVF_UN:
2213 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2215 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2216 ppc_mfspr (code, ppc_r0, ppc_xer);
2217 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2218 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2220 case OP_ADD_OVF_CARRY:
2221 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2223 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2224 ppc_mfspr (code, ppc_r0, ppc_xer);
2225 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2226 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2228 case OP_ADD_OVF_UN_CARRY:
2229 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2231 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2232 ppc_mfspr (code, ppc_r0, ppc_xer);
2233 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2234 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2236 case OP_SUB_OVF_CARRY:
2237 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2239 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2240 ppc_mfspr (code, ppc_r0, ppc_xer);
2241 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2242 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2244 case OP_SUB_OVF_UN_CARRY:
2245 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2247 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2248 ppc_mfspr (code, ppc_r0, ppc_xer);
2249 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2250 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2253 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2256 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2259 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2262 // we add the negated value
2263 if (ppc_is_imm16 (-ins->inst_imm))
2264 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2266 g_assert_not_reached ();
2270 g_assert (ppc_is_imm16 (ins->inst_imm));
2271 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2274 ppc_subfze (code, ins->dreg, ins->sreg1);
2277 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2278 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2281 if (!(ins->inst_imm & 0xffff0000)) {
2282 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2283 } else if (!(ins->inst_imm & 0xffff)) {
2284 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2286 g_assert_not_reached ();
2290 guint32 *divisor_is_m1;
2291 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2293 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2294 divisor_is_m1 = code;
2295 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2296 ppc_lis (code, ppc_r11, 0x8000);
2297 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2298 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2299 ppc_patch (divisor_is_m1, code);
2300 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2302 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2303 ppc_mfspr (code, ppc_r0, ppc_xer);
2304 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2305 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2309 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2310 ppc_mfspr (code, ppc_r0, ppc_xer);
2311 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2312 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2315 g_assert_not_reached ();
2317 ppc_load (code, ppc_r11, ins->inst_imm);
2318 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2319 ppc_mfspr (code, ppc_r0, ppc_xer);
2320 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2321 /* FIXME: use OverflowException for 0x80000000/-1 */
2322 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2326 guint32 *divisor_is_m1;
2327 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2328 divisor_is_m1 = code;
2329 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2330 ppc_lis (code, ppc_r11, 0x8000);
2331 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2332 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2333 ppc_patch (divisor_is_m1, code);
2334 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2335 ppc_mfspr (code, ppc_r0, ppc_xer);
2336 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2337 /* FIXME: use OverflowException for 0x80000000/-1 */
2338 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2339 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2340 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2344 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2345 ppc_mfspr (code, ppc_r0, ppc_xer);
2346 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2347 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2348 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2349 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2352 g_assert_not_reached ();
2354 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2357 if (!(ins->inst_imm & 0xffff0000)) {
2358 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2359 } else if (!(ins->inst_imm & 0xffff)) {
2360 ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2362 g_assert_not_reached ();
2366 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2369 if (!(ins->inst_imm & 0xffff0000)) {
2370 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2371 } else if (!(ins->inst_imm & 0xffff)) {
2372 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2374 g_assert_not_reached ();
2378 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2381 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2384 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2387 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2390 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2393 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2396 ppc_not (code, ins->dreg, ins->sreg1);
2399 ppc_neg (code, ins->dreg, ins->sreg1);
2402 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2405 if (ppc_is_imm16 (ins->inst_imm)) {
2406 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2408 g_assert_not_reached ();
2412 /* we annot use mcrxr, since it's not implemented on some processors
2413 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2415 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2416 ppc_mfspr (code, ppc_r0, ppc_xer);
2417 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2418 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2420 case CEE_MUL_OVF_UN:
2421 /* we first multiply to get the high word and compare to 0
2422 * to set the flags, then the result is discarded and then
2423 * we multiply to get the lower * bits result
2425 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2426 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2427 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2428 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2432 ppc_load (code, ins->dreg, ins->inst_c0);
2435 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2436 ppc_lis (code, ins->dreg, 0);
2437 ppc_ori (code, ins->dreg, ins->dreg, 0);
2443 ppc_mr (code, ins->dreg, ins->sreg1);
2446 int saved = ins->sreg1;
2447 if (ins->sreg1 == ppc_r3) {
2448 ppc_mr (code, ppc_r0, ins->sreg1);
2451 if (ins->sreg2 != ppc_r3)
2452 ppc_mr (code, ppc_r3, ins->sreg2);
2453 if (saved != ppc_r4)
2454 ppc_mr (code, ppc_r4, saved);
2459 ppc_fmr (code, ins->dreg, ins->sreg1);
2461 case OP_FCONV_TO_R4:
2462 ppc_frsp (code, ins->dreg, ins->sreg1);
2468 * Keep in sync with mono_arch_emit_epilog
2470 g_assert (!cfg->method->save_lmf);
2471 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2472 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2473 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2475 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2476 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2478 ppc_mtlr (code, ppc_r0);
2480 if (ppc_is_imm16 (cfg->stack_usage)) {
2481 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2483 ppc_load (code, ppc_r11, cfg->stack_usage);
2484 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2486 if (!cfg->method->save_lmf) {
2487 /*for (i = 31; i >= 14; --i) {
2488 if (cfg->used_float_regs & (1 << i)) {
2489 pos += sizeof (double);
2490 ppc_lfd (code, i, -pos, cfg->frame_reg);
2493 for (i = 31; i >= 13; --i) {
2494 if (cfg->used_int_regs & (1 << i)) {
2495 pos += sizeof (gulong);
2496 ppc_lwz (code, i, -pos, cfg->frame_reg);
2500 /* FIXME restore from MonoLMF: though this can't happen yet */
2502 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2507 /* ensure ins->sreg1 is not NULL */
2508 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2511 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2512 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2514 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2515 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2517 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2525 call = (MonoCallInst*)ins;
2526 if (ins->flags & MONO_INST_HAS_METHOD)
2527 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2529 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2530 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2531 ppc_lis (code, ppc_r0, 0);
2532 ppc_ori (code, ppc_r0, ppc_r0, 0);
2533 ppc_mtlr (code, ppc_r0);
2542 case OP_VOIDCALL_REG:
2544 ppc_mtlr (code, ins->sreg1);
2547 case OP_FCALL_MEMBASE:
2548 case OP_LCALL_MEMBASE:
2549 case OP_VCALL_MEMBASE:
2550 case OP_VOIDCALL_MEMBASE:
2551 case OP_CALL_MEMBASE:
2552 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2553 ppc_mtlr (code, ppc_r0);
2557 g_assert_not_reached ();
2560 guint32 * zero_loop_jump, * zero_loop_start;
2561 /* keep alignment */
2562 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2563 int area_offset = alloca_waste;
2565 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2566 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2567 /* use ctr to store the number of words to 0 if needed */
2568 if (ins->flags & MONO_INST_INIT) {
2569 /* we zero 4 bytes at a time */
2570 ppc_addi (code, ppc_r0, ins->sreg1, 3);
2571 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2572 ppc_mtctr (code, ppc_r0);
2574 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2575 ppc_neg (code, ppc_r11, ppc_r11);
2576 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2578 if (ins->flags & MONO_INST_INIT) {
2579 /* adjust the dest reg by -4 so we can use stwu */
2580 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
2581 ppc_li (code, ppc_r11, 0);
2582 zero_loop_start = code;
2583 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2584 zero_loop_jump = code;
2585 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2586 ppc_patch (zero_loop_jump, zero_loop_start);
2588 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2596 ppc_mr (code, ppc_r3, ins->sreg1);
2597 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2598 (gpointer)"mono_arch_throw_exception");
2599 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2600 ppc_lis (code, ppc_r0, 0);
2601 ppc_ori (code, ppc_r0, ppc_r0, 0);
2602 ppc_mtlr (code, ppc_r0);
2611 ppc_mr (code, ppc_r3, ins->sreg1);
2612 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2613 (gpointer)"mono_arch_rethrow_exception");
2614 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2615 ppc_lis (code, ppc_r0, 0);
2616 ppc_ori (code, ppc_r0, ppc_r0, 0);
2617 ppc_mtlr (code, ppc_r0);
2624 case OP_START_HANDLER:
2625 ppc_mflr (code, ppc_r0);
2626 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2627 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2629 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2630 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2634 if (ins->sreg1 != ppc_r3)
2635 ppc_mr (code, ppc_r3, ins->sreg1);
2636 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2637 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2639 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2640 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2642 ppc_mtlr (code, ppc_r0);
2645 case CEE_ENDFINALLY:
2646 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2647 ppc_mtlr (code, ppc_r0);
2650 case OP_CALL_HANDLER:
2651 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2655 ins->inst_c0 = code - cfg->native_code;
2658 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2659 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2661 if (ins->flags & MONO_INST_BRLABEL) {
2662 /*if (ins->inst_i0->inst_c0) {
2664 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2666 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2670 /*if (ins->inst_target_bb->native_offset) {
2672 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2674 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2680 ppc_mtctr (code, ins->sreg1);
2681 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2684 ppc_li (code, ins->dreg, 0);
2685 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2686 ppc_li (code, ins->dreg, 1);
2690 ppc_li (code, ins->dreg, 1);
2691 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2692 ppc_li (code, ins->dreg, 0);
2696 ppc_li (code, ins->dreg, 1);
2697 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2698 ppc_li (code, ins->dreg, 0);
2700 case OP_COND_EXC_EQ:
2701 case OP_COND_EXC_NE_UN:
2702 case OP_COND_EXC_LT:
2703 case OP_COND_EXC_LT_UN:
2704 case OP_COND_EXC_GT:
2705 case OP_COND_EXC_GT_UN:
2706 case OP_COND_EXC_GE:
2707 case OP_COND_EXC_GE_UN:
2708 case OP_COND_EXC_LE:
2709 case OP_COND_EXC_LE_UN:
2710 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2713 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2715 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2716 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2717 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2719 case OP_COND_EXC_OV:
2720 /*ppc_mcrxr (code, 0);
2721 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2723 case OP_COND_EXC_NC:
2724 case OP_COND_EXC_NO:
2725 g_assert_not_reached ();
2737 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2740 /* floating point opcodes */
2742 ppc_load (code, ppc_r11, ins->inst_p0);
2743 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2746 ppc_load (code, ppc_r11, ins->inst_p0);
2747 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2749 case OP_STORER8_MEMBASE_REG:
2750 if (ppc_is_imm16 (ins->inst_offset)) {
2751 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2753 g_assert_not_reached ();
2756 case OP_LOADR8_MEMBASE:
2757 if (ppc_is_imm16 (ins->inst_offset)) {
2758 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2760 g_assert_not_reached ();
2763 case OP_STORER4_MEMBASE_REG:
2764 ppc_frsp (code, ins->sreg1, ins->sreg1);
2765 if (ppc_is_imm16 (ins->inst_offset)) {
2766 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2768 g_assert_not_reached ();
2771 case OP_LOADR4_MEMBASE:
2772 if (ppc_is_imm16 (ins->inst_offset)) {
2773 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2775 g_assert_not_reached ();
2778 case OP_LOADR4_MEMINDEX:
2779 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2781 case OP_LOADR8_MEMINDEX:
2782 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2784 case OP_STORER4_MEMINDEX:
2785 ppc_frsp (code, ins->sreg1, ins->sreg1);
2786 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2788 case OP_STORER8_MEMINDEX:
2789 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2791 case CEE_CONV_R_UN: {
2792 static const guint64 adjust_val = 0x4330000000000000ULL;
2793 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2794 ppc_stw (code, ppc_r0, -8, ppc_sp);
2795 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2796 ppc_load (code, ppc_r11, &adjust_val);
2797 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2798 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2799 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2802 case CEE_CONV_R4: /* FIXME: change precision */
2804 static const guint64 adjust_val = 0x4330000080000000ULL;
2805 // addis is special for ppc_r0
2806 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2807 ppc_stw (code, ppc_r0, -8, ppc_sp);
2808 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2809 ppc_stw (code, ppc_r11, -4, ppc_sp);
2810 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2811 ppc_load (code, ppc_r11, &adjust_val);
2812 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2813 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2816 case OP_FCONV_TO_I1:
2817 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2819 case OP_FCONV_TO_U1:
2820 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2822 case OP_FCONV_TO_I2:
2823 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2825 case OP_FCONV_TO_U2:
2826 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2828 case OP_FCONV_TO_I4:
2830 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2832 case OP_FCONV_TO_U4:
2834 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2836 case OP_FCONV_TO_I8:
2837 case OP_FCONV_TO_U8:
2838 g_assert_not_reached ();
2839 /* Implemented as helper calls */
2841 case OP_LCONV_TO_R_UN:
2842 g_assert_not_reached ();
2843 /* Implemented as helper calls */
2845 case OP_LCONV_TO_OVF_I: {
2846 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2847 // Check if its negative
2848 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2849 negative_branch = code;
2850 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2851 // Its positive msword == 0
2852 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2853 msword_positive_branch = code;
2854 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2856 ovf_ex_target = code;
2857 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2859 ppc_patch (negative_branch, code);
2860 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2861 msword_negative_branch = code;
2862 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2863 ppc_patch (msword_negative_branch, ovf_ex_target);
2865 ppc_patch (msword_positive_branch, code);
2866 if (ins->dreg != ins->sreg1)
2867 ppc_mr (code, ins->dreg, ins->sreg1);
2871 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2874 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2877 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2880 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2883 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2886 ppc_fneg (code, ins->dreg, ins->sreg1);
2890 g_assert_not_reached ();
2893 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2896 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2897 ppc_li (code, ins->dreg, 0);
2898 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2899 ppc_li (code, ins->dreg, 1);
2902 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2903 ppc_li (code, ins->dreg, 1);
2904 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2905 ppc_li (code, ins->dreg, 0);
2908 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2909 ppc_li (code, ins->dreg, 1);
2910 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2911 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2912 ppc_li (code, ins->dreg, 0);
2915 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2916 ppc_li (code, ins->dreg, 1);
2917 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2918 ppc_li (code, ins->dreg, 0);
2921 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2922 ppc_li (code, ins->dreg, 1);
2923 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2924 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2925 ppc_li (code, ins->dreg, 0);
2928 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2931 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2934 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2937 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2938 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2941 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2944 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2945 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2948 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2951 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2954 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2957 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2959 case CEE_CKFINITE: {
2960 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2961 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2962 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2963 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2964 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2965 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2969 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2970 g_assert_not_reached ();
2973 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2974 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2975 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2976 g_assert_not_reached ();
2982 last_offset = offset;
2987 cfg->code_len = code - cfg->native_code;
2991 mono_arch_register_lowlevel_calls (void)
2995 #define patch_lis_ori(ip,val) do {\
2996 guint16 *__lis_ori = (guint16*)(ip); \
2997 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
2998 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3002 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3004 MonoJumpInfo *patch_info;
3006 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3007 unsigned char *ip = patch_info->ip.i + code;
3008 const unsigned char *target;
3010 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3012 switch (patch_info->type) {
3013 case MONO_PATCH_INFO_IP:
3014 patch_lis_ori (ip, ip);
3016 case MONO_PATCH_INFO_METHOD_REL:
3017 g_assert_not_reached ();
3018 *((gpointer *)(ip)) = code + patch_info->data.offset;
3020 case MONO_PATCH_INFO_SWITCH: {
3021 gpointer *table = (gpointer *)patch_info->data.table->table;
3024 patch_lis_ori (ip, table);
3026 for (i = 0; i < patch_info->data.table->table_size; i++) {
3027 table [i] = (int)patch_info->data.table->table [i] + code;
3029 /* we put into the table the absolute address, no need for ppc_patch in this case */
3032 case MONO_PATCH_INFO_METHODCONST:
3033 case MONO_PATCH_INFO_CLASS:
3034 case MONO_PATCH_INFO_IMAGE:
3035 case MONO_PATCH_INFO_FIELD:
3036 case MONO_PATCH_INFO_VTABLE:
3037 case MONO_PATCH_INFO_IID:
3038 case MONO_PATCH_INFO_SFLDA:
3039 case MONO_PATCH_INFO_LDSTR:
3040 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3041 case MONO_PATCH_INFO_LDTOKEN:
3042 /* from OP_AOTCONST : lis + ori */
3043 patch_lis_ori (ip, target);
3045 case MONO_PATCH_INFO_R4:
3046 case MONO_PATCH_INFO_R8:
3047 g_assert_not_reached ();
3048 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3050 case MONO_PATCH_INFO_EXC_NAME:
3051 g_assert_not_reached ();
3052 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3054 case MONO_PATCH_INFO_NONE:
3055 case MONO_PATCH_INFO_BB_OVF:
3056 case MONO_PATCH_INFO_EXC_OVF:
3057 /* everything is dealt with at epilog output time */
3062 ppc_patch (ip, target);
3067 * Stack frame layout:
3069 * ------------------- sp
3070 * MonoLMF structure or saved registers
3071 * -------------------
3073 * -------------------
3075 * -------------------
3076 * optional 8 bytes for tracing
3077 * -------------------
3078 * param area size is cfg->param_area
3079 * -------------------
3080 * linkage area size is PPC_STACK_PARAM_OFFSET
3081 * ------------------- sp
3085 mono_arch_emit_prolog (MonoCompile *cfg)
3087 MonoMethod *method = cfg->method;
3089 MonoMethodSignature *sig;
3091 int alloc_size, pos, max_offset, i;
3097 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3100 sig = mono_method_signature (method);
3101 cfg->code_size = 256 + sig->param_count * 20;
3102 code = cfg->native_code = g_malloc (cfg->code_size);
3104 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3105 ppc_mflr (code, ppc_r0);
3106 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3109 alloc_size = cfg->stack_offset;
3112 if (!method->save_lmf) {
3113 /*for (i = 31; i >= 14; --i) {
3114 if (cfg->used_float_regs & (1 << i)) {
3115 pos += sizeof (gdouble);
3116 ppc_stfd (code, i, -pos, ppc_sp);
3119 for (i = 31; i >= 13; --i) {
3120 if (cfg->used_int_regs & (1 << i)) {
3121 pos += sizeof (gulong);
3122 ppc_stw (code, i, -pos, ppc_sp);
3127 pos += sizeof (MonoLMF);
3129 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3130 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3131 for (i = 14; i < 32; i++) {
3132 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3136 // align to PPC_STACK_ALIGNMENT bytes
3137 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3138 alloc_size += PPC_STACK_ALIGNMENT - 1;
3139 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3142 cfg->stack_usage = alloc_size;
3143 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3145 if (ppc_is_imm16 (-alloc_size)) {
3146 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3148 ppc_load (code, ppc_r11, -alloc_size);
3149 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3152 if (cfg->frame_reg != ppc_sp)
3153 ppc_mr (code, cfg->frame_reg, ppc_sp);
3155 /* compute max_offset in order to use short forward jumps
3156 * we always do it on ppc because the immediate displacement
3157 * for jumps is too small
3160 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3161 MonoInst *ins = bb->code;
3162 bb->max_offset = max_offset;
3164 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3168 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3173 /* load arguments allocated to register from the stack */
3176 cinfo = calculate_sizes (sig, sig->pinvoke);
3178 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3179 ArgInfo *ainfo = &cinfo->ret;
3181 if (ppc_is_imm16 (inst->inst_offset)) {
3182 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3184 ppc_load (code, ppc_r11, inst->inst_offset);
3185 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3188 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3189 ArgInfo *ainfo = cinfo->args + i;
3190 inst = cfg->varinfo [pos];
3192 if (cfg->verbose_level > 2)
3193 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3194 if (inst->opcode == OP_REGVAR) {
3195 if (ainfo->regtype == RegTypeGeneral)
3196 ppc_mr (code, inst->dreg, ainfo->reg);
3197 else if (ainfo->regtype == RegTypeFP)
3198 ppc_fmr (code, inst->dreg, ainfo->reg);
3199 else if (ainfo->regtype == RegTypeBase) {
3200 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3201 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3203 g_assert_not_reached ();
3205 if (cfg->verbose_level > 2)
3206 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3208 /* the argument should be put on the stack: FIXME handle size != word */
3209 if (ainfo->regtype == RegTypeGeneral) {
3210 switch (ainfo->size) {
3212 if (ppc_is_imm16 (inst->inst_offset)) {
3213 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3215 ppc_load (code, ppc_r11, inst->inst_offset);
3216 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3220 if (ppc_is_imm16 (inst->inst_offset)) {
3221 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3223 ppc_load (code, ppc_r11, inst->inst_offset);
3224 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3228 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3229 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3230 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3232 ppc_load (code, ppc_r11, inst->inst_offset);
3233 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3234 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3235 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3239 if (ppc_is_imm16 (inst->inst_offset)) {
3240 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3242 ppc_load (code, ppc_r11, inst->inst_offset);
3243 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3247 } else if (ainfo->regtype == RegTypeBase) {
3248 /* load the previous stack pointer in r11 */
3249 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3250 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3251 switch (ainfo->size) {
3253 if (ppc_is_imm16 (inst->inst_offset)) {
3254 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3256 ppc_load (code, ppc_r11, inst->inst_offset);
3257 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3261 if (ppc_is_imm16 (inst->inst_offset)) {
3262 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3264 ppc_load (code, ppc_r11, inst->inst_offset);
3265 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3269 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3270 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3271 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3272 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3275 g_assert_not_reached ();
3279 if (ppc_is_imm16 (inst->inst_offset)) {
3280 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3282 ppc_load (code, ppc_r11, inst->inst_offset);
3283 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3287 } else if (ainfo->regtype == RegTypeFP) {
3288 g_assert (ppc_is_imm16 (inst->inst_offset));
3289 if (ainfo->size == 8)
3290 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3291 else if (ainfo->size == 4)
3292 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3294 g_assert_not_reached ();
3295 } else if (ainfo->regtype == RegTypeStructByVal) {
3296 int doffset = inst->inst_offset;
3300 g_assert (ppc_is_imm16 (inst->inst_offset));
3301 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3302 if (mono_class_from_mono_type (inst->inst_vtype))
3303 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3304 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3306 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3307 register. Should this case include linux/ppc?
3311 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3313 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3316 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3317 soffset += sizeof (gpointer);
3318 doffset += sizeof (gpointer);
3320 if (ainfo->vtsize) {
3321 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3322 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3323 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3324 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3326 } else if (ainfo->regtype == RegTypeStructByAddr) {
3327 g_assert (ppc_is_imm16 (inst->inst_offset));
3328 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3329 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3331 g_assert_not_reached ();
3336 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3337 ppc_load (code, ppc_r3, cfg->domain);
3338 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3342 if (method->save_lmf) {
3343 if (lmf_pthread_key != -1) {
3344 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3345 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3346 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3348 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3349 (gpointer)"mono_get_lmf_addr");
3350 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3351 ppc_lis (code, ppc_r0, 0);
3352 ppc_ori (code, ppc_r0, ppc_r0, 0);
3353 ppc_mtlr (code, ppc_r0);
3359 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3360 /* lmf_offset is the offset from the previous stack pointer,
3361 * alloc_size is the total stack space allocated, so the offset
3362 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3363 * The pointer to the struct is put in ppc_r11 (new_lmf).
3364 * The callee-saved registers are already in the MonoLMF structure
3366 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3367 /* ppc_r3 is the result from mono_get_lmf_addr () */
3368 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3369 /* new_lmf->previous_lmf = *lmf_addr */
3370 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3371 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3372 /* *(lmf_addr) = r11 */
3373 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3374 /* save method info */
3375 ppc_load (code, ppc_r0, method);
3376 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3377 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3378 /* save the current IP */
3379 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3380 ppc_load (code, ppc_r0, 0x01010101);
3381 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3385 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3387 cfg->code_len = code - cfg->native_code;
3388 g_assert (cfg->code_len < cfg->code_size);
3395 mono_arch_emit_epilog (MonoCompile *cfg)
3397 MonoJumpInfo *patch_info;
3398 MonoMethod *method = cfg->method;
3400 int max_epilog_size = 16 + 20*4;
3403 if (cfg->method->save_lmf)
3404 max_epilog_size += 128;
3406 if (mono_jit_trace_calls != NULL)
3407 max_epilog_size += 50;
3409 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3410 max_epilog_size += 50;
3412 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3413 cfg->code_size *= 2;
3414 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3415 mono_jit_stats.code_reallocs++;
3419 * Keep in sync with CEE_JMP
3421 code = cfg->native_code + cfg->code_len;
3423 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3424 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3428 if (method->save_lmf) {
3430 pos += sizeof (MonoLMF);
3432 /* save the frame reg in r8 */
3433 ppc_mr (code, ppc_r8, cfg->frame_reg);
3434 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3435 /* r5 = previous_lmf */
3436 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3438 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3439 /* *(lmf_addr) = previous_lmf */
3440 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3441 /* FIXME: speedup: there is no actual need to restore the registers if
3442 * we didn't actually change them (idea from Zoltan).
3445 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3447 /*for (i = 14; i < 32; i++) {
3448 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3450 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3451 /* use the saved copy of the frame reg in r8 */
3452 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3453 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3454 ppc_mtlr (code, ppc_r0);
3456 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3458 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3459 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3460 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3462 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3463 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3465 ppc_mtlr (code, ppc_r0);
3467 if (ppc_is_imm16 (cfg->stack_usage)) {
3468 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3470 ppc_load (code, ppc_r11, cfg->stack_usage);
3471 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3474 /*for (i = 31; i >= 14; --i) {
3475 if (cfg->used_float_regs & (1 << i)) {
3476 pos += sizeof (double);
3477 ppc_lfd (code, i, -pos, ppc_sp);
3480 for (i = 31; i >= 13; --i) {
3481 if (cfg->used_int_regs & (1 << i)) {
3482 pos += sizeof (gulong);
3483 ppc_lwz (code, i, -pos, ppc_sp);
3489 cfg->code_len = code - cfg->native_code;
3491 g_assert (cfg->code_len < cfg->code_size);
3495 /* remove once throw_exception_by_name is eliminated */
3497 exception_id_by_name (const char *name)
3499 if (strcmp (name, "IndexOutOfRangeException") == 0)
3500 return MONO_EXC_INDEX_OUT_OF_RANGE;
3501 if (strcmp (name, "OverflowException") == 0)
3502 return MONO_EXC_OVERFLOW;
3503 if (strcmp (name, "ArithmeticException") == 0)
3504 return MONO_EXC_ARITHMETIC;
3505 if (strcmp (name, "DivideByZeroException") == 0)
3506 return MONO_EXC_DIVIDE_BY_ZERO;
3507 if (strcmp (name, "InvalidCastException") == 0)
3508 return MONO_EXC_INVALID_CAST;
3509 if (strcmp (name, "NullReferenceException") == 0)
3510 return MONO_EXC_NULL_REF;
3511 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3512 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3513 g_error ("Unknown intrinsic exception %s\n", name);
3518 mono_arch_emit_exceptions (MonoCompile *cfg)
3520 MonoJumpInfo *patch_info;
3523 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3524 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3527 int max_epilog_size = 50;
3529 /* count the number of exception infos */
3532 * make sure we have enough space for exceptions
3533 * 24 is the simulated call to throw_exception_by_name
3535 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3536 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3537 i = exception_id_by_name (patch_info->data.target);
3538 if (!exc_throw_found [i]) {
3539 max_epilog_size += 12;
3540 exc_throw_found [i] = TRUE;
3542 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3543 max_epilog_size += 12;
3544 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3545 MonoOvfJump *ovfj = patch_info->data.target;
3546 i = exception_id_by_name (ovfj->data.exception);
3547 if (!exc_throw_found [i]) {
3548 max_epilog_size += 12;
3549 exc_throw_found [i] = TRUE;
3551 max_epilog_size += 8;
3555 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3556 cfg->code_size *= 2;
3557 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3558 mono_jit_stats.code_reallocs++;
3561 code = cfg->native_code + cfg->code_len;
3563 /* add code to raise exceptions */
3564 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3565 switch (patch_info->type) {
3566 case MONO_PATCH_INFO_BB_OVF: {
3567 MonoOvfJump *ovfj = patch_info->data.target;
3568 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3569 /* patch the initial jump */
3570 ppc_patch (ip, code);
3571 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3573 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3574 /* jump back to the true target */
3576 ip = ovfj->data.bb->native_offset + cfg->native_code;
3577 ppc_patch (code - 4, ip);
3580 case MONO_PATCH_INFO_EXC_OVF: {
3581 MonoOvfJump *ovfj = patch_info->data.target;
3582 MonoJumpInfo *newji;
3583 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3584 unsigned char *bcl = code;
3585 /* patch the initial jump: we arrived here with a call */
3586 ppc_patch (ip, code);
3587 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3589 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3590 /* patch the conditional jump to the right handler */
3591 /* make it processed next */
3592 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3593 newji->type = MONO_PATCH_INFO_EXC;
3594 newji->ip.i = bcl - cfg->native_code;
3595 newji->data.target = ovfj->data.exception;
3596 newji->next = patch_info->next;
3597 patch_info->next = newji;
3600 case MONO_PATCH_INFO_EXC: {
3601 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3602 i = exception_id_by_name (patch_info->data.target);
3603 if (exc_throw_pos [i]) {
3604 ppc_patch (ip, exc_throw_pos [i]);
3605 patch_info->type = MONO_PATCH_INFO_NONE;
3608 exc_throw_pos [i] = code;
3610 ppc_patch (ip, code);
3611 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3612 ppc_load (code, ppc_r3, patch_info->data.target);
3613 /* we got here from a conditional call, so the calling ip is set in lr already */
3614 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3615 patch_info->data.name = "mono_arch_throw_exception_by_name";
3616 patch_info->ip.i = code - cfg->native_code;
3626 cfg->code_len = code - cfg->native_code;
3628 g_assert (cfg->code_len < cfg->code_size);
3633 try_offset_access (void *value, guint32 idx)
3635 register void* me __asm__ ("r2");
3636 void ***p = (void***)((char*)me + 284);
3637 int idx1 = idx / 32;
3638 int idx2 = idx % 32;
3641 if (value != p[idx1][idx2])
3647 setup_tls_access (void)
3650 guint32 *ins, *code;
3651 guint32 cmplwi_1023, li_0x48, blr_ins;
3652 if (tls_mode == TLS_MODE_FAILED)
3655 if (g_getenv ("MONO_NO_TLS")) {
3656 tls_mode = TLS_MODE_FAILED;
3660 if (tls_mode == TLS_MODE_DETECT) {
3661 ins = (guint32*)pthread_getspecific;
3662 /* uncond branch to the real method */
3663 if ((*ins >> 26) == 18) {
3665 val = (*ins & ~3) << 6;
3669 ins = (guint32*)val;
3671 ins = (guint32*) ((char*)ins + val);
3674 code = &cmplwi_1023;
3675 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3677 ppc_li (code, ppc_r4, 0x48);
3680 if (*ins == cmplwi_1023) {
3681 int found_lwz_284 = 0;
3682 for (ptk = 0; ptk < 20; ++ptk) {
3684 if (!*ins || *ins == blr_ins)
3686 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3691 if (!found_lwz_284) {
3692 tls_mode = TLS_MODE_FAILED;
3695 tls_mode = TLS_MODE_LTHREADS;
3696 } else if (*ins == li_0x48) {
3698 /* uncond branch to the real method */
3699 if ((*ins >> 26) == 18) {
3701 val = (*ins & ~3) << 6;
3705 ins = (guint32*)val;
3707 ins = (guint32*) ((char*)ins + val);
3710 ppc_li (code, ppc_r0, 0x7FF2);
3711 if (ins [1] == val) {
3712 /* Darwin on G4, implement */
3713 tls_mode = TLS_MODE_FAILED;
3717 ppc_mfspr (code, ppc_r3, 104);
3718 if (ins [1] != val) {
3719 tls_mode = TLS_MODE_FAILED;
3722 tls_mode = TLS_MODE_DARWIN_G5;
3725 tls_mode = TLS_MODE_FAILED;
3729 tls_mode = TLS_MODE_FAILED;
3733 if (monodomain_key == -1) {
3734 ptk = mono_domain_get_tls_key ();
3736 ptk = mono_pthread_key_for_tls (ptk);
3738 monodomain_key = ptk;
3742 if (lmf_pthread_key == -1) {
3743 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3745 /*g_print ("MonoLMF at: %d\n", ptk);*/
3746 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3747 init_tls_failed = 1;
3750 lmf_pthread_key = ptk;
3753 if (monothread_key == -1) {
3754 ptk = mono_thread_get_tls_key ();
3756 ptk = mono_pthread_key_for_tls (ptk);
3758 monothread_key = ptk;
3759 /*g_print ("thread inited: %d\n", ptk);*/
3762 /*g_print ("thread not inited yet %d\n", ptk);*/
3768 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3770 setup_tls_access ();
3774 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3779 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3781 int this_dreg = ppc_r3;
3786 /* add the this argument */
3787 if (this_reg != -1) {
3789 MONO_INST_NEW (cfg, this, OP_SETREG);
3790 this->type = this_type;
3791 this->sreg1 = this_reg;
3792 this->dreg = mono_regstate_next_int (cfg->rs);
3793 mono_bblock_add_inst (cfg->cbb, this);
3794 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3799 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3800 vtarg->type = STACK_MP;
3801 vtarg->sreg1 = vt_reg;
3802 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3803 mono_bblock_add_inst (cfg->cbb, vtarg);
3804 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3809 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3811 MonoInst *ins = NULL;
3813 if (cmethod->klass == mono_defaults.thread_class &&
3814 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3815 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3817 /*if (cmethod->klass == mono_defaults.math_class) {
3818 if (strcmp (cmethod->name, "Sqrt") == 0) {
3819 MONO_INST_NEW (cfg, ins, OP_SQRT);
3820 ins->inst_i0 = args [0];
3827 mono_arch_print_tree (MonoInst *tree, int arity)
3832 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3836 setup_tls_access ();
3837 if (monodomain_key == -1)
3840 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3841 ins->inst_offset = monodomain_key;
3846 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3850 setup_tls_access ();
3851 if (monothread_key == -1)
3854 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3855 ins->inst_offset = monothread_key;