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 mono_arch_get_vcall_slot_addr (guint8 *code_ptr, gpointer *regs)
226 guint32* code = (guint32*)code_ptr;
228 /* This is the 'blrl' instruction */
231 /* Sanity check: instruction must be 'blrl' */
232 if (*code != 0x4e800021)
235 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
236 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
240 /* OK, we're now at the 'blrl' instruction. Now walk backwards
241 till we get to a 'mtlr rA' */
243 if((*code & 0x7c0803a6) == 0x7c0803a6) {
244 /* Here we are: we reached the 'mtlr rA'.
245 Extract the register from the instruction */
246 reg = (*code & 0x03e00000) >> 21;
248 /* ok, this is a lwz reg, offset (vtreg)
249 * it is emitted with:
250 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
252 offset = (*code & 0xffff);
253 reg = (*code >> 16) & 0x1f;
254 g_assert (reg != ppc_r1);
255 /*g_print ("patching reg is %d\n", reg);*/
257 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
258 /* saved in the MonoLMF structure */
259 o = (gpointer)lmf->iregs [reg - 13];
271 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
277 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
279 /* FIXME: handle returning a struct */
280 if (MONO_TYPE_ISSTRUCT (sig->ret))
281 return (gpointer)regs [ppc_r4];
282 return (gpointer)regs [ppc_r3];
286 * Initialize the cpu to execute managed code.
289 mono_arch_cpu_init (void)
294 * Initialize architecture specific code.
297 mono_arch_init (void)
302 * Cleanup architecture specific code.
305 mono_arch_cleanup (void)
310 * This function returns the optimizations supported on this cpu.
313 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
317 /* no ppc-specific optimizations yet */
323 is_regsize_var (MonoType *t) {
326 t = mono_type_get_underlying_type (t);
333 case MONO_TYPE_FNPTR:
335 case MONO_TYPE_OBJECT:
336 case MONO_TYPE_STRING:
337 case MONO_TYPE_CLASS:
338 case MONO_TYPE_SZARRAY:
339 case MONO_TYPE_ARRAY:
341 case MONO_TYPE_GENERICINST:
342 if (!mono_type_generic_inst_is_valuetype (t))
345 case MONO_TYPE_VALUETYPE:
352 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
357 for (i = 0; i < cfg->num_varinfo; i++) {
358 MonoInst *ins = cfg->varinfo [i];
359 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
362 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
365 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
368 /* we can only allocate 32 bit values */
369 if (is_regsize_var (ins->inst_vtype)) {
370 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
371 g_assert (i == vmv->idx);
372 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
380 mono_arch_get_global_int_regs (MonoCompile *cfg)
384 if (cfg->frame_reg != ppc_sp)
386 /* ppc_r13 is used by the system on PPC EABI */
387 for (i = 14; i < top; ++i)
388 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
394 * mono_arch_regalloc_cost:
396 * Return the cost, in number of memory references, of the action of
397 * allocating the variable VMV into a register during global register
401 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
413 mono_arch_flush_icache (guint8 *code, gint size)
415 guint8 *p, *endp, *start;
416 static int cachelinesize = 0;
417 static int cachelineinc = 16;
419 if (!cachelinesize) {
423 mib [1] = HW_CACHELINE;
424 len = sizeof (cachelinesize);
425 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
429 cachelineinc = cachelinesize;
430 /*g_print ("setting cl size to %d\n", cachelinesize);*/
432 #elif defined(__linux__)
433 /* sadly this will work only with 2.6 kernels... */
434 FILE* f = fopen ("/proc/self/auxv", "rb");
437 while (fread (&vec, sizeof (vec), 1, f) == 1) {
438 if (vec.type == 19) {
439 cachelinesize = vec.value;
448 #warning Need a way to get cache line size
454 start = (guint8*)((guint32)start & ~(cachelinesize - 1));
455 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
457 for (p = start; p < endp; p += cachelineinc) {
458 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
461 for (p = start; p < endp; p += cachelineinc) {
462 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
467 for (p = start; p < endp; p += cachelineinc) {
468 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
474 #define NOT_IMPLEMENTED(x) \
475 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
478 #define ALWAYS_ON_STACK(s) s
479 #define FP_ALSO_IN_REG(s) s
481 #define ALWAYS_ON_STACK(s)
482 #define FP_ALSO_IN_REG(s)
483 #define ALIGN_DOUBLES
496 guint32 vtsize; /* in param area */
498 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
499 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
514 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
517 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
518 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
519 ainfo->reg = ppc_sp; /* in the caller */
520 ainfo->regtype = RegTypeBase;
523 ALWAYS_ON_STACK (*stack_size += 4);
527 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
529 //*stack_size += (*stack_size % 8);
531 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
532 ainfo->reg = ppc_sp; /* in the caller */
533 ainfo->regtype = RegTypeBase;
540 ALWAYS_ON_STACK (*stack_size += 8);
549 /* size == 4 is checked already */
551 has_only_a_r4_field (MonoClass *klass)
556 while ((f = mono_class_get_fields (klass, &iter))) {
557 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
558 if (!f->type->byref && f->type->type == MONO_TYPE_R4)
568 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
571 int n = sig->hasthis + sig->param_count;
573 guint32 stack_size = 0;
574 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
576 fr = PPC_FIRST_FPARG_REG;
577 gr = PPC_FIRST_ARG_REG;
579 /* FIXME: handle returning a struct */
580 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
581 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
582 cinfo->struct_ret = PPC_FIRST_ARG_REG;
587 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
590 DEBUG(printf("params: %d\n", sig->param_count));
591 for (i = 0; i < sig->param_count; ++i) {
592 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
593 /* Prevent implicit arguments and sig_cookie from
594 being passed in registers */
595 gr = PPC_LAST_ARG_REG + 1;
596 /* Emit the signature cookie just before the implicit arguments */
597 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
599 DEBUG(printf("param %d: ", i));
600 if (sig->params [i]->byref) {
601 DEBUG(printf("byref\n"));
602 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
606 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
607 switch (simpletype) {
608 case MONO_TYPE_BOOLEAN:
611 cinfo->args [n].size = 1;
612 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
618 cinfo->args [n].size = 2;
619 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
624 cinfo->args [n].size = 4;
625 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
631 case MONO_TYPE_FNPTR:
632 case MONO_TYPE_CLASS:
633 case MONO_TYPE_OBJECT:
634 case MONO_TYPE_STRING:
635 case MONO_TYPE_SZARRAY:
636 case MONO_TYPE_ARRAY:
637 cinfo->args [n].size = sizeof (gpointer);
638 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
641 case MONO_TYPE_GENERICINST:
642 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
643 cinfo->args [n].size = sizeof (gpointer);
644 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
649 case MONO_TYPE_VALUETYPE: {
652 klass = mono_class_from_mono_type (sig->params [i]);
654 size = mono_class_native_size (klass, NULL);
656 size = mono_class_value_size (klass, NULL);
658 if (size == 4 && has_only_a_r4_field (klass)) {
659 cinfo->args [n].size = 4;
661 /* It was 7, now it is 8 in LinuxPPC */
662 if (fr <= PPC_LAST_FPARG_REG) {
663 cinfo->args [n].regtype = RegTypeFP;
664 cinfo->args [n].reg = fr;
666 FP_ALSO_IN_REG (gr ++);
667 ALWAYS_ON_STACK (stack_size += 4);
669 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
670 cinfo->args [n].regtype = RegTypeBase;
671 cinfo->args [n].reg = ppc_sp; /* in the caller*/
678 DEBUG(printf ("load %d bytes struct\n",
679 mono_class_native_size (sig->params [i]->data.klass, NULL)));
680 #if PPC_PASS_STRUCTS_BY_VALUE
682 int align_size = size;
684 align_size += (sizeof (gpointer) - 1);
685 align_size &= ~(sizeof (gpointer) - 1);
686 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
687 cinfo->args [n].regtype = RegTypeStructByVal;
688 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
689 cinfo->args [n].size = 0;
690 cinfo->args [n].vtsize = nwords;
692 int rest = PPC_LAST_ARG_REG - gr + 1;
693 int n_in_regs = rest >= nwords? nwords: rest;
694 cinfo->args [n].size = n_in_regs;
695 cinfo->args [n].vtsize = nwords - n_in_regs;
696 cinfo->args [n].reg = gr;
699 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
700 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
701 stack_size += nwords * sizeof (gpointer);
704 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
705 cinfo->args [n].regtype = RegTypeStructByAddr;
706 cinfo->args [n].vtsize = size;
711 case MONO_TYPE_TYPEDBYREF: {
712 int size = sizeof (MonoTypedRef);
713 /* keep in sync or merge with the valuetype case */
714 #if PPC_PASS_STRUCTS_BY_VALUE
716 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
717 cinfo->args [n].regtype = RegTypeStructByVal;
718 if (gr <= PPC_LAST_ARG_REG) {
719 int rest = PPC_LAST_ARG_REG - gr + 1;
720 int n_in_regs = rest >= nwords? nwords: rest;
721 cinfo->args [n].size = n_in_regs;
722 cinfo->args [n].vtsize = nwords - n_in_regs;
723 cinfo->args [n].reg = gr;
726 cinfo->args [n].size = 0;
727 cinfo->args [n].vtsize = nwords;
729 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
730 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
731 stack_size += nwords * sizeof (gpointer);
734 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
735 cinfo->args [n].regtype = RegTypeStructByAddr;
736 cinfo->args [n].vtsize = size;
743 cinfo->args [n].size = 8;
744 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
748 cinfo->args [n].size = 4;
750 /* It was 7, now it is 8 in LinuxPPC */
751 if (fr <= PPC_LAST_FPARG_REG) {
752 cinfo->args [n].regtype = RegTypeFP;
753 cinfo->args [n].reg = fr;
755 FP_ALSO_IN_REG (gr ++);
756 ALWAYS_ON_STACK (stack_size += 4);
758 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
759 cinfo->args [n].regtype = RegTypeBase;
760 cinfo->args [n].reg = ppc_sp; /* in the caller*/
766 cinfo->args [n].size = 8;
767 /* It was 7, now it is 8 in LinuxPPC */
768 if (fr <= PPC_LAST_FPARG_REG) {
769 cinfo->args [n].regtype = RegTypeFP;
770 cinfo->args [n].reg = fr;
772 FP_ALSO_IN_REG (gr += 2);
773 ALWAYS_ON_STACK (stack_size += 8);
775 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
776 cinfo->args [n].regtype = RegTypeBase;
777 cinfo->args [n].reg = ppc_sp; /* in the caller*/
783 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
788 simpletype = mono_type_get_underlying_type (sig->ret)->type;
789 switch (simpletype) {
790 case MONO_TYPE_BOOLEAN:
801 case MONO_TYPE_FNPTR:
802 case MONO_TYPE_CLASS:
803 case MONO_TYPE_OBJECT:
804 case MONO_TYPE_SZARRAY:
805 case MONO_TYPE_ARRAY:
806 case MONO_TYPE_STRING:
807 cinfo->ret.reg = ppc_r3;
811 cinfo->ret.reg = ppc_r3;
815 cinfo->ret.reg = ppc_f1;
816 cinfo->ret.regtype = RegTypeFP;
818 case MONO_TYPE_GENERICINST:
819 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
820 cinfo->ret.reg = ppc_r3;
824 case MONO_TYPE_VALUETYPE:
826 case MONO_TYPE_TYPEDBYREF:
830 g_error ("Can't handle as return value 0x%x", sig->ret->type);
834 /* align stack size to 16 */
835 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
836 stack_size = (stack_size + 15) & ~15;
838 cinfo->stack_usage = stack_size;
844 * Set var information according to the calling convention. ppc version.
845 * The locals var stuff should most likely be split in another method.
848 mono_arch_allocate_vars (MonoCompile *m)
850 MonoMethodSignature *sig;
851 MonoMethodHeader *header;
853 int i, offset, size, align, curinst;
854 int frame_reg = ppc_sp;
856 m->flags |= MONO_CFG_HAS_SPILLUP;
858 /* allow room for the vararg method args: void* and long/double */
859 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
860 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
861 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
862 * call convs needs to be handled this way.
864 if (m->flags & MONO_CFG_HAS_VARARGS)
865 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
866 /* gtk-sharp and other broken code will dllimport vararg functions even with
867 * non-varargs signatures. Since there is little hope people will get this right
868 * we assume they won't.
870 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
871 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
873 header = mono_method_get_header (m->method);
876 * We use the frame register also for any method that has
877 * exception clauses. This way, when the handlers are called,
878 * the code will reference local variables using the frame reg instead of
879 * the stack pointer: if we had to restore the stack pointer, we'd
880 * corrupt the method frames that are already on the stack (since
881 * filters get called before stack unwinding happens) when the filter
882 * code would call any method (this also applies to finally etc.).
884 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
886 m->frame_reg = frame_reg;
887 if (frame_reg != ppc_sp) {
888 m->used_int_regs |= 1 << frame_reg;
891 sig = mono_method_signature (m->method);
895 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
896 m->ret->opcode = OP_REGVAR;
897 m->ret->inst_c0 = ppc_r3;
899 /* FIXME: handle long and FP values */
900 switch (mono_type_get_underlying_type (sig->ret)->type) {
904 m->ret->opcode = OP_REGVAR;
905 m->ret->inst_c0 = ppc_r3;
909 /* local vars are at a positive offset from the stack pointer */
911 * also note that if the function uses alloca, we use ppc_r31
912 * to point at the local variables.
914 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
915 /* align the offset to 16 bytes: not sure this is needed here */
917 //offset &= ~(16 - 1);
919 /* add parameter area size for called functions */
920 offset += m->param_area;
924 /* allow room to save the return value */
925 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
928 /* the MonoLMF structure is stored just below the stack pointer */
931 /* this stuff should not be needed on ppc and the new jit,
932 * because a call on ppc to the handlers doesn't change the
933 * stack pointer and the jist doesn't manipulate the stack pointer
934 * for operations involving valuetypes.
936 /* reserve space to store the esp */
937 offset += sizeof (gpointer);
939 /* this is a global constant */
940 mono_exc_esp_offset = offset;
942 if (sig->call_convention == MONO_CALL_VARARG) {
943 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
946 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
948 offset += sizeof(gpointer) - 1;
949 offset &= ~(sizeof(gpointer) - 1);
950 inst->inst_offset = offset;
951 inst->opcode = OP_REGOFFSET;
952 inst->inst_basereg = frame_reg;
953 offset += sizeof(gpointer);
954 if (sig->call_convention == MONO_CALL_VARARG)
955 m->sig_cookie += sizeof (gpointer);
958 curinst = m->locals_start;
959 for (i = curinst; i < m->num_varinfo; ++i) {
960 inst = m->varinfo [i];
961 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
964 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
965 * pinvoke wrappers when they call functions returning structure */
966 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
967 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
969 size = mono_type_size (inst->inst_vtype, &align);
972 offset &= ~(align - 1);
973 inst->inst_offset = offset;
974 inst->opcode = OP_REGOFFSET;
975 inst->inst_basereg = frame_reg;
977 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
982 inst = m->args [curinst];
983 if (inst->opcode != OP_REGVAR) {
984 inst->opcode = OP_REGOFFSET;
985 inst->inst_basereg = frame_reg;
986 offset += sizeof (gpointer) - 1;
987 offset &= ~(sizeof (gpointer) - 1);
988 inst->inst_offset = offset;
989 offset += sizeof (gpointer);
990 if (sig->call_convention == MONO_CALL_VARARG)
991 m->sig_cookie += sizeof (gpointer);
996 for (i = 0; i < sig->param_count; ++i) {
997 inst = m->args [curinst];
998 if (inst->opcode != OP_REGVAR) {
999 inst->opcode = OP_REGOFFSET;
1000 inst->inst_basereg = frame_reg;
1001 size = mono_type_size (sig->params [i], &align);
1002 offset += align - 1;
1003 offset &= ~(align - 1);
1004 inst->inst_offset = offset;
1006 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1007 m->sig_cookie += size;
1012 /* align the offset to 16 bytes */
1014 offset &= ~(16 - 1);
1017 m->stack_offset = offset;
1021 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1022 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1026 * take the arguments and generate the arch-specific
1027 * instructions to properly call the function in call.
1028 * This includes pushing, moving arguments to the right register
1030 * Issue: who does the spilling if needed, and when?
1033 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1035 MonoMethodSignature *sig;
1040 sig = call->signature;
1041 n = sig->param_count + sig->hasthis;
1043 cinfo = calculate_sizes (sig, sig->pinvoke);
1044 if (cinfo->struct_ret)
1045 call->used_iregs |= 1 << cinfo->struct_ret;
1047 for (i = 0; i < n; ++i) {
1048 ainfo = cinfo->args + i;
1049 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1051 cfg->disable_aot = TRUE;
1053 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1054 sig_arg->inst_p0 = call->signature;
1056 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1057 arg->inst_imm = cinfo->sig_cookie.offset;
1058 arg->inst_left = sig_arg;
1060 /* prepend, so they get reversed */
1061 arg->next = call->out_args;
1062 call->out_args = arg;
1064 if (is_virtual && i == 0) {
1065 /* the argument will be attached to the call instrucion */
1066 in = call->args [i];
1067 call->used_iregs |= 1 << ainfo->reg;
1069 MONO_INST_NEW (cfg, arg, OP_OUTARG);
1070 in = call->args [i];
1071 arg->cil_code = in->cil_code;
1072 arg->inst_left = in;
1073 arg->inst_call = call;
1074 arg->type = in->type;
1075 /* prepend, we'll need to reverse them later */
1076 arg->next = call->out_args;
1077 call->out_args = arg;
1078 if (ainfo->regtype == RegTypeGeneral) {
1079 arg->backend.reg3 = ainfo->reg;
1080 call->used_iregs |= 1 << ainfo->reg;
1081 if (arg->type == STACK_I8)
1082 call->used_iregs |= 1 << (ainfo->reg + 1);
1083 } else if (ainfo->regtype == RegTypeStructByAddr) {
1084 if (ainfo->offset) {
1085 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1086 arg->opcode = OP_OUTARG_MEMBASE;
1087 ai->reg = ainfo->reg;
1088 ai->size = sizeof (gpointer);
1089 ai->offset = ainfo->offset;
1090 arg->backend.data = ai;
1092 arg->backend.reg3 = ainfo->reg;
1093 call->used_iregs |= 1 << ainfo->reg;
1095 } else if (ainfo->regtype == RegTypeStructByVal) {
1097 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1098 /* mark the used regs */
1099 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1100 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1102 arg->opcode = OP_OUTARG_VT;
1103 ai->reg = ainfo->reg;
1104 ai->size = ainfo->size;
1105 ai->vtsize = ainfo->vtsize;
1106 ai->offset = ainfo->offset;
1107 arg->backend.data = ai;
1108 } else if (ainfo->regtype == RegTypeBase) {
1109 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1110 arg->opcode = OP_OUTARG_MEMBASE;
1111 ai->reg = ainfo->reg;
1112 ai->size = ainfo->size;
1113 ai->offset = ainfo->offset;
1114 arg->backend.data = ai;
1115 } else if (ainfo->regtype == RegTypeFP) {
1116 arg->opcode = OP_OUTARG_R8;
1117 arg->backend.reg3 = ainfo->reg;
1118 call->used_fregs |= 1 << ainfo->reg;
1119 if (ainfo->size == 4) {
1120 arg->opcode = OP_OUTARG_R8;
1121 /* we reduce the precision */
1123 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1124 conv->inst_left = arg->inst_left;
1125 arg->inst_left = conv;*/
1128 g_assert_not_reached ();
1133 * Reverse the call->out_args list.
1136 MonoInst *prev = NULL, *list = call->out_args, *next;
1143 call->out_args = prev;
1145 call->stack_usage = cinfo->stack_usage;
1146 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1147 cfg->flags |= MONO_CFG_HAS_CALLS;
1149 * should set more info in call, such as the stack space
1150 * used by the args that needs to be added back to esp
1158 * Allow tracing to work with this interface (with an optional argument)
1162 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1166 ppc_load (code, ppc_r3, cfg->method);
1167 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1168 ppc_load (code, ppc_r0, func);
1169 ppc_mtlr (code, ppc_r0);
1183 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1186 int save_mode = SAVE_NONE;
1188 MonoMethod *method = cfg->method;
1189 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1190 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1194 offset = code - cfg->native_code;
1195 /* we need about 16 instructions */
1196 if (offset > (cfg->code_size - 16 * 4)) {
1197 cfg->code_size *= 2;
1198 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1199 code = cfg->native_code + offset;
1203 case MONO_TYPE_VOID:
1204 /* special case string .ctor icall */
1205 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1206 save_mode = SAVE_ONE;
1208 save_mode = SAVE_NONE;
1212 save_mode = SAVE_TWO;
1216 save_mode = SAVE_FP;
1218 case MONO_TYPE_VALUETYPE:
1219 save_mode = SAVE_STRUCT;
1222 save_mode = SAVE_ONE;
1226 switch (save_mode) {
1228 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1229 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1230 if (enable_arguments) {
1231 ppc_mr (code, ppc_r5, ppc_r4);
1232 ppc_mr (code, ppc_r4, ppc_r3);
1236 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1237 if (enable_arguments) {
1238 ppc_mr (code, ppc_r4, ppc_r3);
1242 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1243 if (enable_arguments) {
1244 /* FIXME: what reg? */
1245 ppc_fmr (code, ppc_f3, ppc_f1);
1246 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1247 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1251 if (enable_arguments) {
1252 /* FIXME: get the actual address */
1253 ppc_mr (code, ppc_r4, ppc_r3);
1261 ppc_load (code, ppc_r3, cfg->method);
1262 ppc_load (code, ppc_r0, func);
1263 ppc_mtlr (code, ppc_r0);
1266 switch (save_mode) {
1268 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1269 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1272 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1275 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1285 * Conditional branches have a small offset, so if it is likely overflowed,
1286 * we do a branch to the end of the method (uncond branches have much larger
1287 * offsets) where we perform the conditional and jump back unconditionally.
1288 * It's slightly slower, since we add two uncond branches, but it's very simple
1289 * with the current patch implementation and such large methods are likely not
1290 * going to be perf critical anyway.
1295 const char *exception;
1302 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1303 if (ins->flags & MONO_INST_BRLABEL) { \
1304 if (0 && ins->inst_i0->inst_c0) { \
1305 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1307 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1308 ppc_bc (code, (b0), (b1), 0); \
1311 if (0 && ins->inst_true_bb->native_offset) { \
1312 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1314 int br_disp = ins->inst_true_bb->max_offset - offset; \
1315 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1316 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1317 ovfj->data.bb = ins->inst_true_bb; \
1318 ovfj->ip_offset = 0; \
1319 ovfj->b0_cond = (b0); \
1320 ovfj->b1_cond = (b1); \
1321 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1324 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1325 ppc_bc (code, (b0), (b1), 0); \
1330 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1332 /* emit an exception if condition is fail
1334 * We assign the extra code used to throw the implicit exceptions
1335 * to cfg->bb_exit as far as the big branch handling is concerned
1337 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1339 int br_disp = cfg->bb_exit->max_offset - offset; \
1340 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1341 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1342 ovfj->data.exception = (exc_name); \
1343 ovfj->ip_offset = code - cfg->native_code; \
1344 ovfj->b0_cond = (b0); \
1345 ovfj->b1_cond = (b1); \
1346 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1348 cfg->bb_exit->max_offset += 24; \
1350 mono_add_patch_info (cfg, code - cfg->native_code, \
1351 MONO_PATCH_INFO_EXC, exc_name); \
1352 ppc_bcl (code, (b0), (b1), 0); \
1356 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1359 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1361 MonoInst *ins, *last_ins = NULL;
1366 switch (ins->opcode) {
1368 /* remove unnecessary multiplication with 1 */
1369 if (ins->inst_imm == 1) {
1370 if (ins->dreg != ins->sreg1) {
1371 ins->opcode = OP_MOVE;
1373 last_ins->next = ins->next;
1378 int power2 = mono_is_power_of_two (ins->inst_imm);
1380 ins->opcode = OP_SHL_IMM;
1381 ins->inst_imm = power2;
1385 case OP_LOAD_MEMBASE:
1386 case OP_LOADI4_MEMBASE:
1388 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1389 * OP_LOAD_MEMBASE offset(basereg), reg
1391 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1392 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1393 ins->inst_basereg == last_ins->inst_destbasereg &&
1394 ins->inst_offset == last_ins->inst_offset) {
1395 if (ins->dreg == last_ins->sreg1) {
1396 last_ins->next = ins->next;
1400 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1401 ins->opcode = OP_MOVE;
1402 ins->sreg1 = last_ins->sreg1;
1406 * Note: reg1 must be different from the basereg in the second load
1407 * OP_LOAD_MEMBASE offset(basereg), reg1
1408 * OP_LOAD_MEMBASE offset(basereg), reg2
1410 * OP_LOAD_MEMBASE offset(basereg), reg1
1411 * OP_MOVE reg1, reg2
1413 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1414 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1415 ins->inst_basereg != last_ins->dreg &&
1416 ins->inst_basereg == last_ins->inst_basereg &&
1417 ins->inst_offset == last_ins->inst_offset) {
1419 if (ins->dreg == last_ins->dreg) {
1420 last_ins->next = ins->next;
1424 ins->opcode = OP_MOVE;
1425 ins->sreg1 = last_ins->dreg;
1428 //g_assert_not_reached ();
1432 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1433 * OP_LOAD_MEMBASE offset(basereg), reg
1435 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1436 * OP_ICONST reg, imm
1438 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1439 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1440 ins->inst_basereg == last_ins->inst_destbasereg &&
1441 ins->inst_offset == last_ins->inst_offset) {
1442 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1443 ins->opcode = OP_ICONST;
1444 ins->inst_c0 = last_ins->inst_imm;
1445 g_assert_not_reached (); // check this rule
1449 case OP_LOADU1_MEMBASE:
1450 case OP_LOADI1_MEMBASE:
1451 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1452 ins->inst_basereg == last_ins->inst_destbasereg &&
1453 ins->inst_offset == last_ins->inst_offset) {
1454 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1455 ins->sreg1 = last_ins->sreg1;
1458 case OP_LOADU2_MEMBASE:
1459 case OP_LOADI2_MEMBASE:
1460 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1461 ins->inst_basereg == last_ins->inst_destbasereg &&
1462 ins->inst_offset == last_ins->inst_offset) {
1463 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1464 ins->sreg1 = last_ins->sreg1;
1471 ins->opcode = OP_MOVE;
1475 if (ins->dreg == ins->sreg1) {
1477 last_ins->next = ins->next;
1482 * OP_MOVE sreg, dreg
1483 * OP_MOVE dreg, sreg
1485 if (last_ins && last_ins->opcode == OP_MOVE &&
1486 ins->sreg1 == last_ins->dreg &&
1487 ins->dreg == last_ins->sreg1) {
1488 last_ins->next = ins->next;
1497 bb->last_ins = last_ins;
1501 * the branch_b0_table should maintain the order of these
1515 branch_b0_table [] = {
1530 branch_b1_table [] = {
1545 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1549 bb->code = to_insert;
1550 to_insert->next = ins;
1552 to_insert->next = ins->next;
1553 ins->next = to_insert;
1557 #define NEW_INS(cfg,dest,op) do { \
1558 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
1559 (dest)->opcode = (op); \
1560 insert_after_ins (bb, last_ins, (dest)); \
1564 map_to_reg_reg_op (int op)
1573 case OP_COMPARE_IMM:
1589 case OP_LOAD_MEMBASE:
1590 return OP_LOAD_MEMINDEX;
1591 case OP_LOADI4_MEMBASE:
1592 return OP_LOADI4_MEMINDEX;
1593 case OP_LOADU4_MEMBASE:
1594 return OP_LOADU4_MEMINDEX;
1595 case OP_LOADU1_MEMBASE:
1596 return OP_LOADU1_MEMINDEX;
1597 case OP_LOADI2_MEMBASE:
1598 return OP_LOADI2_MEMINDEX;
1599 case OP_LOADU2_MEMBASE:
1600 return OP_LOADU2_MEMINDEX;
1601 case OP_LOADI1_MEMBASE:
1602 return OP_LOADI1_MEMINDEX;
1603 case OP_LOADR4_MEMBASE:
1604 return OP_LOADR4_MEMINDEX;
1605 case OP_LOADR8_MEMBASE:
1606 return OP_LOADR8_MEMINDEX;
1607 case OP_STOREI1_MEMBASE_REG:
1608 return OP_STOREI1_MEMINDEX;
1609 case OP_STOREI2_MEMBASE_REG:
1610 return OP_STOREI2_MEMINDEX;
1611 case OP_STOREI4_MEMBASE_REG:
1612 return OP_STOREI4_MEMINDEX;
1613 case OP_STORE_MEMBASE_REG:
1614 return OP_STORE_MEMINDEX;
1615 case OP_STORER4_MEMBASE_REG:
1616 return OP_STORER4_MEMINDEX;
1617 case OP_STORER8_MEMBASE_REG:
1618 return OP_STORER8_MEMINDEX;
1619 case OP_STORE_MEMBASE_IMM:
1620 return OP_STORE_MEMBASE_REG;
1621 case OP_STOREI1_MEMBASE_IMM:
1622 return OP_STOREI1_MEMBASE_REG;
1623 case OP_STOREI2_MEMBASE_IMM:
1624 return OP_STOREI2_MEMBASE_REG;
1625 case OP_STOREI4_MEMBASE_IMM:
1626 return OP_STOREI4_MEMBASE_REG;
1628 g_assert_not_reached ();
1631 #define compare_opcode_is_unsigned(opcode) \
1632 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
1633 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
1634 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1636 * Remove from the instruction list the instructions that can't be
1637 * represented with very simple instructions with no register
1641 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1643 MonoInst *ins, *next, *temp, *last_ins = NULL;
1646 /* setup the virtual reg allocator */
1647 if (bb->max_vreg > cfg->rs->next_vreg)
1648 cfg->rs->next_vreg = bb->max_vreg;
1653 switch (ins->opcode) {
1656 if (!ppc_is_imm16 (ins->inst_imm)) {
1657 NEW_INS (cfg, temp, OP_ICONST);
1658 temp->inst_c0 = ins->inst_imm;
1659 temp->dreg = mono_regstate_next_int (cfg->rs);
1660 ins->sreg2 = temp->dreg;
1661 ins->opcode = map_to_reg_reg_op (ins->opcode);
1665 if (!ppc_is_imm16 (-ins->inst_imm)) {
1666 NEW_INS (cfg, temp, OP_ICONST);
1667 temp->inst_c0 = ins->inst_imm;
1668 temp->dreg = mono_regstate_next_int (cfg->rs);
1669 ins->sreg2 = temp->dreg;
1670 ins->opcode = map_to_reg_reg_op (ins->opcode);
1676 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1677 NEW_INS (cfg, temp, OP_ICONST);
1678 temp->inst_c0 = ins->inst_imm;
1679 temp->dreg = mono_regstate_next_int (cfg->rs);
1680 ins->sreg2 = temp->dreg;
1681 ins->opcode = map_to_reg_reg_op (ins->opcode);
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->sreg2 = temp->dreg;
1691 ins->opcode = map_to_reg_reg_op (ins->opcode);
1693 case OP_COMPARE_IMM:
1694 if (compare_opcode_is_unsigned (ins->next->opcode)) {
1695 if (!ppc_is_uimm16 (ins->inst_imm)) {
1696 NEW_INS (cfg, temp, OP_ICONST);
1697 temp->inst_c0 = ins->inst_imm;
1698 temp->dreg = mono_regstate_next_int (cfg->rs);
1699 ins->sreg2 = temp->dreg;
1700 ins->opcode = map_to_reg_reg_op (ins->opcode);
1703 if (!ppc_is_imm16 (ins->inst_imm)) {
1704 NEW_INS (cfg, temp, OP_ICONST);
1705 temp->inst_c0 = ins->inst_imm;
1706 temp->dreg = mono_regstate_next_int (cfg->rs);
1707 ins->sreg2 = temp->dreg;
1708 ins->opcode = map_to_reg_reg_op (ins->opcode);
1713 if (ins->inst_imm == 1) {
1714 ins->opcode = OP_MOVE;
1717 if (ins->inst_imm == 0) {
1718 ins->opcode = OP_ICONST;
1722 imm = mono_is_power_of_two (ins->inst_imm);
1724 ins->opcode = OP_SHL_IMM;
1725 ins->inst_imm = imm;
1728 if (!ppc_is_imm16 (ins->inst_imm)) {
1729 NEW_INS (cfg, temp, OP_ICONST);
1730 temp->inst_c0 = ins->inst_imm;
1731 temp->dreg = mono_regstate_next_int (cfg->rs);
1732 ins->sreg2 = temp->dreg;
1733 ins->opcode = map_to_reg_reg_op (ins->opcode);
1736 case OP_LOAD_MEMBASE:
1737 case OP_LOADI4_MEMBASE:
1738 case OP_LOADU4_MEMBASE:
1739 case OP_LOADI2_MEMBASE:
1740 case OP_LOADU2_MEMBASE:
1741 case OP_LOADI1_MEMBASE:
1742 case OP_LOADU1_MEMBASE:
1743 case OP_LOADR4_MEMBASE:
1744 case OP_LOADR8_MEMBASE:
1745 case OP_STORE_MEMBASE_REG:
1746 case OP_STOREI4_MEMBASE_REG:
1747 case OP_STOREI2_MEMBASE_REG:
1748 case OP_STOREI1_MEMBASE_REG:
1749 case OP_STORER4_MEMBASE_REG:
1750 case OP_STORER8_MEMBASE_REG:
1751 /* we can do two things: load the immed in a register
1752 * and use an indexed load, or see if the immed can be
1753 * represented as an ad_imm + a load with a smaller offset
1754 * that fits. We just do the first for now, optimize later.
1756 if (ppc_is_imm16 (ins->inst_offset))
1758 NEW_INS (cfg, temp, OP_ICONST);
1759 temp->inst_c0 = ins->inst_offset;
1760 temp->dreg = mono_regstate_next_int (cfg->rs);
1761 ins->sreg2 = temp->dreg;
1762 ins->opcode = map_to_reg_reg_op (ins->opcode);
1764 case OP_STORE_MEMBASE_IMM:
1765 case OP_STOREI1_MEMBASE_IMM:
1766 case OP_STOREI2_MEMBASE_IMM:
1767 case OP_STOREI4_MEMBASE_IMM:
1768 NEW_INS (cfg, temp, OP_ICONST);
1769 temp->inst_c0 = ins->inst_imm;
1770 temp->dreg = mono_regstate_next_int (cfg->rs);
1771 ins->sreg1 = temp->dreg;
1772 ins->opcode = map_to_reg_reg_op (ins->opcode);
1774 goto loop_start; /* make it handle the possibly big ins->inst_offset */
1779 bb->last_ins = last_ins;
1780 bb->max_vreg = cfg->rs->next_vreg;
1785 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1789 mono_arch_lowering_pass (cfg, bb);
1790 mono_local_regalloc (cfg, bb);
1794 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1796 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1797 ppc_fctiwz (code, ppc_f0, sreg);
1798 ppc_stfd (code, ppc_f0, -8, ppc_sp);
1799 ppc_lwz (code, dreg, -4, ppc_sp);
1802 ppc_andid (code, dreg, dreg, 0xff);
1804 ppc_andid (code, dreg, dreg, 0xffff);
1807 ppc_extsb (code, dreg, dreg);
1809 ppc_extsh (code, dreg, dreg);
1814 static unsigned char*
1815 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1818 int sreg = tree->sreg1;
1819 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1820 if (tree->flags & MONO_INST_INIT) {
1822 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1823 x86_push_reg (code, X86_EAX);
1826 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1827 x86_push_reg (code, X86_ECX);
1830 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1831 x86_push_reg (code, X86_EDI);
1835 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1836 if (sreg != X86_ECX)
1837 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1838 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1840 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1842 x86_prefix (code, X86_REP_PREFIX);
1845 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1846 x86_pop_reg (code, X86_EDI);
1847 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1848 x86_pop_reg (code, X86_ECX);
1849 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1850 x86_pop_reg (code, X86_EAX);
1863 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1866 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1867 PatchData *pdata = (PatchData*)user_data;
1868 guchar *code = data;
1869 guint32 *thunks = data;
1870 guint32 *endthunks = (guint32*)(code + bsize);
1874 int difflow, diffhigh;
1876 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1877 difflow = (char*)pdata->code - (char*)thunks;
1878 diffhigh = (char*)pdata->code - (char*)endthunks;
1879 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1882 templ = (guchar*)load;
1883 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1884 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1886 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1887 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1888 while (thunks < endthunks) {
1889 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1890 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1891 ppc_patch (pdata->code, (guchar*)thunks);
1892 mono_arch_flush_icache (pdata->code, 4);
1895 static int num_thunks = 0;
1897 if ((num_thunks % 20) == 0)
1898 g_print ("num_thunks lookup: %d\n", num_thunks);
1901 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1902 /* found a free slot instead: emit thunk */
1903 code = (guchar*)thunks;
1904 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1905 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1906 ppc_mtctr (code, ppc_r0);
1907 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1908 mono_arch_flush_icache ((guchar*)thunks, 16);
1910 ppc_patch (pdata->code, (guchar*)thunks);
1911 mono_arch_flush_icache (pdata->code, 4);
1914 static int num_thunks = 0;
1916 if ((num_thunks % 20) == 0)
1917 g_print ("num_thunks: %d\n", num_thunks);
1921 /* skip 16 bytes, the size of the thunk */
1925 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1931 handle_thunk (int absolute, guchar *code, guchar *target) {
1932 MonoDomain *domain = mono_domain_get ();
1936 pdata.target = target;
1937 pdata.absolute = absolute;
1940 mono_domain_lock (domain);
1941 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1944 /* this uses the first available slot */
1946 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1948 mono_domain_unlock (domain);
1950 if (pdata.found != 1)
1951 g_print ("thunk failed for %p from %p\n", target, code);
1952 g_assert (pdata.found == 1);
1956 ppc_patch (guchar *code, guchar *target)
1958 guint32 ins = *(guint32*)code;
1959 guint32 prim = ins >> 26;
1962 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1964 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1965 gint diff = target - code;
1967 if (diff <= 33554431){
1968 ins = (18 << 26) | (diff) | (ins & 1);
1969 *(guint32*)code = ins;
1973 /* diff between 0 and -33554432 */
1974 if (diff >= -33554432){
1975 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1976 *(guint32*)code = ins;
1981 if ((glong)target >= 0){
1982 if ((glong)target <= 33554431){
1983 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1984 *(guint32*)code = ins;
1988 if ((glong)target >= -33554432){
1989 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1990 *(guint32*)code = ins;
1995 handle_thunk (TRUE, code, target);
1998 g_assert_not_reached ();
2005 guint32 li = (guint32)target;
2006 ins = (ins & 0xffff0000) | (ins & 3);
2007 ovf = li & 0xffff0000;
2008 if (ovf != 0 && ovf != 0xffff0000)
2009 g_assert_not_reached ();
2012 // FIXME: assert the top bits of li are 0
2014 gint diff = target - code;
2015 ins = (ins & 0xffff0000) | (ins & 3);
2016 ovf = diff & 0xffff0000;
2017 if (ovf != 0 && ovf != 0xffff0000)
2018 g_assert_not_reached ();
2022 *(guint32*)code = ins;
2026 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2028 /* the trampoline code will try to patch the blrl, blr, bcctr */
2029 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2032 /* this is the lis/ori/mtlr/blrl sequence */
2033 seq = (guint32*)code;
2034 g_assert ((seq [0] >> 26) == 15);
2035 g_assert ((seq [1] >> 26) == 24);
2036 g_assert ((seq [2] >> 26) == 31);
2037 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2038 /* FIXME: make this thread safe */
2039 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2040 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2041 mono_arch_flush_icache (code - 8, 8);
2043 g_assert_not_reached ();
2045 // g_print ("patched with 0x%08x\n", ins);
2049 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2054 guint8 *code = cfg->native_code + cfg->code_len;
2055 MonoInst *last_ins = NULL;
2056 guint last_offset = 0;
2059 if (cfg->opt & MONO_OPT_PEEPHOLE)
2060 peephole_pass (cfg, bb);
2062 /* we don't align basic blocks of loops on ppc */
2064 if (cfg->verbose_level > 2)
2065 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2067 cpos = bb->max_offset;
2069 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2070 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2071 //g_assert (!mono_compile_aot);
2074 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2075 /* this is not thread save, but good enough */
2076 /* fixme: howto handle overflows? */
2077 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2082 offset = code - cfg->native_code;
2084 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2086 if (offset > (cfg->code_size - max_len - 16)) {
2087 cfg->code_size *= 2;
2088 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2089 code = cfg->native_code + offset;
2091 // if (ins->cil_code)
2092 // g_print ("cil code\n");
2093 mono_debug_record_line_number (cfg, ins, offset);
2095 switch (ins->opcode) {
2097 emit_tls_access (code, ins->dreg, ins->inst_offset);
2100 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2101 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2102 ppc_mr (code, ppc_r4, ppc_r0);
2105 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2106 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2107 ppc_mr (code, ppc_r4, ppc_r0);
2109 case OP_MEMORY_BARRIER:
2112 case OP_STOREI1_MEMBASE_REG:
2113 if (ppc_is_imm16 (ins->inst_offset)) {
2114 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2116 g_assert_not_reached ();
2119 case OP_STOREI2_MEMBASE_REG:
2120 if (ppc_is_imm16 (ins->inst_offset)) {
2121 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2123 g_assert_not_reached ();
2126 case OP_STORE_MEMBASE_REG:
2127 case OP_STOREI4_MEMBASE_REG:
2128 if (ppc_is_imm16 (ins->inst_offset)) {
2129 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2131 g_assert_not_reached ();
2134 case OP_STOREI1_MEMINDEX:
2135 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2137 case OP_STOREI2_MEMINDEX:
2138 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2140 case OP_STORE_MEMINDEX:
2141 case OP_STOREI4_MEMINDEX:
2142 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2147 g_assert_not_reached ();
2148 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2151 g_assert_not_reached ();
2153 case OP_LOAD_MEMBASE:
2154 case OP_LOADI4_MEMBASE:
2155 case OP_LOADU4_MEMBASE:
2156 if (ppc_is_imm16 (ins->inst_offset)) {
2157 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2159 g_assert_not_reached ();
2162 case OP_LOADI1_MEMBASE:
2163 case OP_LOADU1_MEMBASE:
2164 if (ppc_is_imm16 (ins->inst_offset)) {
2165 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2167 g_assert_not_reached ();
2169 if (ins->opcode == OP_LOADI1_MEMBASE)
2170 ppc_extsb (code, ins->dreg, ins->dreg);
2172 case OP_LOADU2_MEMBASE:
2173 if (ppc_is_imm16 (ins->inst_offset)) {
2174 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2176 g_assert_not_reached ();
2179 case OP_LOADI2_MEMBASE:
2180 if (ppc_is_imm16 (ins->inst_offset)) {
2181 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2183 g_assert_not_reached ();
2186 case OP_LOAD_MEMINDEX:
2187 case OP_LOADI4_MEMINDEX:
2188 case OP_LOADU4_MEMINDEX:
2189 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2191 case OP_LOADU2_MEMINDEX:
2192 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2194 case OP_LOADI2_MEMINDEX:
2195 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2197 case OP_LOADU1_MEMINDEX:
2198 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2200 case OP_LOADI1_MEMINDEX:
2201 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2202 ppc_extsb (code, ins->dreg, ins->dreg);
2205 ppc_extsb (code, ins->dreg, ins->sreg1);
2208 ppc_extsh (code, ins->dreg, ins->sreg1);
2211 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2214 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2217 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2218 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2220 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2222 case OP_COMPARE_IMM:
2223 if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2224 if (ppc_is_uimm16 (ins->inst_imm)) {
2225 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2227 g_assert_not_reached ();
2230 if (ppc_is_imm16 (ins->inst_imm)) {
2231 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2233 g_assert_not_reached ();
2241 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2244 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2247 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2250 if (ppc_is_imm16 (ins->inst_imm)) {
2251 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2253 g_assert_not_reached ();
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 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2266 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2267 ppc_mfspr (code, ppc_r0, ppc_xer);
2268 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2269 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2271 case CEE_ADD_OVF_UN:
2272 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2274 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2275 ppc_mfspr (code, ppc_r0, ppc_xer);
2276 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2277 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2280 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2282 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2283 ppc_mfspr (code, ppc_r0, ppc_xer);
2284 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2285 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2287 case CEE_SUB_OVF_UN:
2288 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2290 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2291 ppc_mfspr (code, ppc_r0, ppc_xer);
2292 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2293 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2295 case OP_ADD_OVF_CARRY:
2296 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2298 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2299 ppc_mfspr (code, ppc_r0, ppc_xer);
2300 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2301 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2303 case OP_ADD_OVF_UN_CARRY:
2304 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2306 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2307 ppc_mfspr (code, ppc_r0, ppc_xer);
2308 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2309 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2311 case OP_SUB_OVF_CARRY:
2312 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2314 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2315 ppc_mfspr (code, ppc_r0, ppc_xer);
2316 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2317 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2319 case OP_SUB_OVF_UN_CARRY:
2320 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2322 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2323 ppc_mfspr (code, ppc_r0, ppc_xer);
2324 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2325 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2328 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2331 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2334 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2337 // we add the negated value
2338 if (ppc_is_imm16 (-ins->inst_imm))
2339 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2341 g_assert_not_reached ();
2345 g_assert (ppc_is_imm16 (ins->inst_imm));
2346 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2349 ppc_subfze (code, ins->dreg, ins->sreg1);
2352 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2353 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2356 if (!(ins->inst_imm & 0xffff0000)) {
2357 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2358 } else if (!(ins->inst_imm & 0xffff)) {
2359 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2361 g_assert_not_reached ();
2365 guint32 *divisor_is_m1;
2366 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2368 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2369 divisor_is_m1 = code;
2370 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2371 ppc_lis (code, ppc_r11, 0x8000);
2372 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2373 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2374 ppc_patch (divisor_is_m1, code);
2375 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2377 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2378 ppc_mfspr (code, ppc_r0, ppc_xer);
2379 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2380 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2384 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2385 ppc_mfspr (code, ppc_r0, ppc_xer);
2386 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2387 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2390 g_assert_not_reached ();
2392 ppc_load (code, ppc_r11, ins->inst_imm);
2393 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2394 ppc_mfspr (code, ppc_r0, ppc_xer);
2395 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2396 /* FIXME: use OverflowException for 0x80000000/-1 */
2397 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2401 guint32 *divisor_is_m1;
2402 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2403 divisor_is_m1 = code;
2404 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2405 ppc_lis (code, ppc_r11, 0x8000);
2406 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2407 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2408 ppc_patch (divisor_is_m1, code);
2409 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2410 ppc_mfspr (code, ppc_r0, ppc_xer);
2411 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2412 /* FIXME: use OverflowException for 0x80000000/-1 */
2413 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2414 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2415 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2419 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2420 ppc_mfspr (code, ppc_r0, ppc_xer);
2421 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2422 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2423 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2424 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2427 g_assert_not_reached ();
2429 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2432 if (!(ins->inst_imm & 0xffff0000)) {
2433 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2434 } else if (!(ins->inst_imm & 0xffff)) {
2435 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2437 g_assert_not_reached ();
2441 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2444 if (!(ins->inst_imm & 0xffff0000)) {
2445 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2446 } else if (!(ins->inst_imm & 0xffff)) {
2447 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2449 g_assert_not_reached ();
2453 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2456 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2459 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2462 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2466 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2468 ppc_mr (code, ins->dreg, ins->sreg1);
2471 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2474 ppc_not (code, ins->dreg, ins->sreg1);
2477 ppc_neg (code, ins->dreg, ins->sreg1);
2480 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2483 if (ppc_is_imm16 (ins->inst_imm)) {
2484 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2486 g_assert_not_reached ();
2490 /* we annot use mcrxr, since it's not implemented on some processors
2491 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2493 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2494 ppc_mfspr (code, ppc_r0, ppc_xer);
2495 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2496 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2498 case CEE_MUL_OVF_UN:
2499 /* we first multiply to get the high word and compare to 0
2500 * to set the flags, then the result is discarded and then
2501 * we multiply to get the lower * bits result
2503 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2504 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2505 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2506 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2510 ppc_load (code, ins->dreg, ins->inst_c0);
2513 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2514 ppc_lis (code, ins->dreg, 0);
2515 ppc_ori (code, ins->dreg, ins->dreg, 0);
2521 ppc_mr (code, ins->dreg, ins->sreg1);
2524 int saved = ins->sreg1;
2525 if (ins->sreg1 == ppc_r3) {
2526 ppc_mr (code, ppc_r0, ins->sreg1);
2529 if (ins->sreg2 != ppc_r3)
2530 ppc_mr (code, ppc_r3, ins->sreg2);
2531 if (saved != ppc_r4)
2532 ppc_mr (code, ppc_r4, saved);
2537 ppc_fmr (code, ins->dreg, ins->sreg1);
2539 case OP_FCONV_TO_R4:
2540 ppc_frsp (code, ins->dreg, ins->sreg1);
2546 * Keep in sync with mono_arch_emit_epilog
2548 g_assert (!cfg->method->save_lmf);
2549 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2550 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2551 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2553 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2554 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2556 ppc_mtlr (code, ppc_r0);
2558 if (ppc_is_imm16 (cfg->stack_usage)) {
2559 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2561 ppc_load (code, ppc_r11, cfg->stack_usage);
2562 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2564 if (!cfg->method->save_lmf) {
2565 /*for (i = 31; i >= 14; --i) {
2566 if (cfg->used_float_regs & (1 << i)) {
2567 pos += sizeof (double);
2568 ppc_lfd (code, i, -pos, cfg->frame_reg);
2571 for (i = 31; i >= 13; --i) {
2572 if (cfg->used_int_regs & (1 << i)) {
2573 pos += sizeof (gulong);
2574 ppc_lwz (code, i, -pos, cfg->frame_reg);
2578 /* FIXME restore from MonoLMF: though this can't happen yet */
2580 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2585 /* ensure ins->sreg1 is not NULL */
2586 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2589 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2590 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2592 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2593 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2595 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2603 call = (MonoCallInst*)ins;
2604 if (ins->flags & MONO_INST_HAS_METHOD)
2605 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2607 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
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);
2620 case OP_VOIDCALL_REG:
2622 ppc_mtlr (code, ins->sreg1);
2625 case OP_FCALL_MEMBASE:
2626 case OP_LCALL_MEMBASE:
2627 case OP_VCALL_MEMBASE:
2628 case OP_VOIDCALL_MEMBASE:
2629 case OP_CALL_MEMBASE:
2630 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2631 ppc_mtlr (code, ppc_r0);
2635 g_assert_not_reached ();
2638 guint32 * zero_loop_jump, * zero_loop_start;
2639 /* keep alignment */
2640 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2641 int area_offset = alloca_waste;
2643 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2644 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2645 /* use ctr to store the number of words to 0 if needed */
2646 if (ins->flags & MONO_INST_INIT) {
2647 /* we zero 4 bytes at a time:
2648 * we add 7 instead of 3 so that we set the counter to
2649 * at least 1, otherwise the bdnz instruction will make
2650 * it negative and iterate billions of times.
2652 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2653 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2654 ppc_mtctr (code, ppc_r0);
2656 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2657 ppc_neg (code, ppc_r11, ppc_r11);
2658 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2660 if (ins->flags & MONO_INST_INIT) {
2661 /* adjust the dest reg by -4 so we can use stwu */
2662 /* we actually adjust -8 because we let the loop
2665 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2666 ppc_li (code, ppc_r11, 0);
2667 zero_loop_start = code;
2668 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2669 zero_loop_jump = code;
2670 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2671 ppc_patch (zero_loop_jump, zero_loop_start);
2673 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2681 ppc_mr (code, ppc_r3, ins->sreg1);
2682 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2683 (gpointer)"mono_arch_throw_exception");
2684 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2685 ppc_lis (code, ppc_r0, 0);
2686 ppc_ori (code, ppc_r0, ppc_r0, 0);
2687 ppc_mtlr (code, ppc_r0);
2696 ppc_mr (code, ppc_r3, ins->sreg1);
2697 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
2698 (gpointer)"mono_arch_rethrow_exception");
2699 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2700 ppc_lis (code, ppc_r0, 0);
2701 ppc_ori (code, ppc_r0, ppc_r0, 0);
2702 ppc_mtlr (code, ppc_r0);
2709 case OP_START_HANDLER:
2710 ppc_mflr (code, ppc_r0);
2711 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2712 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2714 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2715 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2719 if (ins->sreg1 != ppc_r3)
2720 ppc_mr (code, ppc_r3, ins->sreg1);
2721 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2722 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2724 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2725 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2727 ppc_mtlr (code, ppc_r0);
2731 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2732 ppc_mtlr (code, ppc_r0);
2735 case OP_CALL_HANDLER:
2736 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2740 ins->inst_c0 = code - cfg->native_code;
2743 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2744 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2746 if (ins->flags & MONO_INST_BRLABEL) {
2747 /*if (ins->inst_i0->inst_c0) {
2749 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2751 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2755 /*if (ins->inst_target_bb->native_offset) {
2757 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
2759 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2765 ppc_mtctr (code, ins->sreg1);
2766 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2769 ppc_li (code, ins->dreg, 0);
2770 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2771 ppc_li (code, ins->dreg, 1);
2775 ppc_li (code, ins->dreg, 1);
2776 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2777 ppc_li (code, ins->dreg, 0);
2781 ppc_li (code, ins->dreg, 1);
2782 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2783 ppc_li (code, ins->dreg, 0);
2785 case OP_COND_EXC_EQ:
2786 case OP_COND_EXC_NE_UN:
2787 case OP_COND_EXC_LT:
2788 case OP_COND_EXC_LT_UN:
2789 case OP_COND_EXC_GT:
2790 case OP_COND_EXC_GT_UN:
2791 case OP_COND_EXC_GE:
2792 case OP_COND_EXC_GE_UN:
2793 case OP_COND_EXC_LE:
2794 case OP_COND_EXC_LE_UN:
2795 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2798 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2800 /*ppc_mfspr (code, ppc_r0, ppc_xer);
2801 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2802 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2804 case OP_COND_EXC_OV:
2805 /*ppc_mcrxr (code, 0);
2806 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2808 case OP_COND_EXC_NC:
2809 case OP_COND_EXC_NO:
2810 g_assert_not_reached ();
2822 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2825 /* floating point opcodes */
2827 ppc_load (code, ppc_r11, ins->inst_p0);
2828 ppc_lfd (code, ins->dreg, 0, ppc_r11);
2831 ppc_load (code, ppc_r11, ins->inst_p0);
2832 ppc_lfs (code, ins->dreg, 0, ppc_r11);
2834 case OP_STORER8_MEMBASE_REG:
2835 if (ppc_is_imm16 (ins->inst_offset)) {
2836 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2838 g_assert_not_reached ();
2841 case OP_LOADR8_MEMBASE:
2842 if (ppc_is_imm16 (ins->inst_offset)) {
2843 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2845 g_assert_not_reached ();
2848 case OP_STORER4_MEMBASE_REG:
2849 ppc_frsp (code, ins->sreg1, ins->sreg1);
2850 if (ppc_is_imm16 (ins->inst_offset)) {
2851 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2853 g_assert_not_reached ();
2856 case OP_LOADR4_MEMBASE:
2857 if (ppc_is_imm16 (ins->inst_offset)) {
2858 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2860 g_assert_not_reached ();
2863 case OP_LOADR4_MEMINDEX:
2864 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2866 case OP_LOADR8_MEMINDEX:
2867 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2869 case OP_STORER4_MEMINDEX:
2870 ppc_frsp (code, ins->sreg1, ins->sreg1);
2871 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2873 case OP_STORER8_MEMINDEX:
2874 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2876 case CEE_CONV_R_UN: {
2877 static const guint64 adjust_val = 0x4330000000000000ULL;
2878 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2879 ppc_stw (code, ppc_r0, -8, ppc_sp);
2880 ppc_stw (code, ins->sreg1, -4, ppc_sp);
2881 ppc_load (code, ppc_r11, &adjust_val);
2882 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2883 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2884 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2887 case CEE_CONV_R4: /* FIXME: change precision */
2889 static const guint64 adjust_val = 0x4330000080000000ULL;
2890 // addis is special for ppc_r0
2891 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2892 ppc_stw (code, ppc_r0, -8, ppc_sp);
2893 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2894 ppc_stw (code, ppc_r11, -4, ppc_sp);
2895 ppc_lfd (code, ins->dreg, -8, ppc_sp);
2896 ppc_load (code, ppc_r11, &adjust_val);
2897 ppc_lfd (code, ppc_f0, 0, ppc_r11);
2898 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2901 case OP_FCONV_TO_I1:
2902 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2904 case OP_FCONV_TO_U1:
2905 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2907 case OP_FCONV_TO_I2:
2908 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2910 case OP_FCONV_TO_U2:
2911 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2913 case OP_FCONV_TO_I4:
2915 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2917 case OP_FCONV_TO_U4:
2919 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2921 case OP_FCONV_TO_I8:
2922 case OP_FCONV_TO_U8:
2923 g_assert_not_reached ();
2924 /* Implemented as helper calls */
2926 case OP_LCONV_TO_R_UN:
2927 g_assert_not_reached ();
2928 /* Implemented as helper calls */
2930 case OP_LCONV_TO_OVF_I: {
2931 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2932 // Check if its negative
2933 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2934 negative_branch = code;
2935 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2936 // Its positive msword == 0
2937 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2938 msword_positive_branch = code;
2939 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2941 ovf_ex_target = code;
2942 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2944 ppc_patch (negative_branch, code);
2945 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2946 msword_negative_branch = code;
2947 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2948 ppc_patch (msword_negative_branch, ovf_ex_target);
2950 ppc_patch (msword_positive_branch, code);
2951 if (ins->dreg != ins->sreg1)
2952 ppc_mr (code, ins->dreg, ins->sreg1);
2956 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2959 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2962 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2965 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2968 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2971 ppc_fneg (code, ins->dreg, ins->sreg1);
2975 g_assert_not_reached ();
2978 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2981 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2982 ppc_li (code, ins->dreg, 0);
2983 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2984 ppc_li (code, ins->dreg, 1);
2987 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2988 ppc_li (code, ins->dreg, 1);
2989 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2990 ppc_li (code, ins->dreg, 0);
2993 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2994 ppc_li (code, ins->dreg, 1);
2995 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2996 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2997 ppc_li (code, ins->dreg, 0);
3000 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3001 ppc_li (code, ins->dreg, 1);
3002 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3003 ppc_li (code, ins->dreg, 0);
3006 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3007 ppc_li (code, ins->dreg, 1);
3008 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3009 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3010 ppc_li (code, ins->dreg, 0);
3013 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3016 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3019 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3020 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3023 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3024 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3027 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3028 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3031 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3032 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3035 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3036 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3039 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3042 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3043 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3046 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3049 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3050 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3051 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3052 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3053 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3054 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3058 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3059 g_assert_not_reached ();
3062 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3063 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3064 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3065 g_assert_not_reached ();
3071 last_offset = offset;
3076 cfg->code_len = code - cfg->native_code;
3080 mono_arch_register_lowlevel_calls (void)
3084 #define patch_lis_ori(ip,val) do {\
3085 guint16 *__lis_ori = (guint16*)(ip); \
3086 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3087 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3091 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3093 MonoJumpInfo *patch_info;
3095 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3096 unsigned char *ip = patch_info->ip.i + code;
3097 const unsigned char *target;
3099 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3101 switch (patch_info->type) {
3102 case MONO_PATCH_INFO_IP:
3103 patch_lis_ori (ip, ip);
3105 case MONO_PATCH_INFO_METHOD_REL:
3106 g_assert_not_reached ();
3107 *((gpointer *)(ip)) = code + patch_info->data.offset;
3109 case MONO_PATCH_INFO_SWITCH: {
3110 gpointer *table = (gpointer *)patch_info->data.table->table;
3113 patch_lis_ori (ip, table);
3115 for (i = 0; i < patch_info->data.table->table_size; i++) {
3116 table [i] = (int)patch_info->data.table->table [i] + code;
3118 /* we put into the table the absolute address, no need for ppc_patch in this case */
3121 case MONO_PATCH_INFO_METHODCONST:
3122 case MONO_PATCH_INFO_CLASS:
3123 case MONO_PATCH_INFO_IMAGE:
3124 case MONO_PATCH_INFO_FIELD:
3125 case MONO_PATCH_INFO_VTABLE:
3126 case MONO_PATCH_INFO_IID:
3127 case MONO_PATCH_INFO_SFLDA:
3128 case MONO_PATCH_INFO_LDSTR:
3129 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3130 case MONO_PATCH_INFO_LDTOKEN:
3131 /* from OP_AOTCONST : lis + ori */
3132 patch_lis_ori (ip, target);
3134 case MONO_PATCH_INFO_R4:
3135 case MONO_PATCH_INFO_R8:
3136 g_assert_not_reached ();
3137 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3139 case MONO_PATCH_INFO_EXC_NAME:
3140 g_assert_not_reached ();
3141 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3143 case MONO_PATCH_INFO_NONE:
3144 case MONO_PATCH_INFO_BB_OVF:
3145 case MONO_PATCH_INFO_EXC_OVF:
3146 /* everything is dealt with at epilog output time */
3151 ppc_patch (ip, target);
3156 * Stack frame layout:
3158 * ------------------- sp
3159 * MonoLMF structure or saved registers
3160 * -------------------
3162 * -------------------
3164 * -------------------
3165 * optional 8 bytes for tracing
3166 * -------------------
3167 * param area size is cfg->param_area
3168 * -------------------
3169 * linkage area size is PPC_STACK_PARAM_OFFSET
3170 * ------------------- sp
3174 mono_arch_emit_prolog (MonoCompile *cfg)
3176 MonoMethod *method = cfg->method;
3178 MonoMethodSignature *sig;
3180 int alloc_size, pos, max_offset, i;
3186 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3189 sig = mono_method_signature (method);
3190 cfg->code_size = 256 + sig->param_count * 20;
3191 code = cfg->native_code = g_malloc (cfg->code_size);
3193 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3194 ppc_mflr (code, ppc_r0);
3195 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3198 alloc_size = cfg->stack_offset;
3201 if (!method->save_lmf) {
3202 /*for (i = 31; i >= 14; --i) {
3203 if (cfg->used_float_regs & (1 << i)) {
3204 pos += sizeof (gdouble);
3205 ppc_stfd (code, i, -pos, ppc_sp);
3208 for (i = 31; i >= 13; --i) {
3209 if (cfg->used_int_regs & (1 << i)) {
3210 pos += sizeof (gulong);
3211 ppc_stw (code, i, -pos, ppc_sp);
3216 pos += sizeof (MonoLMF);
3218 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3219 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3220 for (i = 14; i < 32; i++) {
3221 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3225 // align to PPC_STACK_ALIGNMENT bytes
3226 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3227 alloc_size += PPC_STACK_ALIGNMENT - 1;
3228 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3231 cfg->stack_usage = alloc_size;
3232 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3234 if (ppc_is_imm16 (-alloc_size)) {
3235 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3237 ppc_load (code, ppc_r11, -alloc_size);
3238 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3241 if (cfg->frame_reg != ppc_sp)
3242 ppc_mr (code, cfg->frame_reg, ppc_sp);
3244 /* compute max_offset in order to use short forward jumps
3245 * we always do it on ppc because the immediate displacement
3246 * for jumps is too small
3249 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3250 MonoInst *ins = bb->code;
3251 bb->max_offset = max_offset;
3253 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3257 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3262 /* load arguments allocated to register from the stack */
3265 cinfo = calculate_sizes (sig, sig->pinvoke);
3267 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3268 ArgInfo *ainfo = &cinfo->ret;
3270 if (ppc_is_imm16 (inst->inst_offset)) {
3271 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3273 ppc_load (code, ppc_r11, inst->inst_offset);
3274 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3277 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3278 ArgInfo *ainfo = cinfo->args + i;
3279 inst = cfg->args [pos];
3281 if (cfg->verbose_level > 2)
3282 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3283 if (inst->opcode == OP_REGVAR) {
3284 if (ainfo->regtype == RegTypeGeneral)
3285 ppc_mr (code, inst->dreg, ainfo->reg);
3286 else if (ainfo->regtype == RegTypeFP)
3287 ppc_fmr (code, inst->dreg, ainfo->reg);
3288 else if (ainfo->regtype == RegTypeBase) {
3289 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3290 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3292 g_assert_not_reached ();
3294 if (cfg->verbose_level > 2)
3295 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3297 /* the argument should be put on the stack: FIXME handle size != word */
3298 if (ainfo->regtype == RegTypeGeneral) {
3299 switch (ainfo->size) {
3301 if (ppc_is_imm16 (inst->inst_offset)) {
3302 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3304 ppc_load (code, ppc_r11, inst->inst_offset);
3305 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3309 if (ppc_is_imm16 (inst->inst_offset)) {
3310 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3312 ppc_load (code, ppc_r11, inst->inst_offset);
3313 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3317 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3318 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3319 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3321 ppc_load (code, ppc_r11, inst->inst_offset);
3322 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3323 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3324 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3328 if (ppc_is_imm16 (inst->inst_offset)) {
3329 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3331 ppc_load (code, ppc_r11, inst->inst_offset);
3332 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3336 } else if (ainfo->regtype == RegTypeBase) {
3337 /* load the previous stack pointer in r11 */
3338 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3339 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3340 switch (ainfo->size) {
3342 if (ppc_is_imm16 (inst->inst_offset)) {
3343 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3345 ppc_load (code, ppc_r11, inst->inst_offset);
3346 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3350 if (ppc_is_imm16 (inst->inst_offset)) {
3351 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3353 ppc_load (code, ppc_r11, inst->inst_offset);
3354 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3358 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3359 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3360 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3361 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3364 g_assert_not_reached ();
3368 if (ppc_is_imm16 (inst->inst_offset)) {
3369 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3371 ppc_load (code, ppc_r11, inst->inst_offset);
3372 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3376 } else if (ainfo->regtype == RegTypeFP) {
3377 g_assert (ppc_is_imm16 (inst->inst_offset));
3378 if (ainfo->size == 8)
3379 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3380 else if (ainfo->size == 4)
3381 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3383 g_assert_not_reached ();
3384 } else if (ainfo->regtype == RegTypeStructByVal) {
3385 int doffset = inst->inst_offset;
3389 g_assert (ppc_is_imm16 (inst->inst_offset));
3390 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3391 if (mono_class_from_mono_type (inst->inst_vtype))
3392 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3393 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3395 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3396 register. Should this case include linux/ppc?
3400 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3402 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3405 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3406 soffset += sizeof (gpointer);
3407 doffset += sizeof (gpointer);
3409 if (ainfo->vtsize) {
3410 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3411 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3412 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3413 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3415 } else if (ainfo->regtype == RegTypeStructByAddr) {
3416 /* if it was originally a RegTypeBase */
3417 if (ainfo->offset) {
3418 /* load the previous stack pointer in r11 */
3419 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3420 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3422 ppc_mr (code, ppc_r11, ainfo->reg);
3424 g_assert (ppc_is_imm16 (inst->inst_offset));
3425 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3426 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3428 g_assert_not_reached ();
3433 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3434 ppc_load (code, ppc_r3, cfg->domain);
3435 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3436 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3437 ppc_lis (code, ppc_r0, 0);
3438 ppc_ori (code, ppc_r0, ppc_r0, 0);
3439 ppc_mtlr (code, ppc_r0);
3446 if (method->save_lmf) {
3447 if (lmf_pthread_key != -1) {
3448 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3449 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3450 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3452 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3453 (gpointer)"mono_get_lmf_addr");
3454 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3455 ppc_lis (code, ppc_r0, 0);
3456 ppc_ori (code, ppc_r0, ppc_r0, 0);
3457 ppc_mtlr (code, ppc_r0);
3463 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3464 /* lmf_offset is the offset from the previous stack pointer,
3465 * alloc_size is the total stack space allocated, so the offset
3466 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3467 * The pointer to the struct is put in ppc_r11 (new_lmf).
3468 * The callee-saved registers are already in the MonoLMF structure
3470 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3471 /* ppc_r3 is the result from mono_get_lmf_addr () */
3472 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3473 /* new_lmf->previous_lmf = *lmf_addr */
3474 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3475 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3476 /* *(lmf_addr) = r11 */
3477 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3478 /* save method info */
3479 ppc_load (code, ppc_r0, method);
3480 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3481 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3482 /* save the current IP */
3483 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3484 ppc_load (code, ppc_r0, 0x01010101);
3485 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3489 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3491 cfg->code_len = code - cfg->native_code;
3492 g_assert (cfg->code_len < cfg->code_size);
3499 mono_arch_emit_epilog (MonoCompile *cfg)
3501 MonoJumpInfo *patch_info;
3502 MonoMethod *method = cfg->method;
3504 int max_epilog_size = 16 + 20*4;
3507 if (cfg->method->save_lmf)
3508 max_epilog_size += 128;
3510 if (mono_jit_trace_calls != NULL)
3511 max_epilog_size += 50;
3513 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3514 max_epilog_size += 50;
3516 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3517 cfg->code_size *= 2;
3518 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3519 mono_jit_stats.code_reallocs++;
3523 * Keep in sync with OP_JMP
3525 code = cfg->native_code + cfg->code_len;
3527 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3528 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3532 if (method->save_lmf) {
3534 pos += sizeof (MonoLMF);
3536 /* save the frame reg in r8 */
3537 ppc_mr (code, ppc_r8, cfg->frame_reg);
3538 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3539 /* r5 = previous_lmf */
3540 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3542 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3543 /* *(lmf_addr) = previous_lmf */
3544 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3545 /* FIXME: speedup: there is no actual need to restore the registers if
3546 * we didn't actually change them (idea from Zoltan).
3549 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3551 /*for (i = 14; i < 32; i++) {
3552 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3554 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3555 /* use the saved copy of the frame reg in r8 */
3556 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3557 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3558 ppc_mtlr (code, ppc_r0);
3560 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3562 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3563 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3564 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3566 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3567 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3569 ppc_mtlr (code, ppc_r0);
3571 if (ppc_is_imm16 (cfg->stack_usage)) {
3572 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3574 ppc_load (code, ppc_r11, cfg->stack_usage);
3575 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3578 /*for (i = 31; i >= 14; --i) {
3579 if (cfg->used_float_regs & (1 << i)) {
3580 pos += sizeof (double);
3581 ppc_lfd (code, i, -pos, ppc_sp);
3584 for (i = 31; i >= 13; --i) {
3585 if (cfg->used_int_regs & (1 << i)) {
3586 pos += sizeof (gulong);
3587 ppc_lwz (code, i, -pos, ppc_sp);
3593 cfg->code_len = code - cfg->native_code;
3595 g_assert (cfg->code_len < cfg->code_size);
3599 /* remove once throw_exception_by_name is eliminated */
3601 exception_id_by_name (const char *name)
3603 if (strcmp (name, "IndexOutOfRangeException") == 0)
3604 return MONO_EXC_INDEX_OUT_OF_RANGE;
3605 if (strcmp (name, "OverflowException") == 0)
3606 return MONO_EXC_OVERFLOW;
3607 if (strcmp (name, "ArithmeticException") == 0)
3608 return MONO_EXC_ARITHMETIC;
3609 if (strcmp (name, "DivideByZeroException") == 0)
3610 return MONO_EXC_DIVIDE_BY_ZERO;
3611 if (strcmp (name, "InvalidCastException") == 0)
3612 return MONO_EXC_INVALID_CAST;
3613 if (strcmp (name, "NullReferenceException") == 0)
3614 return MONO_EXC_NULL_REF;
3615 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3616 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3617 g_error ("Unknown intrinsic exception %s\n", name);
3622 mono_arch_emit_exceptions (MonoCompile *cfg)
3624 MonoJumpInfo *patch_info;
3627 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3628 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3631 int max_epilog_size = 50;
3633 /* count the number of exception infos */
3636 * make sure we have enough space for exceptions
3637 * 24 is the simulated call to throw_exception_by_name
3639 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3640 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3641 i = exception_id_by_name (patch_info->data.target);
3642 if (!exc_throw_found [i]) {
3643 max_epilog_size += 24;
3644 exc_throw_found [i] = TRUE;
3646 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3647 max_epilog_size += 12;
3648 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3649 MonoOvfJump *ovfj = patch_info->data.target;
3650 i = exception_id_by_name (ovfj->data.exception);
3651 if (!exc_throw_found [i]) {
3652 max_epilog_size += 24;
3653 exc_throw_found [i] = TRUE;
3655 max_epilog_size += 8;
3659 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3660 cfg->code_size *= 2;
3661 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3662 mono_jit_stats.code_reallocs++;
3665 code = cfg->native_code + cfg->code_len;
3667 /* add code to raise exceptions */
3668 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3669 switch (patch_info->type) {
3670 case MONO_PATCH_INFO_BB_OVF: {
3671 MonoOvfJump *ovfj = patch_info->data.target;
3672 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3673 /* patch the initial jump */
3674 ppc_patch (ip, code);
3675 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3677 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3678 /* jump back to the true target */
3680 ip = ovfj->data.bb->native_offset + cfg->native_code;
3681 ppc_patch (code - 4, ip);
3684 case MONO_PATCH_INFO_EXC_OVF: {
3685 MonoOvfJump *ovfj = patch_info->data.target;
3686 MonoJumpInfo *newji;
3687 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3688 unsigned char *bcl = code;
3689 /* patch the initial jump: we arrived here with a call */
3690 ppc_patch (ip, code);
3691 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3693 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3694 /* patch the conditional jump to the right handler */
3695 /* make it processed next */
3696 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3697 newji->type = MONO_PATCH_INFO_EXC;
3698 newji->ip.i = bcl - cfg->native_code;
3699 newji->data.target = ovfj->data.exception;
3700 newji->next = patch_info->next;
3701 patch_info->next = newji;
3704 case MONO_PATCH_INFO_EXC: {
3705 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3706 i = exception_id_by_name (patch_info->data.target);
3707 if (exc_throw_pos [i]) {
3708 ppc_patch (ip, exc_throw_pos [i]);
3709 patch_info->type = MONO_PATCH_INFO_NONE;
3712 exc_throw_pos [i] = code;
3714 ppc_patch (ip, code);
3715 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3716 ppc_load (code, ppc_r3, patch_info->data.target);
3717 /* we got here from a conditional call, so the calling ip is set in lr already */
3718 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3719 patch_info->data.name = "mono_arch_throw_exception_by_name";
3720 patch_info->ip.i = code - cfg->native_code;
3721 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3722 ppc_lis (code, ppc_r0, 0);
3723 ppc_ori (code, ppc_r0, ppc_r0, 0);
3724 ppc_mtctr (code, ppc_r0);
3725 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3737 cfg->code_len = code - cfg->native_code;
3739 g_assert (cfg->code_len < cfg->code_size);
3744 try_offset_access (void *value, guint32 idx)
3746 register void* me __asm__ ("r2");
3747 void ***p = (void***)((char*)me + 284);
3748 int idx1 = idx / 32;
3749 int idx2 = idx % 32;
3752 if (value != p[idx1][idx2])
3758 setup_tls_access (void)
3761 guint32 *ins, *code;
3762 guint32 cmplwi_1023, li_0x48, blr_ins;
3763 if (tls_mode == TLS_MODE_FAILED)
3766 if (g_getenv ("MONO_NO_TLS")) {
3767 tls_mode = TLS_MODE_FAILED;
3771 if (tls_mode == TLS_MODE_DETECT) {
3772 ins = (guint32*)pthread_getspecific;
3773 /* uncond branch to the real method */
3774 if ((*ins >> 26) == 18) {
3776 val = (*ins & ~3) << 6;
3780 ins = (guint32*)val;
3782 ins = (guint32*) ((char*)ins + val);
3785 code = &cmplwi_1023;
3786 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3788 ppc_li (code, ppc_r4, 0x48);
3791 if (*ins == cmplwi_1023) {
3792 int found_lwz_284 = 0;
3793 for (ptk = 0; ptk < 20; ++ptk) {
3795 if (!*ins || *ins == blr_ins)
3797 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3802 if (!found_lwz_284) {
3803 tls_mode = TLS_MODE_FAILED;
3806 tls_mode = TLS_MODE_LTHREADS;
3807 } else if (*ins == li_0x48) {
3809 /* uncond branch to the real method */
3810 if ((*ins >> 26) == 18) {
3812 val = (*ins & ~3) << 6;
3816 ins = (guint32*)val;
3818 ins = (guint32*) ((char*)ins + val);
3821 ppc_li (code, ppc_r0, 0x7FF2);
3822 if (ins [1] == val) {
3823 /* Darwin on G4, implement */
3824 tls_mode = TLS_MODE_FAILED;
3828 ppc_mfspr (code, ppc_r3, 104);
3829 if (ins [1] != val) {
3830 tls_mode = TLS_MODE_FAILED;
3833 tls_mode = TLS_MODE_DARWIN_G5;
3836 tls_mode = TLS_MODE_FAILED;
3840 tls_mode = TLS_MODE_FAILED;
3844 if (monodomain_key == -1) {
3845 ptk = mono_domain_get_tls_key ();
3847 ptk = mono_pthread_key_for_tls (ptk);
3849 monodomain_key = ptk;
3853 if (lmf_pthread_key == -1) {
3854 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3856 /*g_print ("MonoLMF at: %d\n", ptk);*/
3857 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3858 init_tls_failed = 1;
3861 lmf_pthread_key = ptk;
3864 if (monothread_key == -1) {
3865 ptk = mono_thread_get_tls_key ();
3867 ptk = mono_pthread_key_for_tls (ptk);
3869 monothread_key = ptk;
3870 /*g_print ("thread inited: %d\n", ptk);*/
3873 /*g_print ("thread not inited yet %d\n", ptk);*/
3879 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3881 setup_tls_access ();
3885 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3890 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3892 int this_dreg = ppc_r3;
3897 /* add the this argument */
3898 if (this_reg != -1) {
3900 MONO_INST_NEW (cfg, this, OP_SETREG);
3901 this->type = this_type;
3902 this->sreg1 = this_reg;
3903 this->dreg = mono_regstate_next_int (cfg->rs);
3904 mono_bblock_add_inst (cfg->cbb, this);
3905 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3910 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3911 vtarg->type = STACK_MP;
3912 vtarg->sreg1 = vt_reg;
3913 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3914 mono_bblock_add_inst (cfg->cbb, vtarg);
3915 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3920 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3922 MonoInst *ins = NULL;
3924 if (cmethod->klass == mono_defaults.thread_class &&
3925 strcmp (cmethod->name, "MemoryBarrier") == 0) {
3926 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3928 /*if (cmethod->klass == mono_defaults.math_class) {
3929 if (strcmp (cmethod->name, "Sqrt") == 0) {
3930 MONO_INST_NEW (cfg, ins, OP_SQRT);
3931 ins->inst_i0 = args [0];
3938 mono_arch_print_tree (MonoInst *tree, int arity)
3943 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3947 setup_tls_access ();
3948 if (monodomain_key == -1)
3951 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3952 ins->inst_offset = monodomain_key;
3957 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3961 setup_tls_access ();
3962 if (monothread_key == -1)
3965 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3966 ins->inst_offset = monothread_key;