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 guint32 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;
625 cinfo->args [n].vtsize = size;
630 case MONO_TYPE_TYPEDBYREF: {
631 int size = sizeof (MonoTypedRef);
632 /* keep in sync or merge with the valuetype case */
633 #if PPC_PASS_STRUCTS_BY_VALUE
635 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
636 cinfo->args [n].regtype = RegTypeStructByVal;
637 if (gr <= PPC_LAST_ARG_REG) {
638 int rest = PPC_LAST_ARG_REG - gr + 1;
639 int n_in_regs = rest >= nwords? nwords: rest;
640 cinfo->args [n].size = n_in_regs;
641 cinfo->args [n].vtsize = nwords - n_in_regs;
642 cinfo->args [n].reg = gr;
645 cinfo->args [n].size = 0;
646 cinfo->args [n].vtsize = nwords;
648 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
649 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
650 stack_size += nwords * sizeof (gpointer);
653 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
654 cinfo->args [n].regtype = RegTypeStructByAddr;
655 cinfo->args [n].vtsize = size;
662 cinfo->args [n].size = 8;
663 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
667 cinfo->args [n].size = 4;
669 /* It was 7, now it is 8 in LinuxPPC */
670 if (fr <= PPC_LAST_FPARG_REG) {
671 cinfo->args [n].regtype = RegTypeFP;
672 cinfo->args [n].reg = fr;
674 FP_ALSO_IN_REG (gr ++);
675 ALWAYS_ON_STACK (stack_size += 4);
677 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
678 cinfo->args [n].regtype = RegTypeBase;
679 cinfo->args [n].reg = ppc_sp; /* in the caller*/
685 cinfo->args [n].size = 8;
686 /* It was 7, now it is 8 in LinuxPPC */
687 if (fr <= PPC_LAST_FPARG_REG) {
688 cinfo->args [n].regtype = RegTypeFP;
689 cinfo->args [n].reg = fr;
691 FP_ALSO_IN_REG (gr += 2);
692 ALWAYS_ON_STACK (stack_size += 8);
694 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
695 cinfo->args [n].regtype = RegTypeBase;
696 cinfo->args [n].reg = ppc_sp; /* in the caller*/
702 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
707 simpletype = mono_type_get_underlying_type (sig->ret)->type;
708 switch (simpletype) {
709 case MONO_TYPE_BOOLEAN:
720 case MONO_TYPE_FNPTR:
721 case MONO_TYPE_CLASS:
722 case MONO_TYPE_OBJECT:
723 case MONO_TYPE_SZARRAY:
724 case MONO_TYPE_ARRAY:
725 case MONO_TYPE_STRING:
726 cinfo->ret.reg = ppc_r3;
730 cinfo->ret.reg = ppc_r3;
734 cinfo->ret.reg = ppc_f1;
735 cinfo->ret.regtype = RegTypeFP;
737 case MONO_TYPE_GENERICINST:
738 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
739 cinfo->ret.reg = ppc_r3;
743 case MONO_TYPE_VALUETYPE:
745 case MONO_TYPE_TYPEDBYREF:
749 g_error ("Can't handle as return value 0x%x", sig->ret->type);
753 /* align stack size to 16 */
754 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
755 stack_size = (stack_size + 15) & ~15;
757 cinfo->stack_usage = stack_size;
763 * Set var information according to the calling convention. ppc version.
764 * The locals var stuff should most likely be split in another method.
767 mono_arch_allocate_vars (MonoCompile *m)
769 MonoMethodSignature *sig;
770 MonoMethodHeader *header;
772 int i, offset, size, align, curinst;
773 int frame_reg = ppc_sp;
775 m->flags |= MONO_CFG_HAS_SPILLUP;
777 /* allow room for the vararg method args: void* and long/double */
778 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
779 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
780 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
781 * call convs needs to be handled this way.
783 if (m->flags & MONO_CFG_HAS_VARARGS)
784 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
785 /* gtk-sharp and other broken code will dllimport vararg functions even with
786 * non-varargs signatures. Since there is little hope people will get this right
787 * we assume they won't.
789 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
790 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
792 header = mono_method_get_header (m->method);
795 * We use the frame register also for any method that has
796 * exception clauses. This way, when the handlers are called,
797 * the code will reference local variables using the frame reg instead of
798 * the stack pointer: if we had to restore the stack pointer, we'd
799 * corrupt the method frames that are already on the stack (since
800 * filters get called before stack unwinding happens) when the filter
801 * code would call any method (this also applies to finally etc.).
803 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
805 m->frame_reg = frame_reg;
806 if (frame_reg != ppc_sp) {
807 m->used_int_regs |= 1 << frame_reg;
810 sig = mono_method_signature (m->method);
814 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
815 m->ret->opcode = OP_REGVAR;
816 m->ret->inst_c0 = ppc_r3;
818 /* FIXME: handle long and FP values */
819 switch (mono_type_get_underlying_type (sig->ret)->type) {
823 m->ret->opcode = OP_REGVAR;
824 m->ret->inst_c0 = ppc_r3;
828 /* local vars are at a positive offset from the stack pointer */
830 * also note that if the function uses alloca, we use ppc_r31
831 * to point at the local variables.
833 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
834 /* align the offset to 16 bytes: not sure this is needed here */
836 //offset &= ~(16 - 1);
838 /* add parameter area size for called functions */
839 offset += m->param_area;
843 /* allow room to save the return value */
844 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
847 /* the MonoLMF structure is stored just below the stack pointer */
850 /* this stuff should not be needed on ppc and the new jit,
851 * because a call on ppc to the handlers doesn't change the
852 * stack pointer and the jist doesn't manipulate the stack pointer
853 * for operations involving valuetypes.
855 /* reserve space to store the esp */
856 offset += sizeof (gpointer);
858 /* this is a global constant */
859 mono_exc_esp_offset = offset;
861 if (sig->call_convention == MONO_CALL_VARARG) {
862 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
865 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
867 offset += sizeof(gpointer) - 1;
868 offset &= ~(sizeof(gpointer) - 1);
869 inst->inst_offset = offset;
870 inst->opcode = OP_REGOFFSET;
871 inst->inst_basereg = frame_reg;
872 offset += sizeof(gpointer);
873 if (sig->call_convention == MONO_CALL_VARARG)
874 m->sig_cookie += sizeof (gpointer);
877 curinst = m->locals_start;
878 for (i = curinst; i < m->num_varinfo; ++i) {
879 inst = m->varinfo [i];
880 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
883 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
884 * pinvoke wrappers when they call functions returning structure */
885 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
886 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
888 size = mono_type_size (inst->inst_vtype, &align);
891 offset &= ~(align - 1);
892 inst->inst_offset = offset;
893 inst->opcode = OP_REGOFFSET;
894 inst->inst_basereg = frame_reg;
896 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
901 inst = m->args [curinst];
902 if (inst->opcode != OP_REGVAR) {
903 inst->opcode = OP_REGOFFSET;
904 inst->inst_basereg = frame_reg;
905 offset += sizeof (gpointer) - 1;
906 offset &= ~(sizeof (gpointer) - 1);
907 inst->inst_offset = offset;
908 offset += sizeof (gpointer);
909 if (sig->call_convention == MONO_CALL_VARARG)
910 m->sig_cookie += sizeof (gpointer);
915 for (i = 0; i < sig->param_count; ++i) {
916 inst = m->args [curinst];
917 if (inst->opcode != OP_REGVAR) {
918 inst->opcode = OP_REGOFFSET;
919 inst->inst_basereg = frame_reg;
920 size = mono_type_size (sig->params [i], &align);
922 offset &= ~(align - 1);
923 inst->inst_offset = offset;
925 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
926 m->sig_cookie += size;
931 /* align the offset to 16 bytes */
936 m->stack_offset = offset;
940 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
941 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
945 * take the arguments and generate the arch-specific
946 * instructions to properly call the function in call.
947 * This includes pushing, moving arguments to the right register
949 * Issue: who does the spilling if needed, and when?
952 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
954 MonoMethodSignature *sig;
959 sig = call->signature;
960 n = sig->param_count + sig->hasthis;
962 cinfo = calculate_sizes (sig, sig->pinvoke);
963 if (cinfo->struct_ret)
964 call->used_iregs |= 1 << cinfo->struct_ret;
966 for (i = 0; i < n; ++i) {
967 ainfo = cinfo->args + i;
968 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
970 cfg->disable_aot = TRUE;
972 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
973 sig_arg->inst_p0 = call->signature;
975 MONO_INST_NEW (cfg, arg, OP_OUTARG);
976 arg->inst_imm = cinfo->sig_cookie.offset;
977 arg->inst_left = sig_arg;
979 /* prepend, so they get reversed */
980 arg->next = call->out_args;
981 call->out_args = arg;
983 if (is_virtual && i == 0) {
984 /* the argument will be attached to the call instrucion */
986 call->used_iregs |= 1 << ainfo->reg;
988 MONO_INST_NEW (cfg, arg, OP_OUTARG);
990 arg->cil_code = in->cil_code;
992 arg->inst_call = call;
993 arg->type = in->type;
994 /* prepend, we'll need to reverse them later */
995 arg->next = call->out_args;
996 call->out_args = arg;
997 if (ainfo->regtype == RegTypeGeneral) {
998 arg->backend.reg3 = ainfo->reg;
999 call->used_iregs |= 1 << ainfo->reg;
1000 if (arg->type == STACK_I8)
1001 call->used_iregs |= 1 << (ainfo->reg + 1);
1002 } else if (ainfo->regtype == RegTypeStructByAddr) {
1003 if (ainfo->offset) {
1004 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1005 arg->opcode = OP_OUTARG_MEMBASE;
1006 ai->reg = ainfo->reg;
1007 ai->size = sizeof (gpointer);
1008 ai->offset = ainfo->offset;
1009 arg->backend.data = ai;
1011 arg->backend.reg3 = ainfo->reg;
1012 call->used_iregs |= 1 << ainfo->reg;
1014 } else if (ainfo->regtype == RegTypeStructByVal) {
1016 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1017 /* mark the used regs */
1018 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1019 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1021 arg->opcode = OP_OUTARG_VT;
1022 ai->reg = ainfo->reg;
1023 ai->size = ainfo->size;
1024 ai->vtsize = ainfo->vtsize;
1025 ai->offset = ainfo->offset;
1026 arg->backend.data = ai;
1027 } else if (ainfo->regtype == RegTypeBase) {
1028 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1029 arg->opcode = OP_OUTARG_MEMBASE;
1030 ai->reg = ainfo->reg;
1031 ai->size = ainfo->size;
1032 ai->offset = ainfo->offset;
1033 arg->backend.data = ai;
1034 } else if (ainfo->regtype == RegTypeFP) {
1035 arg->opcode = OP_OUTARG_R8;
1036 arg->backend.reg3 = ainfo->reg;
1037 call->used_fregs |= 1 << ainfo->reg;
1038 if (ainfo->size == 4) {
1039 arg->opcode = OP_OUTARG_R8;
1040 /* we reduce the precision */
1042 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1043 conv->inst_left = arg->inst_left;
1044 arg->inst_left = conv;*/
1047 g_assert_not_reached ();
1052 * Reverse the call->out_args list.
1055 MonoInst *prev = NULL, *list = call->out_args, *next;
1062 call->out_args = prev;
1064 call->stack_usage = cinfo->stack_usage;
1065 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1066 cfg->flags |= MONO_CFG_HAS_CALLS;
1068 * should set more info in call, such as the stack space
1069 * used by the args that needs to be added back to esp
1077 * Allow tracing to work with this interface (with an optional argument)
1081 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1085 ppc_load (code, ppc_r3, cfg->method);
1086 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1087 ppc_load (code, ppc_r0, func);
1088 ppc_mtlr (code, ppc_r0);
1102 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1105 int save_mode = SAVE_NONE;
1107 MonoMethod *method = cfg->method;
1108 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1109 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1113 offset = code - cfg->native_code;
1114 /* we need about 16 instructions */
1115 if (offset > (cfg->code_size - 16 * 4)) {
1116 cfg->code_size *= 2;
1117 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1118 code = cfg->native_code + offset;
1122 case MONO_TYPE_VOID:
1123 /* special case string .ctor icall */
1124 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1125 save_mode = SAVE_ONE;
1127 save_mode = SAVE_NONE;
1131 save_mode = SAVE_TWO;
1135 save_mode = SAVE_FP;
1137 case MONO_TYPE_VALUETYPE:
1138 save_mode = SAVE_STRUCT;
1141 save_mode = SAVE_ONE;
1145 switch (save_mode) {
1147 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1148 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1149 if (enable_arguments) {
1150 ppc_mr (code, ppc_r5, ppc_r4);
1151 ppc_mr (code, ppc_r4, ppc_r3);
1155 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1156 if (enable_arguments) {
1157 ppc_mr (code, ppc_r4, ppc_r3);
1161 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1162 if (enable_arguments) {
1163 /* FIXME: what reg? */
1164 ppc_fmr (code, ppc_f3, ppc_f1);
1165 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1166 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1170 if (enable_arguments) {
1171 /* FIXME: get the actual address */
1172 ppc_mr (code, ppc_r4, ppc_r3);
1180 ppc_load (code, ppc_r3, cfg->method);
1181 ppc_load (code, ppc_r0, func);
1182 ppc_mtlr (code, ppc_r0);
1185 switch (save_mode) {
1187 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1188 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1191 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1194 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1204 * Conditional branches have a small offset, so if it is likely overflowed,
1205 * we do a branch to the end of the method (uncond branches have much larger
1206 * offsets) where we perform the conditional and jump back unconditionally.
1207 * It's slightly slower, since we add two uncond branches, but it's very simple
1208 * with the current patch implementation and such large methods are likely not
1209 * going to be perf critical anyway.
1214 const char *exception;
1221 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1222 if (ins->flags & MONO_INST_BRLABEL) { \
1223 if (0 && ins->inst_i0->inst_c0) { \
1224 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1226 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1227 ppc_bc (code, (b0), (b1), 0); \
1230 if (0 && ins->inst_true_bb->native_offset) { \
1231 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1233 int br_disp = ins->inst_true_bb->max_offset - offset; \
1234 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1235 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1236 ovfj->data.bb = ins->inst_true_bb; \
1237 ovfj->ip_offset = 0; \
1238 ovfj->b0_cond = (b0); \
1239 ovfj->b1_cond = (b1); \
1240 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1243 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1244 ppc_bc (code, (b0), (b1), 0); \
1249 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1251 /* emit an exception if condition is fail
1253 * We assign the extra code used to throw the implicit exceptions
1254 * to cfg->bb_exit as far as the big branch handling is concerned
1256 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1258 int br_disp = cfg->bb_exit->max_offset - offset; \
1259 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1260 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1261 ovfj->data.exception = (exc_name); \
1262 ovfj->ip_offset = code - cfg->native_code; \
1263 ovfj->b0_cond = (b0); \
1264 ovfj->b1_cond = (b1); \
1265 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1267 cfg->bb_exit->max_offset += 24; \
1269 mono_add_patch_info (cfg, code - cfg->native_code, \
1270 MONO_PATCH_INFO_EXC, exc_name); \
1271 ppc_bcl (code, (b0), (b1), 0); \
1275 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1278 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1280 MonoInst *ins, *last_ins = NULL;
1285 switch (ins->opcode) {
1287 /* remove unnecessary multiplication with 1 */
1288 if (ins->inst_imm == 1) {
1289 if (ins->dreg != ins->sreg1) {
1290 ins->opcode = OP_MOVE;
1292 last_ins->next = ins->next;
1297 int power2 = mono_is_power_of_two (ins->inst_imm);
1299 ins->opcode = OP_SHL_IMM;
1300 ins->inst_imm = power2;
1304 case OP_LOAD_MEMBASE:
1305 case OP_LOADI4_MEMBASE:
1307 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1308 * OP_LOAD_MEMBASE offset(basereg), reg
1310 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1311 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1312 ins->inst_basereg == last_ins->inst_destbasereg &&
1313 ins->inst_offset == last_ins->inst_offset) {
1314 if (ins->dreg == last_ins->sreg1) {
1315 last_ins->next = ins->next;
1319 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1320 ins->opcode = OP_MOVE;
1321 ins->sreg1 = last_ins->sreg1;
1325 * Note: reg1 must be different from the basereg in the second load
1326 * OP_LOAD_MEMBASE offset(basereg), reg1
1327 * OP_LOAD_MEMBASE offset(basereg), reg2
1329 * OP_LOAD_MEMBASE offset(basereg), reg1
1330 * OP_MOVE reg1, reg2
1332 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1333 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1334 ins->inst_basereg != last_ins->dreg &&
1335 ins->inst_basereg == last_ins->inst_basereg &&
1336 ins->inst_offset == last_ins->inst_offset) {
1338 if (ins->dreg == last_ins->dreg) {
1339 last_ins->next = ins->next;
1343 ins->opcode = OP_MOVE;
1344 ins->sreg1 = last_ins->dreg;
1347 //g_assert_not_reached ();
1351 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1352 * OP_LOAD_MEMBASE offset(basereg), reg
1354 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1355 * OP_ICONST reg, imm
1357 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1358 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1359 ins->inst_basereg == last_ins->inst_destbasereg &&
1360 ins->inst_offset == last_ins->inst_offset) {
1361 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1362 ins->opcode = OP_ICONST;
1363 ins->inst_c0 = last_ins->inst_imm;
1364 g_assert_not_reached (); // check this rule
1368 case OP_LOADU1_MEMBASE:
1369 case OP_LOADI1_MEMBASE:
1370 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1371 ins->inst_basereg == last_ins->inst_destbasereg &&
1372 ins->inst_offset == last_ins->inst_offset) {
1373 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1374 ins->sreg1 = last_ins->sreg1;
1377 case OP_LOADU2_MEMBASE:
1378 case OP_LOADI2_MEMBASE:
1379 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1380 ins->inst_basereg == last_ins->inst_destbasereg &&
1381 ins->inst_offset == last_ins->inst_offset) {
1382 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1383 ins->sreg1 = last_ins->sreg1;
1390 ins->opcode = OP_MOVE;
1394 if (ins->dreg == ins->sreg1) {
1396 last_ins->next = ins->next;
1401 * OP_MOVE sreg, dreg
1402 * OP_MOVE dreg, sreg
1404 if (last_ins && last_ins->opcode == OP_MOVE &&
1405 ins->sreg1 == last_ins->dreg &&
1406 ins->dreg == last_ins->sreg1) {
1407 last_ins->next = ins->next;
1416 bb->last_ins = last_ins;
1420 * the branch_b0_table should maintain the order of these
1434 branch_b0_table [] = {
1449 branch_b1_table [] = {
1464 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1468 bb->code = to_insert;
1469 to_insert->next = ins;
1471 to_insert->next = ins->next;
1472 ins->next = to_insert;
1476 #define NEW_INS(cfg,dest,op) do { \
1477 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1478 (dest)->opcode = (op); \
1479 insert_after_ins (bb, last_ins, (dest)); \
1483 map_to_reg_reg_op (int op)
1492 case OP_COMPARE_IMM:
1508 case OP_LOAD_MEMBASE:
1509 return OP_LOAD_MEMINDEX;
1510 case OP_LOADI4_MEMBASE:
1511 return OP_LOADI4_MEMINDEX;
1512 case OP_LOADU4_MEMBASE:
1513 return OP_LOADU4_MEMINDEX;
1514 case OP_LOADU1_MEMBASE:
1515 return OP_LOADU1_MEMINDEX;
1516 case OP_LOADI2_MEMBASE:
1517 return OP_LOADI2_MEMINDEX;
1518 case OP_LOADU2_MEMBASE:
1519 return OP_LOADU2_MEMINDEX;
1520 case OP_LOADI1_MEMBASE:
1521 return OP_LOADI1_MEMINDEX;
1522 case OP_LOADR4_MEMBASE:
1523 return OP_LOADR4_MEMINDEX;
1524 case OP_LOADR8_MEMBASE:
1525 return OP_LOADR8_MEMINDEX;
1526 case OP_STOREI1_MEMBASE_REG:
1527 return OP_STOREI1_MEMINDEX;
1528 case OP_STOREI2_MEMBASE_REG:
1529 return OP_STOREI2_MEMINDEX;
1530 case OP_STOREI4_MEMBASE_REG:
1531 return OP_STOREI4_MEMINDEX;
1532 case OP_STORE_MEMBASE_REG:
1533 return OP_STORE_MEMINDEX;
1534 case OP_STORER4_MEMBASE_REG:
1535 return OP_STORER4_MEMINDEX;
1536 case OP_STORER8_MEMBASE_REG:
1537 return OP_STORER8_MEMINDEX;
1538 case OP_STORE_MEMBASE_IMM:
1539 return OP_STORE_MEMBASE_REG;
1540 case OP_STOREI1_MEMBASE_IMM:
1541 return OP_STOREI1_MEMBASE_REG;
1542 case OP_STOREI2_MEMBASE_IMM:
1543 return OP_STOREI2_MEMBASE_REG;
1544 case OP_STOREI4_MEMBASE_IMM:
1545 return OP_STOREI4_MEMBASE_REG;
1547 g_assert_not_reached ();
1550 #define compare_opcode_is_unsigned(opcode) \
1551 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1552 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1553 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1555 * Remove from the instruction list the instructions that can't be
1556 * represented with very simple instructions with no register
1560 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1562 MonoInst *ins, *next, *temp, *last_ins = NULL;
1565 /* setup the virtual reg allocator */
1566 if (bb->max_vreg > cfg->rs->next_vreg)
1567 cfg->rs->next_vreg = bb->max_vreg;
1572 switch (ins->opcode) {
1575 if (!ppc_is_imm16 (ins->inst_imm)) {
1576 NEW_INS (cfg, temp, OP_ICONST);
1577 temp->inst_c0 = ins->inst_imm;
1578 temp->dreg = mono_regstate_next_int (cfg->rs);
1579 ins->sreg2 = temp->dreg;
1580 ins->opcode = map_to_reg_reg_op (ins->opcode);
1584 if (!ppc_is_imm16 (-ins->inst_imm)) {
1585 NEW_INS (cfg, temp, OP_ICONST);
1586 temp->inst_c0 = ins->inst_imm;
1587 temp->dreg = mono_regstate_next_int (cfg->rs);
1588 ins->sreg2 = temp->dreg;
1589 ins->opcode = map_to_reg_reg_op (ins->opcode);
1595 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1596 NEW_INS (cfg, temp, OP_ICONST);
1597 temp->inst_c0 = ins->inst_imm;
1598 temp->dreg = mono_regstate_next_int (cfg->rs);
1599 ins->sreg2 = temp->dreg;
1600 ins->opcode = map_to_reg_reg_op (ins->opcode);
1606 NEW_INS (cfg, temp, OP_ICONST);
1607 temp->inst_c0 = ins->inst_imm;
1608 temp->dreg = mono_regstate_next_int (cfg->rs);
1609 ins->sreg2 = temp->dreg;
1610 ins->opcode = map_to_reg_reg_op (ins->opcode);
1612 case OP_COMPARE_IMM:
1613 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1614 if (!ppc_is_uimm16 (ins->inst_imm)) {
1615 NEW_INS (cfg, temp, OP_ICONST);
1616 temp->inst_c0 = ins->inst_imm;
1617 temp->dreg = mono_regstate_next_int (cfg->rs);
1618 ins->sreg2 = temp->dreg;
1619 ins->opcode = map_to_reg_reg_op (ins->opcode);
1622 if (!ppc_is_imm16 (ins->inst_imm)) {
1623 NEW_INS (cfg, temp, OP_ICONST);
1624 temp->inst_c0 = ins->inst_imm;
1625 temp->dreg = mono_regstate_next_int (cfg->rs);
1626 ins->sreg2 = temp->dreg;
1627 ins->opcode = map_to_reg_reg_op (ins->opcode);
1632 if (ins->inst_imm == 1) {
1633 ins->opcode = OP_MOVE;
1636 if (ins->inst_imm == 0) {
1637 ins->opcode = OP_ICONST;
1641 imm = mono_is_power_of_two (ins->inst_imm);
1643 ins->opcode = OP_SHL_IMM;
1644 ins->inst_imm = imm;
1647 if (!ppc_is_imm16 (ins->inst_imm)) {
1648 NEW_INS (cfg, temp, OP_ICONST);
1649 temp->inst_c0 = ins->inst_imm;
1650 temp->dreg = mono_regstate_next_int (cfg->rs);
1651 ins->sreg2 = temp->dreg;
1652 ins->opcode = map_to_reg_reg_op (ins->opcode);
1655 case OP_LOAD_MEMBASE:
1656 case OP_LOADI4_MEMBASE:
1657 case OP_LOADU4_MEMBASE:
1658 case OP_LOADI2_MEMBASE:
1659 case OP_LOADU2_MEMBASE:
1660 case OP_LOADI1_MEMBASE:
1661 case OP_LOADU1_MEMBASE:
1662 case OP_LOADR4_MEMBASE:
1663 case OP_LOADR8_MEMBASE:
1664 case OP_STORE_MEMBASE_REG:
1665 case OP_STOREI4_MEMBASE_REG:
1666 case OP_STOREI2_MEMBASE_REG:
1667 case OP_STOREI1_MEMBASE_REG:
1668 case OP_STORER4_MEMBASE_REG:
1669 case OP_STORER8_MEMBASE_REG:
1670 /* we can do two things: load the immed in a register
1671 * and use an indexed load, or see if the immed can be
1672 * represented as an ad_imm + a load with a smaller offset
1673 * that fits. We just do the first for now, optimize later.
1675 if (ppc_is_imm16 (ins->inst_offset))
1677 NEW_INS (cfg, temp, OP_ICONST);
1678 temp->inst_c0 = ins->inst_offset;
1679 temp->dreg = mono_regstate_next_int (cfg->rs);
1680 ins->sreg2 = temp->dreg;
1681 ins->opcode = map_to_reg_reg_op (ins->opcode);
1683 case OP_STORE_MEMBASE_IMM:
1684 case OP_STOREI1_MEMBASE_IMM:
1685 case OP_STOREI2_MEMBASE_IMM:
1686 case OP_STOREI4_MEMBASE_IMM:
1687 NEW_INS (cfg, temp, OP_ICONST);
1688 temp->inst_c0 = ins->inst_imm;
1689 temp->dreg = mono_regstate_next_int (cfg->rs);
1690 ins->sreg1 = temp->dreg;
1691 ins->opcode = map_to_reg_reg_op (ins->opcode);
1693 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1698 bb->last_ins = last_ins;
1699 bb->max_vreg = cfg->rs->next_vreg;
1704 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1708 mono_arch_lowering_pass (cfg, bb);
1709 mono_local_regalloc (cfg, bb);
1713 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1715 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1716 ppc_fctiwz (code, ppc_f0, sreg);
1717 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1718 ppc_lwz (code, dreg, -4, ppc_sp);
1721 ppc_andid (code, dreg, dreg, 0xff);
1723 ppc_andid (code, dreg, dreg, 0xffff);
1726 ppc_extsb (code, dreg, dreg);
1728 ppc_extsh (code, dreg, dreg);
1733 static unsigned char*
1734 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1737 int sreg = tree->sreg1;
1738 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1739 if (tree->flags & MONO_INST_INIT) {
1741 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1742 x86_push_reg (code, X86_EAX);
1745 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1746 x86_push_reg (code, X86_ECX);
1749 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1750 x86_push_reg (code, X86_EDI);
1754 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1755 if (sreg != X86_ECX)
1756 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1757 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1759 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1761 x86_prefix (code, X86_REP_PREFIX);
1764 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1765 x86_pop_reg (code, X86_EDI);
1766 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1767 x86_pop_reg (code, X86_ECX);
1768 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1769 x86_pop_reg (code, X86_EAX);
1782 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1785 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1786 PatchData *pdata = (PatchData*)user_data;
1787 guchar *code = data;
1788 guint32 *thunks = data;
1789 guint32 *endthunks = (guint32*)(code + bsize);
1793 int difflow, diffhigh;
1795 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1796 difflow = (char*)pdata->code - (char*)thunks;
1797 diffhigh = (char*)pdata->code - (char*)endthunks;
1798 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1801 templ = (guchar*)load;
1802 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1803 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1805 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1806 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1807 while (thunks < endthunks) {
1808 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1809 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1810 ppc_patch (pdata->code, (guchar*)thunks);
1811 mono_arch_flush_icache (pdata->code, 4);
1814 static int num_thunks = 0;
1816 if ((num_thunks % 20) == 0)
1817 g_print ("num_thunks lookup: %d\n", num_thunks);
1820 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1821 /* found a free slot instead: emit thunk */
1822 code = (guchar*)thunks;
1823 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1824 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1825 ppc_mtctr (code, ppc_r0);
1826 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1827 mono_arch_flush_icache ((guchar*)thunks, 16);
1829 ppc_patch (pdata->code, (guchar*)thunks);
1830 mono_arch_flush_icache (pdata->code, 4);
1833 static int num_thunks = 0;
1835 if ((num_thunks % 20) == 0)
1836 g_print ("num_thunks: %d\n", num_thunks);
1840 /* skip 16 bytes, the size of the thunk */
1844 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1850 handle_thunk (int absolute, guchar *code, guchar *target) {
1851 MonoDomain *domain = mono_domain_get ();
1855 pdata.target = target;
1856 pdata.absolute = absolute;
1859 mono_domain_lock (domain);
1860 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1863 /* this uses the first available slot */
1865 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1867 mono_domain_unlock (domain);
1869 if (pdata.found != 1)
1870 g_print ("thunk failed for %p from %p\n", target, code);
1871 g_assert (pdata.found == 1);
1875 ppc_patch (guchar *code, guchar *target)
1877 guint32 ins = *(guint32*)code;
1878 guint32 prim = ins >> 26;
1881 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1883 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1884 gint diff = target - code;
1886 if (diff <= 33554431){
1887 ins = (18 << 26) | (diff) | (ins & 1);
1888 *(guint32*)code = ins;
1892 /* diff between 0 and -33554432 */
1893 if (diff >= -33554432){
1894 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1895 *(guint32*)code = ins;
1900 if ((glong)target >= 0){
1901 if ((glong)target <= 33554431){
1902 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1903 *(guint32*)code = ins;
1907 if ((glong)target >= -33554432){
1908 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1909 *(guint32*)code = ins;
1914 handle_thunk (TRUE, code, target);
1917 g_assert_not_reached ();
1924 guint32 li = (guint32)target;
1925 ins = (ins & 0xffff0000) | (ins & 3);
1926 ovf = li & 0xffff0000;
1927 if (ovf != 0 && ovf != 0xffff0000)
1928 g_assert_not_reached ();
1931 // FIXME: assert the top bits of li are 0
1933 gint diff = target - code;
1934 ins = (ins & 0xffff0000) | (ins & 3);
1935 ovf = diff & 0xffff0000;
1936 if (ovf != 0 && ovf != 0xffff0000)
1937 g_assert_not_reached ();
1941 *(guint32*)code = ins;
1945 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
1947 /* the trampoline code will try to patch the blrl, blr, bcctr */
1948 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
1951 /* this is the lis/ori/mtlr/blrl sequence */
1952 seq = (guint32*)code;
1953 g_assert ((seq [0] >> 26) == 15);
1954 g_assert ((seq [1] >> 26) == 24);
1955 g_assert ((seq [2] >> 26) == 31);
1956 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
1957 /* FIXME: make this thread safe */
1958 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
1959 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
1960 mono_arch_flush_icache (code - 8, 8);
1962 g_assert_not_reached ();
1964 // g_print ("patched with 0x%08x\n", ins);
1968 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1973 guint8 *code = cfg->native_code + cfg->code_len;
1974 MonoInst *last_ins = NULL;
1975 guint last_offset = 0;
1978 if (cfg->opt & MONO_OPT_PEEPHOLE)
1979 peephole_pass (cfg, bb);
1981 /* we don't align basic blocks of loops on ppc */
1983 if (cfg->verbose_level > 2)
1984 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1986 cpos = bb->max_offset;
1988 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1989 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1990 //g_assert (!mono_compile_aot);
1993 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1994 /* this is not thread save, but good enough */
1995 /* fixme: howto handle overflows? */
1996 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2001 offset = code - cfg->native_code;
2003 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2005 if (offset > (cfg->code_size - max_len - 16)) {
2006 cfg->code_size *= 2;
2007 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2008 code = cfg->native_code + offset;
2010 // if (ins->cil_code)
2011 // g_print ("cil code\n");
2012 mono_debug_record_line_number (cfg, ins, offset);
2014 switch (ins->opcode) {
2016 emit_tls_access (code, ins->dreg, ins->inst_offset);
2019 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2020 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2021 ppc_mr (code, ppc_r4, ppc_r0);
2024 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2025 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2026 ppc_mr (code, ppc_r4, ppc_r0);
2028 case OP_MEMORY_BARRIER:
2031 case OP_STOREI1_MEMBASE_REG:
2032 if (ppc_is_imm16 (ins->inst_offset)) {
2033 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2035 g_assert_not_reached ();
2038 case OP_STOREI2_MEMBASE_REG:
2039 if (ppc_is_imm16 (ins->inst_offset)) {
2040 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2042 g_assert_not_reached ();
2045 case OP_STORE_MEMBASE_REG:
2046 case OP_STOREI4_MEMBASE_REG:
2047 if (ppc_is_imm16 (ins->inst_offset)) {
2048 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2050 g_assert_not_reached ();
2053 case OP_STOREI1_MEMINDEX:
2054 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2056 case OP_STOREI2_MEMINDEX:
2057 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2059 case OP_STORE_MEMINDEX:
2060 case OP_STOREI4_MEMINDEX:
2061 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2066 g_assert_not_reached ();
2067 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2070 g_assert_not_reached ();
2072 case OP_LOAD_MEMBASE:
2073 case OP_LOADI4_MEMBASE:
2074 case OP_LOADU4_MEMBASE:
2075 if (ppc_is_imm16 (ins->inst_offset)) {
2076 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2078 g_assert_not_reached ();
2081 case OP_LOADI1_MEMBASE:
2082 case OP_LOADU1_MEMBASE:
2083 if (ppc_is_imm16 (ins->inst_offset)) {
2084 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2086 g_assert_not_reached ();
2088 if (ins->opcode == OP_LOADI1_MEMBASE)
2089 ppc_extsb (code, ins->dreg, ins->dreg);
2091 case OP_LOADU2_MEMBASE:
2092 if (ppc_is_imm16 (ins->inst_offset)) {
2093 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2095 g_assert_not_reached ();
2098 case OP_LOADI2_MEMBASE:
2099 if (ppc_is_imm16 (ins->inst_offset)) {
2100 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2102 g_assert_not_reached ();
2105 case OP_LOAD_MEMINDEX:
2106 case OP_LOADI4_MEMINDEX:
2107 case OP_LOADU4_MEMINDEX:
2108 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2110 case OP_LOADU2_MEMINDEX:
2111 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2113 case OP_LOADI2_MEMINDEX:
2114 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2116 case OP_LOADU1_MEMINDEX:
2117 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2119 case OP_LOADI1_MEMINDEX:
2120 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2121 ppc_extsb (code, ins->dreg, ins->dreg);
2124 ppc_extsb (code, ins->dreg, ins->sreg1);
2127 ppc_extsh (code, ins->dreg, ins->sreg1);
2130 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2133 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2136 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2137 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2139 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2141 case OP_COMPARE_IMM:
2142 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2143 if (ppc_is_uimm16 (ins->inst_imm)) {
2144 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2146 g_assert_not_reached ();
2149 if (ppc_is_imm16 (ins->inst_imm)) {
2150 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2152 g_assert_not_reached ();
2160 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2163 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2166 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2169 if (ppc_is_imm16 (ins->inst_imm)) {
2170 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2172 g_assert_not_reached ();
2176 if (ppc_is_imm16 (ins->inst_imm)) {
2177 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2179 g_assert_not_reached ();
2183 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2185 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2186 ppc_mfspr (code, ppc_r0, ppc_xer);
2187 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2188 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2190 case CEE_ADD_OVF_UN:
2191 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2193 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2194 ppc_mfspr (code, ppc_r0, ppc_xer);
2195 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2196 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2199 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2201 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2202 ppc_mfspr (code, ppc_r0, ppc_xer);
2203 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2204 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2206 case CEE_SUB_OVF_UN:
2207 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2209 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2210 ppc_mfspr (code, ppc_r0, ppc_xer);
2211 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2212 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2214 case OP_ADD_OVF_CARRY:
2215 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2217 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2218 ppc_mfspr (code, ppc_r0, ppc_xer);
2219 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2220 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2222 case OP_ADD_OVF_UN_CARRY:
2223 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2225 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2226 ppc_mfspr (code, ppc_r0, ppc_xer);
2227 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2228 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2230 case OP_SUB_OVF_CARRY:
2231 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2233 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2234 ppc_mfspr (code, ppc_r0, ppc_xer);
2235 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2236 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2238 case OP_SUB_OVF_UN_CARRY:
2239 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2241 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2242 ppc_mfspr (code, ppc_r0, ppc_xer);
2243 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2244 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2247 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2250 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2253 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2256 // we add the negated value
2257 if (ppc_is_imm16 (-ins->inst_imm))
2258 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2260 g_assert_not_reached ();
2264 g_assert (ppc_is_imm16 (ins->inst_imm));
2265 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2268 ppc_subfze (code, ins->dreg, ins->sreg1);
2271 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2272 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2275 if (!(ins->inst_imm & 0xffff0000)) {
2276 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2277 } else if (!(ins->inst_imm & 0xffff)) {
2278 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2280 g_assert_not_reached ();
2284 guint32 *divisor_is_m1;
2285 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2287 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2288 divisor_is_m1 = code;
2289 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2290 ppc_lis (code, ppc_r11, 0x8000);
2291 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2292 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2293 ppc_patch (divisor_is_m1, code);
2294 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2296 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2297 ppc_mfspr (code, ppc_r0, ppc_xer);
2298 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2299 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2303 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2304 ppc_mfspr (code, ppc_r0, ppc_xer);
2305 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2306 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2309 g_assert_not_reached ();
2311 ppc_load (code, ppc_r11, ins->inst_imm);
2312 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2313 ppc_mfspr (code, ppc_r0, ppc_xer);
2314 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2315 /* FIXME: use OverflowException for 0x80000000/-1 */
2316 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2320 guint32 *divisor_is_m1;
2321 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2322 divisor_is_m1 = code;
2323 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2324 ppc_lis (code, ppc_r11, 0x8000);
2325 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2326 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2327 ppc_patch (divisor_is_m1, code);
2328 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2329 ppc_mfspr (code, ppc_r0, ppc_xer);
2330 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2331 /* FIXME: use OverflowException for 0x80000000/-1 */
2332 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2333 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2334 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2338 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2339 ppc_mfspr (code, ppc_r0, ppc_xer);
2340 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2341 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2342 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2343 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2346 g_assert_not_reached ();
2348 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2351 if (!(ins->inst_imm & 0xffff0000)) {
2352 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2353 } else if (!(ins->inst_imm & 0xffff)) {
2354 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2356 g_assert_not_reached ();
2360 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2363 if (!(ins->inst_imm & 0xffff0000)) {
2364 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2365 } else if (!(ins->inst_imm & 0xffff)) {
2366 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2368 g_assert_not_reached ();
2372 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2375 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2378 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2381 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2384 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2387 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2390 ppc_not (code, ins->dreg, ins->sreg1);
2393 ppc_neg (code, ins->dreg, ins->sreg1);
2396 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2399 if (ppc_is_imm16 (ins->inst_imm)) {
2400 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2402 g_assert_not_reached ();
2406 /* we annot use mcrxr, since it's not implemented on some processors
2407 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2409 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2410 ppc_mfspr (code, ppc_r0, ppc_xer);
2411 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2412 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2414 case CEE_MUL_OVF_UN:
2415 /* we first multiply to get the high word and compare to 0
2416 * to set the flags, then the result is discarded and then
2417 * we multiply to get the lower * bits result
2419 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2420 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2421 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2422 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2426 ppc_load (code, ins->dreg, ins->inst_c0);
2429 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2430 ppc_lis (code, ins->dreg, 0);
2431 ppc_ori (code, ins->dreg, ins->dreg, 0);
2437 ppc_mr (code, ins->dreg, ins->sreg1);
2440 int saved = ins->sreg1;
2441 if (ins->sreg1 == ppc_r3) {
2442 ppc_mr (code, ppc_r0, ins->sreg1);
2445 if (ins->sreg2 != ppc_r3)
2446 ppc_mr (code, ppc_r3, ins->sreg2);
2447 if (saved != ppc_r4)
2448 ppc_mr (code, ppc_r4, saved);
2453 ppc_fmr (code, ins->dreg, ins->sreg1);
2455 case OP_FCONV_TO_R4:
2456 ppc_frsp (code, ins->dreg, ins->sreg1);
2462 * Keep in sync with mono_arch_emit_epilog
2464 g_assert (!cfg->method->save_lmf);
2465 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2466 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2467 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2469 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2470 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2472 ppc_mtlr (code, ppc_r0);
2474 if (ppc_is_imm16 (cfg->stack_usage)) {
2475 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2477 ppc_load (code, ppc_r11, cfg->stack_usage);
2478 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2480 if (!cfg->method->save_lmf) {
2481 /*for (i = 31; i >= 14; --i) {
2482 if (cfg->used_float_regs & (1 << i)) {
2483 pos += sizeof (double);
2484 ppc_lfd (code, i, -pos, cfg->frame_reg);
2487 for (i = 31; i >= 13; --i) {
2488 if (cfg->used_int_regs & (1 << i)) {
2489 pos += sizeof (gulong);
2490 ppc_lwz (code, i, -pos, cfg->frame_reg);
2494 /* FIXME restore from MonoLMF: though this can't happen yet */
2496 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2501 /* ensure ins->sreg1 is not NULL */
2502 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2505 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2506 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2508 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2509 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2511 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2519 call = (MonoCallInst*)ins;
2520 if (ins->flags & MONO_INST_HAS_METHOD)
2521 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2523 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2524 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2525 ppc_lis (code, ppc_r0, 0);
2526 ppc_ori (code, ppc_r0, ppc_r0, 0);
2527 ppc_mtlr (code, ppc_r0);
2536 case OP_VOIDCALL_REG:
2538 ppc_mtlr (code, ins->sreg1);
2541 case OP_FCALL_MEMBASE:
2542 case OP_LCALL_MEMBASE:
2543 case OP_VCALL_MEMBASE:
2544 case OP_VOIDCALL_MEMBASE:
2545 case OP_CALL_MEMBASE:
2546 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2547 ppc_mtlr (code, ppc_r0);
2551 g_assert_not_reached ();
2554 guint32 * zero_loop_jump, * zero_loop_start;
2555 /* keep alignment */
2556 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2557 int area_offset = alloca_waste;
2559 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2560 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2561 /* use ctr to store the number of words to 0 if needed */
2562 if (ins->flags & MONO_INST_INIT) {
2563 /* we zero 4 bytes at a time */
2564 ppc_addi (code, ppc_r0, ins->sreg1, 3);
2565 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2566 ppc_mtctr (code, ppc_r0);
2568 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2569 ppc_neg (code, ppc_r11, ppc_r11);
2570 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2572 if (ins->flags & MONO_INST_INIT) {
2573 /* adjust the dest reg by -4 so we can use stwu */
2574 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
2575 ppc_li (code, ppc_r11, 0);
2576 zero_loop_start = code;
2577 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2578 zero_loop_jump = code;
2579 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2580 ppc_patch (zero_loop_jump, zero_loop_start);
2582 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2590 ppc_mr (code, ppc_r3, ins->sreg1);
2591 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2592 (gpointer)"mono_arch_throw_exception");
2593 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2594 ppc_lis (code, ppc_r0, 0);
2595 ppc_ori (code, ppc_r0, ppc_r0, 0);
2596 ppc_mtlr (code, ppc_r0);
2605 ppc_mr (code, ppc_r3, ins->sreg1);
2606 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2607 (gpointer)"mono_arch_rethrow_exception");
2608 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2609 ppc_lis (code, ppc_r0, 0);
2610 ppc_ori (code, ppc_r0, ppc_r0, 0);
2611 ppc_mtlr (code, ppc_r0);
2618 case OP_START_HANDLER:
2619 ppc_mflr (code, ppc_r0);
2620 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2621 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2623 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2624 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2628 if (ins->sreg1 != ppc_r3)
2629 ppc_mr (code, ppc_r3, ins->sreg1);
2630 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2631 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2633 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2634 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2636 ppc_mtlr (code, ppc_r0);
2640 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2641 ppc_mtlr (code, ppc_r0);
2644 case OP_CALL_HANDLER:
2645 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2649 ins->inst_c0 = code - cfg->native_code;
2652 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2653 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2655 if (ins->flags & MONO_INST_BRLABEL) {
2656 /*if (ins->inst_i0->inst_c0) {
2658 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2660 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2664 /*if (ins->inst_target_bb->native_offset) {
2666 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2668 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2674 ppc_mtctr (code, ins->sreg1);
2675 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2678 ppc_li (code, ins->dreg, 0);
2679 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2680 ppc_li (code, ins->dreg, 1);
2684 ppc_li (code, ins->dreg, 1);
2685 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2686 ppc_li (code, ins->dreg, 0);
2690 ppc_li (code, ins->dreg, 1);
2691 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2692 ppc_li (code, ins->dreg, 0);
2694 case OP_COND_EXC_EQ:
2695 case OP_COND_EXC_NE_UN:
2696 case OP_COND_EXC_LT:
2697 case OP_COND_EXC_LT_UN:
2698 case OP_COND_EXC_GT:
2699 case OP_COND_EXC_GT_UN:
2700 case OP_COND_EXC_GE:
2701 case OP_COND_EXC_GE_UN:
2702 case OP_COND_EXC_LE:
2703 case OP_COND_EXC_LE_UN:
2704 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2707 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2709 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2710 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2711 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2713 case OP_COND_EXC_OV:
2714 /*ppc_mcrxr (code, 0);
2715 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2717 case OP_COND_EXC_NC:
2718 case OP_COND_EXC_NO:
2719 g_assert_not_reached ();
2731 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2734 /* floating point opcodes */
2736 ppc_load (code, ppc_r11, ins->inst_p0);
2737 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2740 ppc_load (code, ppc_r11, ins->inst_p0);
2741 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2743 case OP_STORER8_MEMBASE_REG:
2744 if (ppc_is_imm16 (ins->inst_offset)) {
2745 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2747 g_assert_not_reached ();
2750 case OP_LOADR8_MEMBASE:
2751 if (ppc_is_imm16 (ins->inst_offset)) {
2752 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2754 g_assert_not_reached ();
2757 case OP_STORER4_MEMBASE_REG:
2758 ppc_frsp (code, ins->sreg1, ins->sreg1);
2759 if (ppc_is_imm16 (ins->inst_offset)) {
2760 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2762 g_assert_not_reached ();
2765 case OP_LOADR4_MEMBASE:
2766 if (ppc_is_imm16 (ins->inst_offset)) {
2767 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2769 g_assert_not_reached ();
2772 case OP_LOADR4_MEMINDEX:
2773 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2775 case OP_LOADR8_MEMINDEX:
2776 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2778 case OP_STORER4_MEMINDEX:
2779 ppc_frsp (code, ins->sreg1, ins->sreg1);
2780 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2782 case OP_STORER8_MEMINDEX:
2783 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2785 case CEE_CONV_R_UN: {
2786 static const guint64 adjust_val = 0x4330000000000000ULL;
2787 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2788 ppc_stw (code, ppc_r0, -8, ppc_sp);
2789 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2790 ppc_load (code, ppc_r11, &adjust_val);
2791 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2792 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2793 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2796 case CEE_CONV_R4: /* FIXME: change precision */
2798 static const guint64 adjust_val = 0x4330000080000000ULL;
2799 // addis is special for ppc_r0
2800 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2801 ppc_stw (code, ppc_r0, -8, ppc_sp);
2802 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2803 ppc_stw (code, ppc_r11, -4, ppc_sp);
2804 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2805 ppc_load (code, ppc_r11, &adjust_val);
2806 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2807 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2810 case OP_FCONV_TO_I1:
2811 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2813 case OP_FCONV_TO_U1:
2814 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2816 case OP_FCONV_TO_I2:
2817 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2819 case OP_FCONV_TO_U2:
2820 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2822 case OP_FCONV_TO_I4:
2824 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2826 case OP_FCONV_TO_U4:
2828 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2830 case OP_FCONV_TO_I8:
2831 case OP_FCONV_TO_U8:
2832 g_assert_not_reached ();
2833 /* Implemented as helper calls */
2835 case OP_LCONV_TO_R_UN:
2836 g_assert_not_reached ();
2837 /* Implemented as helper calls */
2839 case OP_LCONV_TO_OVF_I: {
2840 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2841 // Check if its negative
2842 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2843 negative_branch = code;
2844 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2845 // Its positive msword == 0
2846 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2847 msword_positive_branch = code;
2848 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2850 ovf_ex_target = code;
2851 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2853 ppc_patch (negative_branch, code);
2854 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2855 msword_negative_branch = code;
2856 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2857 ppc_patch (msword_negative_branch, ovf_ex_target);
2859 ppc_patch (msword_positive_branch, code);
2860 if (ins->dreg != ins->sreg1)
2861 ppc_mr (code, ins->dreg, ins->sreg1);
2865 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2868 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2871 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2874 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2877 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2880 ppc_fneg (code, ins->dreg, ins->sreg1);
2884 g_assert_not_reached ();
2887 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2890 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2891 ppc_li (code, ins->dreg, 0);
2892 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2893 ppc_li (code, ins->dreg, 1);
2896 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2897 ppc_li (code, ins->dreg, 1);
2898 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2899 ppc_li (code, ins->dreg, 0);
2902 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2903 ppc_li (code, ins->dreg, 1);
2904 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2905 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2906 ppc_li (code, ins->dreg, 0);
2909 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2910 ppc_li (code, ins->dreg, 1);
2911 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2912 ppc_li (code, ins->dreg, 0);
2915 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2916 ppc_li (code, ins->dreg, 1);
2917 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2918 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2919 ppc_li (code, ins->dreg, 0);
2922 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2925 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2928 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2929 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2932 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2933 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2936 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2937 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2940 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2941 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2944 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2945 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2948 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2951 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2952 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2955 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2958 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2959 ppc_lwz (code, ppc_r11, -8, ppc_sp);
2960 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2961 ppc_addis (code, ppc_r11, ppc_r11, -32752);
2962 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2963 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2967 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2968 g_assert_not_reached ();
2971 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2972 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2973 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2974 g_assert_not_reached ();
2980 last_offset = offset;
2985 cfg->code_len = code - cfg->native_code;
2989 mono_arch_register_lowlevel_calls (void)
2993 #define patch_lis_ori(ip,val) do {\
2994 guint16 *__lis_ori = (guint16*)(ip); \
2995 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
2996 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3000 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3002 MonoJumpInfo *patch_info;
3004 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3005 unsigned char *ip = patch_info->ip.i + code;
3006 const unsigned char *target;
3008 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3010 switch (patch_info->type) {
3011 case MONO_PATCH_INFO_IP:
3012 patch_lis_ori (ip, ip);
3014 case MONO_PATCH_INFO_METHOD_REL:
3015 g_assert_not_reached ();
3016 *((gpointer *)(ip)) = code + patch_info->data.offset;
3018 case MONO_PATCH_INFO_SWITCH: {
3019 gpointer *table = (gpointer *)patch_info->data.table->table;
3022 patch_lis_ori (ip, table);
3024 for (i = 0; i < patch_info->data.table->table_size; i++) {
3025 table [i] = (int)patch_info->data.table->table [i] + code;
3027 /* we put into the table the absolute address, no need for ppc_patch in this case */
3030 case MONO_PATCH_INFO_METHODCONST:
3031 case MONO_PATCH_INFO_CLASS:
3032 case MONO_PATCH_INFO_IMAGE:
3033 case MONO_PATCH_INFO_FIELD:
3034 case MONO_PATCH_INFO_VTABLE:
3035 case MONO_PATCH_INFO_IID:
3036 case MONO_PATCH_INFO_SFLDA:
3037 case MONO_PATCH_INFO_LDSTR:
3038 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3039 case MONO_PATCH_INFO_LDTOKEN:
3040 /* from OP_AOTCONST : lis + ori */
3041 patch_lis_ori (ip, target);
3043 case MONO_PATCH_INFO_R4:
3044 case MONO_PATCH_INFO_R8:
3045 g_assert_not_reached ();
3046 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3048 case MONO_PATCH_INFO_EXC_NAME:
3049 g_assert_not_reached ();
3050 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3052 case MONO_PATCH_INFO_NONE:
3053 case MONO_PATCH_INFO_BB_OVF:
3054 case MONO_PATCH_INFO_EXC_OVF:
3055 /* everything is dealt with at epilog output time */
3060 ppc_patch (ip, target);
3065 * Stack frame layout:
3067 * ------------------- sp
3068 * MonoLMF structure or saved registers
3069 * -------------------
3071 * -------------------
3073 * -------------------
3074 * optional 8 bytes for tracing
3075 * -------------------
3076 * param area size is cfg->param_area
3077 * -------------------
3078 * linkage area size is PPC_STACK_PARAM_OFFSET
3079 * ------------------- sp
3083 mono_arch_emit_prolog (MonoCompile *cfg)
3085 MonoMethod *method = cfg->method;
3087 MonoMethodSignature *sig;
3089 int alloc_size, pos, max_offset, i;
3095 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3098 sig = mono_method_signature (method);
3099 cfg->code_size = 256 + sig->param_count * 20;
3100 code = cfg->native_code = g_malloc (cfg->code_size);
3102 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3103 ppc_mflr (code, ppc_r0);
3104 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3107 alloc_size = cfg->stack_offset;
3110 if (!method->save_lmf) {
3111 /*for (i = 31; i >= 14; --i) {
3112 if (cfg->used_float_regs & (1 << i)) {
3113 pos += sizeof (gdouble);
3114 ppc_stfd (code, i, -pos, ppc_sp);
3117 for (i = 31; i >= 13; --i) {
3118 if (cfg->used_int_regs & (1 << i)) {
3119 pos += sizeof (gulong);
3120 ppc_stw (code, i, -pos, ppc_sp);
3125 pos += sizeof (MonoLMF);
3127 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3128 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3129 for (i = 14; i < 32; i++) {
3130 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3134 // align to PPC_STACK_ALIGNMENT bytes
3135 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3136 alloc_size += PPC_STACK_ALIGNMENT - 1;
3137 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3140 cfg->stack_usage = alloc_size;
3141 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3143 if (ppc_is_imm16 (-alloc_size)) {
3144 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3146 ppc_load (code, ppc_r11, -alloc_size);
3147 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3150 if (cfg->frame_reg != ppc_sp)
3151 ppc_mr (code, cfg->frame_reg, ppc_sp);
3153 /* compute max_offset in order to use short forward jumps
3154 * we always do it on ppc because the immediate displacement
3155 * for jumps is too small
3158 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3159 MonoInst *ins = bb->code;
3160 bb->max_offset = max_offset;
3162 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3166 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3171 /* load arguments allocated to register from the stack */
3174 cinfo = calculate_sizes (sig, sig->pinvoke);
3176 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3177 ArgInfo *ainfo = &cinfo->ret;
3179 if (ppc_is_imm16 (inst->inst_offset)) {
3180 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3182 ppc_load (code, ppc_r11, inst->inst_offset);
3183 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3186 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3187 ArgInfo *ainfo = cinfo->args + i;
3188 inst = cfg->args [pos];
3190 if (cfg->verbose_level > 2)
3191 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3192 if (inst->opcode == OP_REGVAR) {
3193 if (ainfo->regtype == RegTypeGeneral)
3194 ppc_mr (code, inst->dreg, ainfo->reg);
3195 else if (ainfo->regtype == RegTypeFP)
3196 ppc_fmr (code, inst->dreg, ainfo->reg);
3197 else if (ainfo->regtype == RegTypeBase) {
3198 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3199 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3201 g_assert_not_reached ();
3203 if (cfg->verbose_level > 2)
3204 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3206 /* the argument should be put on the stack: FIXME handle size != word */
3207 if (ainfo->regtype == RegTypeGeneral) {
3208 switch (ainfo->size) {
3210 if (ppc_is_imm16 (inst->inst_offset)) {
3211 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3213 ppc_load (code, ppc_r11, inst->inst_offset);
3214 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3218 if (ppc_is_imm16 (inst->inst_offset)) {
3219 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3221 ppc_load (code, ppc_r11, inst->inst_offset);
3222 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3226 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3227 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3228 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3230 ppc_load (code, ppc_r11, inst->inst_offset);
3231 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3232 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3233 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3237 if (ppc_is_imm16 (inst->inst_offset)) {
3238 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3240 ppc_load (code, ppc_r11, inst->inst_offset);
3241 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3245 } else if (ainfo->regtype == RegTypeBase) {
3246 /* load the previous stack pointer in r11 */
3247 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3248 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3249 switch (ainfo->size) {
3251 if (ppc_is_imm16 (inst->inst_offset)) {
3252 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3254 ppc_load (code, ppc_r11, inst->inst_offset);
3255 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3259 if (ppc_is_imm16 (inst->inst_offset)) {
3260 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3262 ppc_load (code, ppc_r11, inst->inst_offset);
3263 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3267 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3268 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3269 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3270 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3273 g_assert_not_reached ();
3277 if (ppc_is_imm16 (inst->inst_offset)) {
3278 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3280 ppc_load (code, ppc_r11, inst->inst_offset);
3281 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3285 } else if (ainfo->regtype == RegTypeFP) {
3286 g_assert (ppc_is_imm16 (inst->inst_offset));
3287 if (ainfo->size == 8)
3288 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3289 else if (ainfo->size == 4)
3290 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3292 g_assert_not_reached ();
3293 } else if (ainfo->regtype == RegTypeStructByVal) {
3294 int doffset = inst->inst_offset;
3298 g_assert (ppc_is_imm16 (inst->inst_offset));
3299 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3300 if (mono_class_from_mono_type (inst->inst_vtype))
3301 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3302 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3304 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3305 register. Should this case include linux/ppc?
3309 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3311 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3314 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3315 soffset += sizeof (gpointer);
3316 doffset += sizeof (gpointer);
3318 if (ainfo->vtsize) {
3319 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3320 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3321 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3322 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3324 } else if (ainfo->regtype == RegTypeStructByAddr) {
3325 /* if it was originally a RegTypeBase */
3326 if (ainfo->offset) {
3327 /* load the previous stack pointer in r11 */
3328 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3329 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3331 ppc_mr (code, ppc_r11, ainfo->reg);
3333 g_assert (ppc_is_imm16 (inst->inst_offset));
3334 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3335 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3337 g_assert_not_reached ();
3342 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3343 ppc_load (code, ppc_r3, cfg->domain);
3344 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3345 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3346 ppc_lis (code, ppc_r0, 0);
3347 ppc_ori (code, ppc_r0, ppc_r0, 0);
3348 ppc_mtlr (code, ppc_r0);
3355 if (method->save_lmf) {
3356 if (lmf_pthread_key != -1) {
3357 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3358 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3359 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3361 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3362 (gpointer)"mono_get_lmf_addr");
3363 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3364 ppc_lis (code, ppc_r0, 0);
3365 ppc_ori (code, ppc_r0, ppc_r0, 0);
3366 ppc_mtlr (code, ppc_r0);
3372 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3373 /* lmf_offset is the offset from the previous stack pointer,
3374 * alloc_size is the total stack space allocated, so the offset
3375 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3376 * The pointer to the struct is put in ppc_r11 (new_lmf).
3377 * The callee-saved registers are already in the MonoLMF structure
3379 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3380 /* ppc_r3 is the result from mono_get_lmf_addr () */
3381 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3382 /* new_lmf->previous_lmf = *lmf_addr */
3383 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3384 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3385 /* *(lmf_addr) = r11 */
3386 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3387 /* save method info */
3388 ppc_load (code, ppc_r0, method);
3389 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3390 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3391 /* save the current IP */
3392 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3393 ppc_load (code, ppc_r0, 0x01010101);
3394 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3398 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3400 cfg->code_len = code - cfg->native_code;
3401 g_assert (cfg->code_len < cfg->code_size);
3408 mono_arch_emit_epilog (MonoCompile *cfg)
3410 MonoJumpInfo *patch_info;
3411 MonoMethod *method = cfg->method;
3413 int max_epilog_size = 16 + 20*4;
3416 if (cfg->method->save_lmf)
3417 max_epilog_size += 128;
3419 if (mono_jit_trace_calls != NULL)
3420 max_epilog_size += 50;
3422 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3423 max_epilog_size += 50;
3425 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3426 cfg->code_size *= 2;
3427 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3428 mono_jit_stats.code_reallocs++;
3432 * Keep in sync with OP_JMP
3434 code = cfg->native_code + cfg->code_len;
3436 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3437 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3441 if (method->save_lmf) {
3443 pos += sizeof (MonoLMF);
3445 /* save the frame reg in r8 */
3446 ppc_mr (code, ppc_r8, cfg->frame_reg);
3447 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3448 /* r5 = previous_lmf */
3449 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3451 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3452 /* *(lmf_addr) = previous_lmf */
3453 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3454 /* FIXME: speedup: there is no actual need to restore the registers if
3455 * we didn't actually change them (idea from Zoltan).
3458 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3460 /*for (i = 14; i < 32; i++) {
3461 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3463 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3464 /* use the saved copy of the frame reg in r8 */
3465 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3466 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3467 ppc_mtlr (code, ppc_r0);
3469 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3471 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3472 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3473 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3475 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3476 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3478 ppc_mtlr (code, ppc_r0);
3480 if (ppc_is_imm16 (cfg->stack_usage)) {
3481 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3483 ppc_load (code, ppc_r11, cfg->stack_usage);
3484 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3487 /*for (i = 31; i >= 14; --i) {
3488 if (cfg->used_float_regs & (1 << i)) {
3489 pos += sizeof (double);
3490 ppc_lfd (code, i, -pos, ppc_sp);
3493 for (i = 31; i >= 13; --i) {
3494 if (cfg->used_int_regs & (1 << i)) {
3495 pos += sizeof (gulong);
3496 ppc_lwz (code, i, -pos, ppc_sp);
3502 cfg->code_len = code - cfg->native_code;
3504 g_assert (cfg->code_len < cfg->code_size);
3508 /* remove once throw_exception_by_name is eliminated */
3510 exception_id_by_name (const char *name)
3512 if (strcmp (name, "IndexOutOfRangeException") == 0)
3513 return MONO_EXC_INDEX_OUT_OF_RANGE;
3514 if (strcmp (name, "OverflowException") == 0)
3515 return MONO_EXC_OVERFLOW;
3516 if (strcmp (name, "ArithmeticException") == 0)
3517 return MONO_EXC_ARITHMETIC;
3518 if (strcmp (name, "DivideByZeroException") == 0)
3519 return MONO_EXC_DIVIDE_BY_ZERO;
3520 if (strcmp (name, "InvalidCastException") == 0)
3521 return MONO_EXC_INVALID_CAST;
3522 if (strcmp (name, "NullReferenceException") == 0)
3523 return MONO_EXC_NULL_REF;
3524 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3525 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3526 g_error ("Unknown intrinsic exception %s\n", name);
3531 mono_arch_emit_exceptions (MonoCompile *cfg)
3533 MonoJumpInfo *patch_info;
3536 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3537 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3540 int max_epilog_size = 50;
3542 /* count the number of exception infos */
3545 * make sure we have enough space for exceptions
3546 * 24 is the simulated call to throw_exception_by_name
3548 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3549 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3550 i = exception_id_by_name (patch_info->data.target);
3551 if (!exc_throw_found [i]) {
3552 max_epilog_size += 24;
3553 exc_throw_found [i] = TRUE;
3555 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3556 max_epilog_size += 12;
3557 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3558 MonoOvfJump *ovfj = patch_info->data.target;
3559 i = exception_id_by_name (ovfj->data.exception);
3560 if (!exc_throw_found [i]) {
3561 max_epilog_size += 24;
3562 exc_throw_found [i] = TRUE;
3564 max_epilog_size += 8;
3568 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3569 cfg->code_size *= 2;
3570 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3571 mono_jit_stats.code_reallocs++;
3574 code = cfg->native_code + cfg->code_len;
3576 /* add code to raise exceptions */
3577 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3578 switch (patch_info->type) {
3579 case MONO_PATCH_INFO_BB_OVF: {
3580 MonoOvfJump *ovfj = patch_info->data.target;
3581 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3582 /* patch the initial jump */
3583 ppc_patch (ip, code);
3584 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3586 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3587 /* jump back to the true target */
3589 ip = ovfj->data.bb->native_offset + cfg->native_code;
3590 ppc_patch (code - 4, ip);
3593 case MONO_PATCH_INFO_EXC_OVF: {
3594 MonoOvfJump *ovfj = patch_info->data.target;
3595 MonoJumpInfo *newji;
3596 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3597 unsigned char *bcl = code;
3598 /* patch the initial jump: we arrived here with a call */
3599 ppc_patch (ip, code);
3600 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3602 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3603 /* patch the conditional jump to the right handler */
3604 /* make it processed next */
3605 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3606 newji->type = MONO_PATCH_INFO_EXC;
3607 newji->ip.i = bcl - cfg->native_code;
3608 newji->data.target = ovfj->data.exception;
3609 newji->next = patch_info->next;
3610 patch_info->next = newji;
3613 case MONO_PATCH_INFO_EXC: {
3614 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3615 i = exception_id_by_name (patch_info->data.target);
3616 if (exc_throw_pos [i]) {
3617 ppc_patch (ip, exc_throw_pos [i]);
3618 patch_info->type = MONO_PATCH_INFO_NONE;
3621 exc_throw_pos [i] = code;
3623 ppc_patch (ip, code);
3624 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3625 ppc_load (code, ppc_r3, patch_info->data.target);
3626 /* we got here from a conditional call, so the calling ip is set in lr already */
3627 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3628 patch_info->data.name = "mono_arch_throw_exception_by_name";
3629 patch_info->ip.i = code - cfg->native_code;
3630 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3631 ppc_lis (code, ppc_r0, 0);
3632 ppc_ori (code, ppc_r0, ppc_r0, 0);
3633 ppc_mtctr (code, ppc_r0);
3634 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3646 cfg->code_len = code - cfg->native_code;
3648 g_assert (cfg->code_len < cfg->code_size);
3653 try_offset_access (void *value, guint32 idx)
3655 register void* me __asm__ ("r2");
3656 void ***p = (void***)((char*)me + 284);
3657 int idx1 = idx / 32;
3658 int idx2 = idx % 32;
3661 if (value != p[idx1][idx2])
3667 setup_tls_access (void)
3670 guint32 *ins, *code;
3671 guint32 cmplwi_1023, li_0x48, blr_ins;
3672 if (tls_mode == TLS_MODE_FAILED)
3675 if (g_getenv ("MONO_NO_TLS")) {
3676 tls_mode = TLS_MODE_FAILED;
3680 if (tls_mode == TLS_MODE_DETECT) {
3681 ins = (guint32*)pthread_getspecific;
3682 /* uncond branch to the real method */
3683 if ((*ins >> 26) == 18) {
3685 val = (*ins & ~3) << 6;
3689 ins = (guint32*)val;
3691 ins = (guint32*) ((char*)ins + val);
3694 code = &cmplwi_1023;
3695 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3697 ppc_li (code, ppc_r4, 0x48);
3700 if (*ins == cmplwi_1023) {
3701 int found_lwz_284 = 0;
3702 for (ptk = 0; ptk < 20; ++ptk) {
3704 if (!*ins || *ins == blr_ins)
3706 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3711 if (!found_lwz_284) {
3712 tls_mode = TLS_MODE_FAILED;
3715 tls_mode = TLS_MODE_LTHREADS;
3716 } else if (*ins == li_0x48) {
3718 /* uncond branch to the real method */
3719 if ((*ins >> 26) == 18) {
3721 val = (*ins & ~3) << 6;
3725 ins = (guint32*)val;
3727 ins = (guint32*) ((char*)ins + val);
3730 ppc_li (code, ppc_r0, 0x7FF2);
3731 if (ins [1] == val) {
3732 /* Darwin on G4, implement */
3733 tls_mode = TLS_MODE_FAILED;
3737 ppc_mfspr (code, ppc_r3, 104);
3738 if (ins [1] != val) {
3739 tls_mode = TLS_MODE_FAILED;
3742 tls_mode = TLS_MODE_DARWIN_G5;
3745 tls_mode = TLS_MODE_FAILED;
3749 tls_mode = TLS_MODE_FAILED;
3753 if (monodomain_key == -1) {
3754 ptk = mono_domain_get_tls_key ();
3756 ptk = mono_pthread_key_for_tls (ptk);
3758 monodomain_key = ptk;
3762 if (lmf_pthread_key == -1) {
3763 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3765 /*g_print ("MonoLMF at: %d\n", ptk);*/
3766 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3767 init_tls_failed = 1;
3770 lmf_pthread_key = ptk;
3773 if (monothread_key == -1) {
3774 ptk = mono_thread_get_tls_key ();
3776 ptk = mono_pthread_key_for_tls (ptk);
3778 monothread_key = ptk;
3779 /*g_print ("thread inited: %d\n", ptk);*/
3782 /*g_print ("thread not inited yet %d\n", ptk);*/
3788 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3790 setup_tls_access ();
3794 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3799 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3801 int this_dreg = ppc_r3;
3806 /* add the this argument */
3807 if (this_reg != -1) {
3809 MONO_INST_NEW (cfg, this, OP_SETREG);
3810 this->type = this_type;
3811 this->sreg1 = this_reg;
3812 this->dreg = mono_regstate_next_int (cfg->rs);
3813 mono_bblock_add_inst (cfg->cbb, this);
3814 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3819 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3820 vtarg->type = STACK_MP;
3821 vtarg->sreg1 = vt_reg;
3822 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3823 mono_bblock_add_inst (cfg->cbb, vtarg);
3824 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3829 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3831 MonoInst *ins = NULL;
3833 if (cmethod->klass == mono_defaults.thread_class &&
3834 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3835 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3837 /*if (cmethod->klass == mono_defaults.math_class) {
3838 if (strcmp (cmethod->name, "Sqrt") == 0) {
3839 MONO_INST_NEW (cfg, ins, OP_SQRT);
3840 ins->inst_i0 = args [0];
3847 mono_arch_print_tree (MonoInst *tree, int arity)
3852 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3856 setup_tls_access ();
3857 if (monodomain_key == -1)
3860 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3861 ins->inst_offset = monodomain_key;
3866 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3870 setup_tls_access ();
3871 if (monothread_key == -1)
3874 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3875 ins->inst_offset = monothread_key;