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>
30 int mono_exc_esp_offset = 0;
31 static int tls_mode = TLS_MODE_DETECT;
32 static int lmf_pthread_key = -1;
33 static int monothread_key = -1;
34 static int monodomain_key = -1;
37 offsets_from_pthread_key (guint32 key, int *offset2)
41 *offset2 = idx2 * sizeof (gpointer);
42 return 284 + idx1 * sizeof (gpointer);
45 #define emit_linuxthreads_tls(code,dreg,key) do {\
47 off1 = offsets_from_pthread_key ((key), &off2); \
48 ppc_lwz ((code), (dreg), off1, ppc_r2); \
49 ppc_lwz ((code), (dreg), off2, (dreg)); \
52 #define emit_darwing5_tls(code,dreg,key) do {\
53 int off1 = 0x48 + key * sizeof (gpointer); \
54 ppc_mfspr ((code), (dreg), 104); \
55 ppc_lwz ((code), (dreg), off1, (dreg)); \
58 /* FIXME: ensure the sc call preserves all but r3 */
59 #define emit_darwing4_tls(code,dreg,key) do {\
60 int off1 = 0x48 + key * sizeof (gpointer); \
61 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
62 ppc_li ((code), ppc_r0, 0x7FF2); \
64 ppc_lwz ((code), (dreg), off1, ppc_r3); \
65 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
68 #define emit_tls_access(code,dreg,key) do { \
70 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
71 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
72 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
73 default: g_assert_not_reached (); \
78 mono_arch_regname (int reg) {
79 static const char * rnames[] = {
80 "ppc_r0", "ppc_sp", "ppc_r2", "ppc_r3", "ppc_r4",
81 "ppc_r5", "ppc_r6", "ppc_r7", "ppc_r8", "ppc_r9",
82 "ppc_r10", "ppc_r11", "ppc_r12", "ppc_r13", "ppc_r14",
83 "ppc_r15", "ppc_r16", "ppc_r17", "ppc_r18", "ppc_r19",
84 "ppc_r20", "ppc_r21", "ppc_r22", "ppc_r23", "ppc_r24",
85 "ppc_r25", "ppc_r26", "ppc_r27", "ppc_r28", "ppc_r29",
88 if (reg >= 0 && reg < 32)
93 /* this function overwrites r0, r11, r12 */
95 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
97 /* unrolled, use the counter in big */
98 if (size > sizeof (gpointer) * 5) {
99 int shifted = size >> 2;
100 guint8 *copy_loop_start, *copy_loop_jump;
102 ppc_load (code, ppc_r0, shifted);
103 ppc_mtctr (code, ppc_r0);
104 g_assert (sreg == ppc_r11);
105 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
106 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
107 copy_loop_start = code;
108 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
109 ppc_stwu (code, ppc_r0, 4, ppc_r12);
110 copy_loop_jump = code;
111 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
112 ppc_patch (copy_loop_jump, copy_loop_start);
114 doffset = soffset = 0;
118 ppc_lwz (code, ppc_r0, soffset, sreg);
119 ppc_stw (code, ppc_r0, doffset, dreg);
125 ppc_lhz (code, ppc_r0, soffset, sreg);
126 ppc_sth (code, ppc_r0, doffset, dreg);
132 ppc_lbz (code, ppc_r0, soffset, sreg);
133 ppc_stb (code, ppc_r0, doffset, dreg);
142 * mono_arch_get_argument_info:
143 * @csig: a method signature
144 * @param_count: the number of parameters to consider
145 * @arg_info: an array to store the result infos
147 * Gathers information on parameters such as size, alignment and
148 * padding. arg_info should be large enought to hold param_count + 1 entries.
150 * Returns the size of the activation frame.
153 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
155 int k, frame_size = 0;
156 int size, align, pad;
159 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
160 frame_size += sizeof (gpointer);
164 arg_info [0].offset = offset;
167 frame_size += sizeof (gpointer);
171 arg_info [0].size = frame_size;
173 for (k = 0; k < param_count; k++) {
176 size = mono_type_native_stack_size (csig->params [k], &align);
178 size = mono_type_stack_size (csig->params [k], &align);
180 /* ignore alignment for now */
183 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
184 arg_info [k].pad = pad;
186 arg_info [k + 1].pad = 0;
187 arg_info [k + 1].size = size;
189 arg_info [k + 1].offset = offset;
193 align = MONO_ARCH_FRAME_ALIGNMENT;
194 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
195 arg_info [k].pad = pad;
201 * Initialize the cpu to execute managed code.
204 mono_arch_cpu_init (void)
209 * This function returns the optimizations supported on this cpu.
212 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
216 /* no ppc-specific optimizations yet */
217 *exclude_mask = MONO_OPT_INLINE;
222 is_regsize_var (MonoType *t) {
225 t = mono_type_get_underlying_type (t);
232 case MONO_TYPE_FNPTR:
234 case MONO_TYPE_OBJECT:
235 case MONO_TYPE_STRING:
236 case MONO_TYPE_CLASS:
237 case MONO_TYPE_SZARRAY:
238 case MONO_TYPE_ARRAY:
240 case MONO_TYPE_VALUETYPE:
247 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
252 for (i = 0; i < cfg->num_varinfo; i++) {
253 MonoInst *ins = cfg->varinfo [i];
254 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
257 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
260 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
263 /* we can only allocate 32 bit values */
264 if (is_regsize_var (ins->inst_vtype)) {
265 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
266 g_assert (i == vmv->idx);
267 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
274 #define USE_EXTRA_TEMPS ((1<<30) | (1<<29))
275 //#define USE_EXTRA_TEMPS 0
278 mono_arch_get_global_int_regs (MonoCompile *cfg)
282 if (cfg->frame_reg != ppc_sp)
287 for (i = 13; i < top; ++i)
288 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
294 * mono_arch_regalloc_cost:
296 * Return the cost, in number of memory references, of the action of
297 * allocating the variable VMV into a register during global register
301 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
307 // code from ppc/tramp.c, try to keep in sync
308 #define MIN_CACHE_LINE 8
311 mono_arch_flush_icache (guint8 *code, gint size)
317 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
319 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
320 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
323 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
324 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
329 for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
330 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
336 #define NOT_IMPLEMENTED(x) \
337 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
340 #define ALWAYS_ON_STACK(s) s
341 #define FP_ALSO_IN_REG(s) s
343 #define ALWAYS_ON_STACK(s)
344 #define FP_ALSO_IN_REG(s)
345 #define ALIGN_DOUBLES
358 guint16 vtsize; /* in param area */
360 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
361 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
376 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
379 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
380 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
381 ainfo->reg = ppc_sp; /* in the caller */
382 ainfo->regtype = RegTypeBase;
385 ALWAYS_ON_STACK (*stack_size += 4);
389 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
391 //*stack_size += (*stack_size % 8);
393 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
394 ainfo->reg = ppc_sp; /* in the caller */
395 ainfo->regtype = RegTypeBase;
402 ALWAYS_ON_STACK (*stack_size += 8);
411 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
414 int n = sig->hasthis + sig->param_count;
416 guint32 stack_size = 0;
417 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
419 fr = PPC_FIRST_FPARG_REG;
420 gr = PPC_FIRST_ARG_REG;
422 /* FIXME: handle returning a struct */
423 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
424 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
425 cinfo->struct_ret = PPC_FIRST_ARG_REG;
430 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
433 DEBUG(printf("params: %d\n", sig->param_count));
434 for (i = 0; i < sig->param_count; ++i) {
435 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
436 /* Prevent implicit arguments and sig_cookie from
437 being passed in registers */
438 gr = PPC_LAST_ARG_REG + 1;
439 /* Emit the signature cookie just before the implicit arguments */
440 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
442 DEBUG(printf("param %d: ", i));
443 if (sig->params [i]->byref) {
444 DEBUG(printf("byref\n"));
445 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
449 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
451 switch (simpletype) {
452 case MONO_TYPE_BOOLEAN:
455 cinfo->args [n].size = 1;
456 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
462 cinfo->args [n].size = 2;
463 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
468 cinfo->args [n].size = 4;
469 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
475 case MONO_TYPE_FNPTR:
476 case MONO_TYPE_CLASS:
477 case MONO_TYPE_OBJECT:
478 case MONO_TYPE_STRING:
479 case MONO_TYPE_SZARRAY:
480 case MONO_TYPE_ARRAY:
481 cinfo->args [n].size = sizeof (gpointer);
482 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
485 case MONO_TYPE_VALUETYPE: {
488 klass = mono_class_from_mono_type (sig->params [i]);
490 size = mono_class_native_size (klass, NULL);
492 size = mono_class_value_size (klass, NULL);
493 DEBUG(printf ("load %d bytes struct\n",
494 mono_class_native_size (sig->params [i]->data.klass, NULL)));
495 #if PPC_PASS_STRUCTS_BY_VALUE
497 int align_size = size;
499 align_size += (sizeof (gpointer) - 1);
500 align_size &= ~(sizeof (gpointer) - 1);
501 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
502 cinfo->args [n].regtype = RegTypeStructByVal;
503 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
504 cinfo->args [n].size = 0;
505 cinfo->args [n].vtsize = nwords;
507 int rest = PPC_LAST_ARG_REG - gr + 1;
508 int n_in_regs = rest >= nwords? nwords: rest;
509 cinfo->args [n].size = n_in_regs;
510 cinfo->args [n].vtsize = nwords - n_in_regs;
511 cinfo->args [n].reg = gr;
514 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
515 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
516 stack_size += nwords * sizeof (gpointer);
519 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
520 cinfo->args [n].regtype = RegTypeStructByAddr;
525 case MONO_TYPE_TYPEDBYREF: {
526 int size = sizeof (MonoTypedRef);
527 /* keep in sync or merge with the valuetype case */
528 #if PPC_PASS_STRUCTS_BY_VALUE
530 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
531 cinfo->args [n].regtype = RegTypeStructByVal;
532 if (gr <= PPC_LAST_ARG_REG) {
533 int rest = PPC_LAST_ARG_REG - gr + 1;
534 int n_in_regs = rest >= nwords? nwords: rest;
535 cinfo->args [n].size = n_in_regs;
536 cinfo->args [n].vtsize = nwords - n_in_regs;
537 cinfo->args [n].reg = gr;
540 cinfo->args [n].size = 0;
541 cinfo->args [n].vtsize = nwords;
543 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
544 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
545 stack_size += nwords * sizeof (gpointer);
548 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
549 cinfo->args [n].regtype = RegTypeStructByAddr;
556 cinfo->args [n].size = 8;
557 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
561 cinfo->args [n].size = 4;
563 /* It was 7, now it is 8 in LinuxPPC */
564 if (fr <= PPC_LAST_FPARG_REG) {
565 cinfo->args [n].regtype = RegTypeFP;
566 cinfo->args [n].reg = fr;
568 FP_ALSO_IN_REG (gr ++);
569 ALWAYS_ON_STACK (stack_size += 4);
571 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
572 cinfo->args [n].regtype = RegTypeBase;
573 cinfo->args [n].reg = ppc_sp; /* in the caller*/
579 cinfo->args [n].size = 8;
580 /* It was 7, now it is 8 in LinuxPPC */
581 if (fr <= PPC_LAST_FPARG_REG) {
582 cinfo->args [n].regtype = RegTypeFP;
583 cinfo->args [n].reg = fr;
585 FP_ALSO_IN_REG (gr += 2);
586 ALWAYS_ON_STACK (stack_size += 8);
588 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
589 cinfo->args [n].regtype = RegTypeBase;
590 cinfo->args [n].reg = ppc_sp; /* in the caller*/
596 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
601 simpletype = mono_type_get_underlying_type (sig->ret)->type;
603 switch (simpletype) {
604 case MONO_TYPE_BOOLEAN:
615 case MONO_TYPE_FNPTR:
616 case MONO_TYPE_CLASS:
617 case MONO_TYPE_OBJECT:
618 case MONO_TYPE_SZARRAY:
619 case MONO_TYPE_ARRAY:
620 case MONO_TYPE_STRING:
621 cinfo->ret.reg = ppc_r3;
625 cinfo->ret.reg = ppc_r3;
629 cinfo->ret.reg = ppc_f1;
630 cinfo->ret.regtype = RegTypeFP;
632 case MONO_TYPE_VALUETYPE:
634 case MONO_TYPE_TYPEDBYREF:
638 g_error ("Can't handle as return value 0x%x", sig->ret->type);
642 /* align stack size to 16 */
643 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
644 stack_size = (stack_size + 15) & ~15;
646 cinfo->stack_usage = stack_size;
652 * Set var information according to the calling convention. ppc version.
653 * The locals var stuff should most likely be split in another method.
656 mono_arch_allocate_vars (MonoCompile *m)
658 MonoMethodSignature *sig;
659 MonoMethodHeader *header;
661 int i, offset, size, align, curinst;
662 int frame_reg = ppc_sp;
665 /* allow room for the vararg method args: void* and long/double */
666 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
667 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
668 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
669 * call convs needs to be handled this way.
671 if (m->flags & MONO_CFG_HAS_VARARGS)
672 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
673 /* gtk-sharp and other broken code will dllimport vararg functions even with
674 * non-varargs signatures. Since there is little hope people will get this right
675 * we assume they won't.
677 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
678 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
680 header = mono_method_get_header (m->method);
683 * We use the frame register also for any method that has
684 * exception clauses. This way, when the handlers are called,
685 * the code will reference local variables using the frame reg instead of
686 * the stack pointer: if we had to restore the stack pointer, we'd
687 * corrupt the method frames that are already on the stack (since
688 * filters get called before stack unwinding happens) when the filter
689 * code would call any method (this also applies to finally etc.).
691 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
693 m->frame_reg = frame_reg;
694 if (frame_reg != ppc_sp) {
695 m->used_int_regs |= 1 << frame_reg;
698 sig = mono_method_signature (m->method);
702 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
703 m->ret->opcode = OP_REGVAR;
704 m->ret->inst_c0 = ppc_r3;
706 /* FIXME: handle long and FP values */
707 switch (mono_type_get_underlying_type (sig->ret)->type) {
711 m->ret->opcode = OP_REGVAR;
712 m->ret->inst_c0 = ppc_r3;
716 /* local vars are at a positive offset from the stack pointer */
718 * also note that if the function uses alloca, we use ppc_r31
719 * to point at the local variables.
721 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
722 /* align the offset to 16 bytes: not sure this is needed here */
724 //offset &= ~(16 - 1);
726 /* add parameter area size for called functions */
727 offset += m->param_area;
731 /* allow room to save the return value */
732 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
735 /* the MonoLMF structure is stored just below the stack pointer */
738 /* this stuff should not be needed on ppc and the new jit,
739 * because a call on ppc to the handlers doesn't change the
740 * stack pointer and the jist doesn't manipulate the stack pointer
741 * for operations involving valuetypes.
743 /* reserve space to store the esp */
744 offset += sizeof (gpointer);
746 /* this is a global constant */
747 mono_exc_esp_offset = offset;
749 if (sig->call_convention == MONO_CALL_VARARG) {
750 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
753 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
755 offset += sizeof(gpointer) - 1;
756 offset &= ~(sizeof(gpointer) - 1);
757 inst->inst_offset = offset;
758 inst->opcode = OP_REGOFFSET;
759 inst->inst_basereg = frame_reg;
760 offset += sizeof(gpointer);
761 if (sig->call_convention == MONO_CALL_VARARG)
762 m->sig_cookie += sizeof (gpointer);
765 curinst = m->locals_start;
766 for (i = curinst; i < m->num_varinfo; ++i) {
767 inst = m->varinfo [i];
768 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
771 /* inst->unused indicates native sized value types, this is used by the
772 * pinvoke wrappers when they call functions returning structure */
773 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
774 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
776 size = mono_type_size (inst->inst_vtype, &align);
779 offset &= ~(align - 1);
780 inst->inst_offset = offset;
781 inst->opcode = OP_REGOFFSET;
782 inst->inst_basereg = frame_reg;
784 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
789 inst = m->varinfo [curinst];
790 if (inst->opcode != OP_REGVAR) {
791 inst->opcode = OP_REGOFFSET;
792 inst->inst_basereg = frame_reg;
793 offset += sizeof (gpointer) - 1;
794 offset &= ~(sizeof (gpointer) - 1);
795 inst->inst_offset = offset;
796 offset += sizeof (gpointer);
797 if (sig->call_convention == MONO_CALL_VARARG)
798 m->sig_cookie += sizeof (gpointer);
803 for (i = 0; i < sig->param_count; ++i) {
804 inst = m->varinfo [curinst];
805 if (inst->opcode != OP_REGVAR) {
806 inst->opcode = OP_REGOFFSET;
807 inst->inst_basereg = frame_reg;
808 size = mono_type_size (sig->params [i], &align);
810 offset &= ~(align - 1);
811 inst->inst_offset = offset;
813 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
814 m->sig_cookie += size;
819 /* align the offset to 16 bytes */
824 m->stack_offset = offset;
828 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
829 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
833 * take the arguments and generate the arch-specific
834 * instructions to properly call the function in call.
835 * This includes pushing, moving arguments to the right register
837 * Issue: who does the spilling if needed, and when?
840 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
842 MonoMethodSignature *sig;
847 sig = call->signature;
848 n = sig->param_count + sig->hasthis;
850 cinfo = calculate_sizes (sig, sig->pinvoke);
851 if (cinfo->struct_ret)
852 call->used_iregs |= 1 << cinfo->struct_ret;
854 for (i = 0; i < n; ++i) {
855 ainfo = cinfo->args + i;
856 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
858 cfg->disable_aot = TRUE;
860 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
861 sig_arg->inst_p0 = call->signature;
863 MONO_INST_NEW (cfg, arg, OP_OUTARG);
864 arg->inst_imm = cinfo->sig_cookie.offset;
865 arg->inst_left = sig_arg;
867 /* prepend, so they get reversed */
868 arg->next = call->out_args;
869 call->out_args = arg;
871 if (is_virtual && i == 0) {
872 /* the argument will be attached to the call instrucion */
874 call->used_iregs |= 1 << ainfo->reg;
876 MONO_INST_NEW (cfg, arg, OP_OUTARG);
878 arg->cil_code = in->cil_code;
880 arg->type = in->type;
881 /* prepend, we'll need to reverse them later */
882 arg->next = call->out_args;
883 call->out_args = arg;
884 if (ainfo->regtype == RegTypeGeneral) {
885 arg->unused = ainfo->reg;
886 call->used_iregs |= 1 << ainfo->reg;
887 if (arg->type == STACK_I8)
888 call->used_iregs |= 1 << (ainfo->reg + 1);
889 } else if (ainfo->regtype == RegTypeStructByAddr) {
890 /* FIXME: where si the data allocated? */
891 arg->unused = ainfo->reg;
892 call->used_iregs |= 1 << ainfo->reg;
893 } else if (ainfo->regtype == RegTypeStructByVal) {
895 /* mark the used regs */
896 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
897 call->used_iregs |= 1 << (ainfo->reg + cur_reg);
899 arg->opcode = OP_OUTARG_VT;
900 arg->unused = ainfo->reg | (ainfo->size << 8) | (ainfo->vtsize << 16);
901 arg->inst_imm = ainfo->offset;
902 } else if (ainfo->regtype == RegTypeBase) {
903 arg->opcode = OP_OUTARG;
904 arg->unused = ainfo->reg | (ainfo->size << 8);
905 arg->inst_imm = ainfo->offset;
906 } else if (ainfo->regtype == RegTypeFP) {
907 arg->opcode = OP_OUTARG_R8;
908 arg->unused = ainfo->reg;
909 call->used_fregs |= 1 << ainfo->reg;
910 if (ainfo->size == 4) {
911 arg->opcode = OP_OUTARG_R8;
912 /* we reduce the precision */
914 MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
915 conv->inst_left = arg->inst_left;
916 arg->inst_left = conv;*/
919 g_assert_not_reached ();
924 * Reverse the call->out_args list.
927 MonoInst *prev = NULL, *list = call->out_args, *next;
934 call->out_args = prev;
936 call->stack_usage = cinfo->stack_usage;
937 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
938 cfg->flags |= MONO_CFG_HAS_CALLS;
940 * should set more info in call, such as the stack space
941 * used by the args that needs to be added back to esp
949 * Allow tracing to work with this interface (with an optional argument)
953 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
957 ppc_load (code, ppc_r3, cfg->method);
958 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
959 ppc_load (code, ppc_r0, func);
960 ppc_mtlr (code, ppc_r0);
974 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
977 int save_mode = SAVE_NONE;
979 MonoMethod *method = cfg->method;
980 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
981 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
985 offset = code - cfg->native_code;
986 /* we need about 16 instructions */
987 if (offset > (cfg->code_size - 16 * 4)) {
989 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
990 code = cfg->native_code + offset;
995 /* special case string .ctor icall */
996 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
997 save_mode = SAVE_ONE;
999 save_mode = SAVE_NONE;
1003 save_mode = SAVE_TWO;
1007 save_mode = SAVE_FP;
1009 case MONO_TYPE_VALUETYPE:
1010 save_mode = SAVE_STRUCT;
1013 save_mode = SAVE_ONE;
1017 switch (save_mode) {
1019 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1020 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1021 if (enable_arguments) {
1022 ppc_mr (code, ppc_r5, ppc_r4);
1023 ppc_mr (code, ppc_r4, ppc_r3);
1027 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1028 if (enable_arguments) {
1029 ppc_mr (code, ppc_r4, ppc_r3);
1033 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1034 if (enable_arguments) {
1035 /* FIXME: what reg? */
1036 ppc_fmr (code, ppc_f3, ppc_f1);
1037 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1038 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1042 if (enable_arguments) {
1043 /* FIXME: get the actual address */
1044 ppc_mr (code, ppc_r4, ppc_r3);
1052 ppc_load (code, ppc_r3, cfg->method);
1053 ppc_load (code, ppc_r0, func);
1054 ppc_mtlr (code, ppc_r0);
1057 switch (save_mode) {
1059 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1060 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1063 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1066 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1076 * Conditional branches have a small offset, so if it is likely overflowed,
1077 * we do a branch to the end of the method (uncond branches have much larger
1078 * offsets) where we perform the conditional and jump back unconditionally.
1079 * It's slightly slower, since we add two uncond branches, but it's very simple
1080 * with the current patch implementation and such large methods are likely not
1081 * going to be perf critical anyway.
1090 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1091 if (ins->flags & MONO_INST_BRLABEL) { \
1092 if (0 && ins->inst_i0->inst_c0) { \
1093 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1095 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1096 ppc_bc (code, (b0), (b1), 0); \
1099 if (0 && ins->inst_true_bb->native_offset) { \
1100 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1102 int br_disp = ins->inst_true_bb->max_offset - offset; \
1103 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1104 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1105 ovfj->bb = ins->inst_true_bb; \
1106 ovfj->ip_offset = 0; \
1107 ovfj->b0_cond = (b0); \
1108 ovfj->b1_cond = (b1); \
1109 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1112 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1113 ppc_bc (code, (b0), (b1), 0); \
1118 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1120 /* emit an exception if condition is fail
1122 * We assign the extra code used to throw the implicit exceptions
1123 * to cfg->bb_exit as far as the big branch handling is concerned
1125 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1127 int br_disp = cfg->bb_exit->max_offset - offset; \
1128 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1129 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1131 ovfj->ip_offset = code - cfg->native_code; \
1132 ovfj->b0_cond = (b0); \
1133 ovfj->b1_cond = (b1); \
1134 /* FIXME: test this code */ \
1135 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1137 cfg->bb_exit->max_offset += 24; \
1139 mono_add_patch_info (cfg, code - cfg->native_code, \
1140 MONO_PATCH_INFO_EXC, exc_name); \
1141 ppc_bcl (code, (b0), (b1), 0); \
1145 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1148 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1150 MonoInst *ins, *last_ins = NULL;
1155 switch (ins->opcode) {
1157 /* remove unnecessary multiplication with 1 */
1158 if (ins->inst_imm == 1) {
1159 if (ins->dreg != ins->sreg1) {
1160 ins->opcode = OP_MOVE;
1162 last_ins->next = ins->next;
1167 int power2 = mono_is_power_of_two (ins->inst_imm);
1169 ins->opcode = OP_SHL_IMM;
1170 ins->inst_imm = power2;
1174 case OP_LOAD_MEMBASE:
1175 case OP_LOADI4_MEMBASE:
1177 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1178 * OP_LOAD_MEMBASE offset(basereg), reg
1180 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1181 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1182 ins->inst_basereg == last_ins->inst_destbasereg &&
1183 ins->inst_offset == last_ins->inst_offset) {
1184 if (ins->dreg == last_ins->sreg1) {
1185 last_ins->next = ins->next;
1189 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1190 ins->opcode = OP_MOVE;
1191 ins->sreg1 = last_ins->sreg1;
1195 * Note: reg1 must be different from the basereg in the second load
1196 * OP_LOAD_MEMBASE offset(basereg), reg1
1197 * OP_LOAD_MEMBASE offset(basereg), reg2
1199 * OP_LOAD_MEMBASE offset(basereg), reg1
1200 * OP_MOVE reg1, reg2
1202 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1203 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1204 ins->inst_basereg != last_ins->dreg &&
1205 ins->inst_basereg == last_ins->inst_basereg &&
1206 ins->inst_offset == last_ins->inst_offset) {
1208 if (ins->dreg == last_ins->dreg) {
1209 last_ins->next = ins->next;
1213 ins->opcode = OP_MOVE;
1214 ins->sreg1 = last_ins->dreg;
1217 //g_assert_not_reached ();
1221 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1222 * OP_LOAD_MEMBASE offset(basereg), reg
1224 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1225 * OP_ICONST reg, imm
1227 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1228 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1229 ins->inst_basereg == last_ins->inst_destbasereg &&
1230 ins->inst_offset == last_ins->inst_offset) {
1231 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1232 ins->opcode = OP_ICONST;
1233 ins->inst_c0 = last_ins->inst_imm;
1234 g_assert_not_reached (); // check this rule
1238 case OP_LOADU1_MEMBASE:
1239 case OP_LOADI1_MEMBASE:
1240 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1241 ins->inst_basereg == last_ins->inst_destbasereg &&
1242 ins->inst_offset == last_ins->inst_offset) {
1243 if (ins->dreg == last_ins->sreg1) {
1244 last_ins->next = ins->next;
1248 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1249 ins->opcode = OP_MOVE;
1250 ins->sreg1 = last_ins->sreg1;
1254 case OP_LOADU2_MEMBASE:
1255 case OP_LOADI2_MEMBASE:
1256 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1257 ins->inst_basereg == last_ins->inst_destbasereg &&
1258 ins->inst_offset == last_ins->inst_offset) {
1259 if (ins->dreg == last_ins->sreg1) {
1260 last_ins->next = ins->next;
1264 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1265 ins->opcode = OP_MOVE;
1266 ins->sreg1 = last_ins->sreg1;
1274 ins->opcode = OP_MOVE;
1278 if (ins->dreg == ins->sreg1) {
1280 last_ins->next = ins->next;
1285 * OP_MOVE sreg, dreg
1286 * OP_MOVE dreg, sreg
1288 if (last_ins && last_ins->opcode == OP_MOVE &&
1289 ins->sreg1 == last_ins->dreg &&
1290 ins->dreg == last_ins->sreg1) {
1291 last_ins->next = ins->next;
1300 bb->last_ins = last_ins;
1304 * the branch_b0_table should maintain the order of these
1318 branch_b0_table [] = {
1333 branch_b1_table [] = {
1348 * returns the offset used by spillvar. It allocates a new
1349 * spill variable if necessary.
1352 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
1354 MonoSpillInfo **si, *info;
1357 si = &cfg->spill_info;
1359 while (i <= spillvar) {
1362 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1364 info->offset = cfg->stack_offset;
1365 cfg->stack_offset += sizeof (gpointer);
1369 return (*si)->offset;
1375 g_assert_not_reached ();
1380 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1382 MonoSpillInfo **si, *info;
1385 si = &cfg->spill_info_float;
1387 while (i <= spillvar) {
1390 *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1392 cfg->stack_offset += 7;
1393 cfg->stack_offset &= ~7;
1394 info->offset = cfg->stack_offset;
1395 cfg->stack_offset += sizeof (double);
1399 return (*si)->offset;
1405 g_assert_not_reached ();
1410 #define DEBUG(a) if (cfg->verbose_level > 1) a
1412 /* use ppc_r3-ppc_10,ppc_r12 as temp registers, f1-f13 for FP registers */
1413 #define PPC_CALLER_REGS ((0xff<<3) | (1<<12) | USE_EXTRA_TEMPS)
1414 #define PPC_CALLER_FREGS (0x3ffe)
1416 #define reg_is_freeable(r) (PPC_CALLER_REGS & 1 << (r))
1417 #define freg_is_freeable(r) ((r) >= 1 && (r) <= 13)
1426 static const char*const * ins_spec = ppcg4;
1429 print_ins (int i, MonoInst *ins)
1431 const char *spec = ins_spec [ins->opcode];
1432 g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1433 if (spec [MONO_INST_DEST]) {
1434 if (ins->dreg >= MONO_MAX_IREGS)
1435 g_print (" R%d <-", ins->dreg);
1437 g_print (" %s <-", mono_arch_regname (ins->dreg));
1439 if (spec [MONO_INST_SRC1]) {
1440 if (ins->sreg1 >= MONO_MAX_IREGS)
1441 g_print (" R%d", ins->sreg1);
1443 g_print (" %s", mono_arch_regname (ins->sreg1));
1445 if (spec [MONO_INST_SRC2]) {
1446 if (ins->sreg2 >= MONO_MAX_IREGS)
1447 g_print (" R%d", ins->sreg2);
1449 g_print (" %s", mono_arch_regname (ins->sreg2));
1451 if (spec [MONO_INST_CLOB])
1452 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1457 print_regtrack (RegTrack *t, int num)
1463 for (i = 0; i < num; ++i) {
1466 if (i >= MONO_MAX_IREGS) {
1467 g_snprintf (buf, sizeof(buf), "R%d", i);
1470 r = mono_arch_regname (i);
1471 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1475 typedef struct InstList InstList;
1483 static inline InstList*
1484 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1486 InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1496 * Force the spilling of the variable in the symbolic register 'reg'.
1499 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1504 sel = cfg->rs->iassign [reg];
1505 /*i = cfg->rs->isymbolic [sel];
1506 g_assert (i == reg);*/
1508 spill = ++cfg->spill_count;
1509 cfg->rs->iassign [i] = -spill - 1;
1510 mono_regstate_free_int (cfg->rs, sel);
1511 /* we need to create a spill var and insert a load to sel after the current instruction */
1512 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1514 load->inst_basereg = cfg->frame_reg;
1515 load->inst_offset = mono_spillvar_offset (cfg, spill);
1517 while (ins->next != item->prev->data)
1520 load->next = ins->next;
1522 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1523 i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1524 g_assert (i == sel);
1530 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1535 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1536 /* exclude the registers in the current instruction */
1537 if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1538 if (ins->sreg1 >= MONO_MAX_IREGS)
1539 regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1541 regmask &= ~ (1 << ins->sreg1);
1542 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1544 if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1545 if (ins->sreg2 >= MONO_MAX_IREGS)
1546 regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1548 regmask &= ~ (1 << ins->sreg2);
1549 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1551 if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1552 regmask &= ~ (1 << ins->dreg);
1553 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1556 DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1557 g_assert (regmask); /* need at least a register we can free */
1559 /* we should track prev_use and spill the register that's farther */
1560 for (i = 0; i < MONO_MAX_IREGS; ++i) {
1561 if (regmask & (1 << i)) {
1563 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1567 i = cfg->rs->isymbolic [sel];
1568 spill = ++cfg->spill_count;
1569 cfg->rs->iassign [i] = -spill - 1;
1570 mono_regstate_free_int (cfg->rs, sel);
1571 /* we need to create a spill var and insert a load to sel after the current instruction */
1572 MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1574 load->inst_basereg = cfg->frame_reg;
1575 load->inst_offset = mono_spillvar_offset (cfg, spill);
1577 while (ins->next != item->prev->data)
1580 load->next = ins->next;
1582 DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1583 i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1584 g_assert (i == sel);
1590 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1595 DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1596 /* exclude the registers in the current instruction */
1597 if (reg != ins->sreg1 && (freg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg1] >= 0))) {
1598 if (ins->sreg1 >= MONO_MAX_FREGS)
1599 regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
1601 regmask &= ~ (1 << ins->sreg1);
1602 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1604 if (reg != ins->sreg2 && (freg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg2] >= 0))) {
1605 if (ins->sreg2 >= MONO_MAX_FREGS)
1606 regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
1608 regmask &= ~ (1 << ins->sreg2);
1609 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1611 if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
1612 regmask &= ~ (1 << ins->dreg);
1613 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1616 DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1617 g_assert (regmask); /* need at least a register we can free */
1619 /* we should track prev_use and spill the register that's farther */
1620 for (i = 0; i < MONO_MAX_FREGS; ++i) {
1621 if (regmask & (1 << i)) {
1623 DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->fassign [sel]));
1627 i = cfg->rs->fsymbolic [sel];
1628 spill = ++cfg->spill_count;
1629 cfg->rs->fassign [i] = -spill - 1;
1630 mono_regstate_free_float(cfg->rs, sel);
1631 /* we need to create a spill var and insert a load to sel after the current instruction */
1632 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1634 load->inst_basereg = cfg->frame_reg;
1635 load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1637 while (ins->next != item->prev->data)
1640 load->next = ins->next;
1642 DEBUG (g_print ("SPILLED LOAD FP (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1643 i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
1644 g_assert (i == sel);
1650 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1653 MONO_INST_NEW (cfg, copy, OP_MOVE);
1657 copy->next = ins->next;
1660 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1665 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1668 MONO_INST_NEW (cfg, copy, OP_FMOVE);
1672 copy->next = ins->next;
1675 DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1680 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1683 MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1685 store->inst_destbasereg = cfg->frame_reg;
1686 store->inst_offset = mono_spillvar_offset (cfg, spill);
1688 store->next = ins->next;
1691 DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1696 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1699 MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1701 store->inst_destbasereg = cfg->frame_reg;
1702 store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1704 store->next = ins->next;
1707 DEBUG (g_print ("SPILLED STORE FP (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1712 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1715 g_assert (item->next);
1716 prev = item->next->data;
1718 while (prev->next != ins)
1720 to_insert->next = ins;
1721 prev->next = to_insert;
1723 * needed otherwise in the next instruction we can add an ins to the
1724 * end and that would get past this instruction.
1726 item->data = to_insert;
1730 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1732 int val = cfg->rs->iassign [sym_reg];
1736 /* the register gets spilled after this inst */
1739 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1741 val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1742 cfg->rs->iassign [sym_reg] = val;
1743 /* add option to store before the instruction for src registers */
1745 create_spilled_store (cfg, spill, val, sym_reg, ins);
1747 cfg->rs->isymbolic [val] = sym_reg;
1752 * Local register allocation.
1753 * We first scan the list of instructions and we save the liveness info of
1754 * each register (when the register is first used, when it's value is set etc.).
1755 * We also reverse the list of instructions (in the InstList list) because assigning
1756 * registers backwards allows for more tricks to be used.
1759 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1762 MonoRegState *rs = cfg->rs;
1764 RegTrack *reginfo, *reginfof;
1765 RegTrack *reginfo1, *reginfo2, *reginfod;
1766 InstList *tmp, *reversed = NULL;
1768 guint32 src1_mask, src2_mask, dest_mask;
1769 guint32 cur_iregs, cur_fregs;
1773 rs->next_vireg = bb->max_ireg;
1774 rs->next_vfreg = bb->max_freg;
1775 mono_regstate_assign (rs);
1776 reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
1777 reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
1778 rs->ifree_mask = PPC_CALLER_REGS;
1779 rs->ffree_mask = PPC_CALLER_FREGS;
1783 DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1784 /* forward pass on the instructions to collect register liveness info */
1786 spec = ins_spec [ins->opcode];
1787 DEBUG (print_ins (i, ins));
1788 /*if (spec [MONO_INST_CLOB] == 'c') {
1789 MonoCallInst * call = (MonoCallInst*)ins;
1792 if (spec [MONO_INST_SRC1]) {
1793 if (spec [MONO_INST_SRC1] == 'f')
1794 reginfo1 = reginfof;
1797 reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1798 reginfo1 [ins->sreg1].last_use = i;
1802 if (spec [MONO_INST_SRC2]) {
1803 if (spec [MONO_INST_SRC2] == 'f')
1804 reginfo2 = reginfof;
1807 reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1808 reginfo2 [ins->sreg2].last_use = i;
1812 if (spec [MONO_INST_DEST]) {
1813 if (spec [MONO_INST_DEST] == 'f')
1814 reginfod = reginfof;
1817 if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1818 reginfod [ins->dreg].killed_in = i;
1819 reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1820 reginfod [ins->dreg].last_use = i;
1821 if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1822 reginfod [ins->dreg].born_in = i;
1823 if (spec [MONO_INST_DEST] == 'l') {
1824 /* result in eax:edx, the virtual register is allocated sequentially */
1825 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1826 reginfod [ins->dreg + 1].last_use = i;
1827 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1828 reginfod [ins->dreg + 1].born_in = i;
1833 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1838 cur_iregs = PPC_CALLER_REGS;
1839 cur_fregs = PPC_CALLER_FREGS;
1841 DEBUG (print_regtrack (reginfo, rs->next_vireg));
1842 DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1845 int prev_dreg, prev_sreg1, prev_sreg2;
1848 spec = ins_spec [ins->opcode];
1849 DEBUG (g_print ("processing:"));
1850 DEBUG (print_ins (i, ins));
1851 /* make the register available for allocation: FIXME add fp reg */
1852 if (ins->opcode == OP_SETREG || ins->opcode == OP_SETREGIMM) {
1853 cur_iregs |= 1 << ins->dreg;
1854 DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
1855 } else if (ins->opcode == OP_SETFREG) {
1856 cur_fregs |= 1 << ins->dreg;
1857 DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
1858 } else if (spec [MONO_INST_CLOB] == 'c') {
1859 MonoCallInst *cinst = (MonoCallInst*)ins;
1860 DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs));
1861 DEBUG (g_print ("excluding fpregs 0x%x from cur_fregs (0x%x)\n", cinst->used_fregs, cur_fregs));
1862 cur_iregs &= ~cinst->used_iregs;
1863 cur_fregs &= ~cinst->used_fregs;
1864 DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
1865 DEBUG (g_print ("available cur_fregs: 0x%x\n", cur_fregs));
1866 /* registers used by the calling convention are excluded from
1867 * allocation: they will be selectively enabled when they are
1868 * assigned by the special SETREG opcodes.
1871 dest_mask = src1_mask = src2_mask = cur_iregs;
1872 /* update for use with FP regs... */
1873 if (spec [MONO_INST_DEST] == 'f') {
1874 dest_mask = cur_fregs;
1875 if (ins->dreg >= MONO_MAX_FREGS) {
1876 val = rs->fassign [ins->dreg];
1877 prev_dreg = ins->dreg;
1881 /* the register gets spilled after this inst */
1884 val = mono_regstate_alloc_float (rs, dest_mask);
1886 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1887 rs->fassign [ins->dreg] = val;
1889 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
1891 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1892 rs->fsymbolic [val] = prev_dreg;
1894 if (spec [MONO_INST_CLOB] == 'c' && ins->dreg != ppc_f1) {
1895 /* this instruction only outputs to ppc_f1, need to copy */
1896 create_copy_ins_float (cfg, ins->dreg, ppc_f1, ins);
1901 if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
1902 DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfof [prev_dreg].born_in));
1903 mono_regstate_free_float (rs, ins->dreg);
1905 } else if (ins->dreg >= MONO_MAX_IREGS) {
1906 val = rs->iassign [ins->dreg];
1907 prev_dreg = ins->dreg;
1911 /* the register gets spilled after this inst */
1914 val = mono_regstate_alloc_int (rs, dest_mask);
1916 val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1917 rs->iassign [ins->dreg] = val;
1919 create_spilled_store (cfg, spill, val, prev_dreg, ins);
1921 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1922 rs->isymbolic [val] = prev_dreg;
1924 if (spec [MONO_INST_DEST] == 'l') {
1925 int hreg = prev_dreg + 1;
1926 val = rs->iassign [hreg];
1930 /* the register gets spilled after this inst */
1933 val = mono_regstate_alloc_int (rs, dest_mask);
1935 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1936 rs->iassign [hreg] = val;
1938 create_spilled_store (cfg, spill, val, hreg, ins);
1940 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1941 rs->isymbolic [val] = hreg;
1942 /* FIXME:? ins->dreg = val; */
1943 if (ins->dreg == ppc_r4) {
1945 create_copy_ins (cfg, val, ppc_r3, ins);
1946 } else if (ins->dreg == ppc_r3) {
1947 if (val == ppc_r4) {
1949 create_copy_ins (cfg, ppc_r4, ppc_r0, ins);
1950 create_copy_ins (cfg, ppc_r3, ppc_r4, ins);
1951 create_copy_ins (cfg, ppc_r0, ppc_r3, ins);
1953 /* two forced copies */
1954 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1955 create_copy_ins (cfg, val, ppc_r3, ins);
1958 if (val == ppc_r3) {
1959 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1961 /* two forced copies */
1962 create_copy_ins (cfg, val, ppc_r3, ins);
1963 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1966 if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
1967 DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1968 mono_regstate_free_int (rs, val);
1970 } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != ppc_r3 && spec [MONO_INST_CLOB] != 'd') {
1971 /* this instruction only outputs to ppc_r3, need to copy */
1972 create_copy_ins (cfg, ins->dreg, ppc_r3, ins);
1977 if (spec [MONO_INST_DEST] == 'f' && freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfof [prev_dreg].born_in >= i)) {
1978 DEBUG (g_print ("\tfreeable float %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfof [prev_dreg].born_in));
1979 mono_regstate_free_float (rs, ins->dreg);
1980 } else if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
1981 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1982 mono_regstate_free_int (rs, ins->dreg);
1984 if (spec [MONO_INST_SRC1] == 'f') {
1985 src1_mask = cur_fregs;
1986 if (ins->sreg1 >= MONO_MAX_FREGS) {
1987 val = rs->fassign [ins->sreg1];
1988 prev_sreg1 = ins->sreg1;
1992 /* the register gets spilled after this inst */
1995 //g_assert (val == -1); /* source cannot be spilled */
1996 val = mono_regstate_alloc_float (rs, src1_mask);
1998 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1999 rs->fassign [ins->sreg1] = val;
2000 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2002 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
2003 insert_before_ins (ins, tmp, store);
2006 rs->fsymbolic [val] = prev_sreg1;
2011 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
2012 val = rs->iassign [ins->sreg1];
2013 prev_sreg1 = ins->sreg1;
2017 /* the register gets spilled after this inst */
2020 if (0 && ins->opcode == OP_MOVE) {
2022 * small optimization: the dest register is already allocated
2023 * but the src one is not: we can simply assign the same register
2024 * here and peephole will get rid of the instruction later.
2025 * This optimization may interfere with the clobbering handling:
2026 * it removes a mov operation that will be added again to handle clobbering.
2027 * There are also some other issues that should with make testjit.
2029 mono_regstate_alloc_int (rs, 1 << ins->dreg);
2030 val = rs->iassign [ins->sreg1] = ins->dreg;
2031 //g_assert (val >= 0);
2032 DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2034 //g_assert (val == -1); /* source cannot be spilled */
2035 val = mono_regstate_alloc_int (rs, src1_mask);
2037 val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
2038 rs->iassign [ins->sreg1] = val;
2039 DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
2042 MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
2043 insert_before_ins (ins, tmp, store);
2046 rs->isymbolic [val] = prev_sreg1;
2051 if (spec [MONO_INST_SRC2] == 'f') {
2052 src2_mask = cur_fregs;
2053 if (ins->sreg2 >= MONO_MAX_FREGS) {
2054 val = rs->fassign [ins->sreg2];
2055 prev_sreg2 = ins->sreg2;
2059 /* the register gets spilled after this inst */
2062 val = mono_regstate_alloc_float (rs, src2_mask);
2064 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2065 rs->fassign [ins->sreg2] = val;
2066 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2068 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
2070 rs->fsymbolic [val] = prev_sreg2;
2075 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
2076 val = rs->iassign [ins->sreg2];
2077 prev_sreg2 = ins->sreg2;
2081 /* the register gets spilled after this inst */
2084 val = mono_regstate_alloc_int (rs, src2_mask);
2086 val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2087 rs->iassign [ins->sreg2] = val;
2088 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2090 create_spilled_store (cfg, spill, val, prev_sreg2, ins);
2092 rs->isymbolic [val] = prev_sreg2;
2098 if (spec [MONO_INST_CLOB] == 'c') {
2100 guint32 clob_mask = PPC_CALLER_REGS;
2101 for (j = 0; j < MONO_MAX_IREGS; ++j) {
2103 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
2104 //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2108 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2109 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2110 mono_regstate_free_int (rs, ins->sreg1);
2112 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2113 DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2114 mono_regstate_free_int (rs, ins->sreg2);
2117 //DEBUG (print_ins (i, ins));
2120 cfg->max_ireg = MAX (cfg->max_ireg, rs->max_ireg);
2124 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2126 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2127 ppc_fctiwz (code, ppc_f0, sreg);
2128 ppc_stfd (code, ppc_f0, -8, ppc_sp);
2129 ppc_lwz (code, dreg, -4, ppc_sp);
2132 ppc_andid (code, dreg, dreg, 0xff);
2134 ppc_andid (code, dreg, dreg, 0xffff);
2137 ppc_extsb (code, dreg, dreg);
2139 ppc_extsh (code, dreg, dreg);
2144 static unsigned char*
2145 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2148 int sreg = tree->sreg1;
2149 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2150 if (tree->flags & MONO_INST_INIT) {
2152 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2153 x86_push_reg (code, X86_EAX);
2156 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2157 x86_push_reg (code, X86_ECX);
2160 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2161 x86_push_reg (code, X86_EDI);
2165 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2166 if (sreg != X86_ECX)
2167 x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2168 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2170 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2172 x86_prefix (code, X86_REP_PREFIX);
2175 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2176 x86_pop_reg (code, X86_EDI);
2177 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2178 x86_pop_reg (code, X86_ECX);
2179 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2180 x86_pop_reg (code, X86_EAX);
2193 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2196 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2197 PatchData *pdata = (PatchData*)user_data;
2198 guchar *code = data;
2199 guint32 *thunks = data;
2200 guint32 *endthunks = (guint32*)(code + bsize);
2204 int difflow, diffhigh;
2206 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2207 difflow = (char*)pdata->code - (char*)thunks;
2208 diffhigh = (char*)pdata->code - (char*)endthunks;
2209 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2212 templ = (guchar*)load;
2213 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2214 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2216 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2217 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2218 while (thunks < endthunks) {
2219 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2220 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2221 ppc_patch (pdata->code, (guchar*)thunks);
2222 mono_arch_flush_icache (pdata->code, 4);
2225 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2226 /* found a free slot instead: emit thunk */
2227 code = (guchar*)thunks;
2228 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2229 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2230 ppc_mtctr (code, ppc_r0);
2231 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2232 mono_arch_flush_icache ((guchar*)thunks, 16);
2234 ppc_patch (pdata->code, (guchar*)thunks);
2235 mono_arch_flush_icache (pdata->code, 4);
2239 /* skip 16 bytes, the size of the thunk */
2243 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2249 handle_thunk (int absolute, guchar *code, guchar *target) {
2250 MonoDomain *domain = mono_domain_get ();
2254 pdata.target = target;
2255 pdata.absolute = absolute;
2258 mono_domain_lock (domain);
2259 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2262 /* this uses the first available slot */
2264 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2266 mono_domain_unlock (domain);
2268 if (pdata.found != 1)
2269 g_print ("thunk failed for %p from %p\n", target, code);
2270 g_assert (pdata.found == 1);
2274 ppc_patch (guchar *code, guchar *target)
2276 guint32 ins = *(guint32*)code;
2277 guint32 prim = ins >> 26;
2280 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2282 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2283 gint diff = target - code;
2285 if (diff <= 33554431){
2286 ins = (18 << 26) | (diff) | (ins & 1);
2287 *(guint32*)code = ins;
2291 /* diff between 0 and -33554432 */
2292 if (diff >= -33554432){
2293 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2294 *(guint32*)code = ins;
2299 if ((glong)target >= 0){
2300 if ((glong)target <= 33554431){
2301 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2302 *(guint32*)code = ins;
2306 if ((glong)target >= -33554432){
2307 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2308 *(guint32*)code = ins;
2313 handle_thunk (TRUE, code, target);
2316 g_assert_not_reached ();
2323 guint32 li = (guint32)target;
2324 ins = (ins & 0xffff0000) | (ins & 3);
2325 ovf = li & 0xffff0000;
2326 if (ovf != 0 && ovf != 0xffff0000)
2327 g_assert_not_reached ();
2330 // FIXME: assert the top bits of li are 0
2332 gint diff = target - code;
2333 ins = (ins & 0xffff0000) | (ins & 3);
2334 ovf = diff & 0xffff0000;
2335 if (ovf != 0 && ovf != 0xffff0000)
2336 g_assert_not_reached ();
2340 *(guint32*)code = ins;
2344 if (prim == 15 || ins == 0x4e800021) {
2346 /* the trampoline code will try to patch the blrl */
2347 if (ins == 0x4e800021) {
2350 /* this is the lis/ori/mtlr/blrl sequence */
2351 seq = (guint32*)code;
2352 g_assert ((seq [0] >> 26) == 15);
2353 g_assert ((seq [1] >> 26) == 24);
2354 g_assert ((seq [2] >> 26) == 31);
2355 g_assert (seq [3] == 0x4e800021);
2356 /* FIXME: make this thread safe */
2357 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2358 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2359 mono_arch_flush_icache (code - 8, 8);
2361 g_assert_not_reached ();
2363 // g_print ("patched with 0x%08x\n", ins);
2367 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2372 guint8 *code = cfg->native_code + cfg->code_len;
2373 MonoInst *last_ins = NULL;
2374 guint last_offset = 0;
2377 if (cfg->opt & MONO_OPT_PEEPHOLE)
2378 peephole_pass (cfg, bb);
2380 /* we don't align basic blocks of loops on ppc */
2382 if (cfg->verbose_level > 2)
2383 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2385 cpos = bb->max_offset;
2387 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2388 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2389 //g_assert (!mono_compile_aot);
2392 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2393 /* this is not thread save, but good enough */
2394 /* fixme: howto handle overflows? */
2395 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2400 offset = code - cfg->native_code;
2402 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2404 if (offset > (cfg->code_size - max_len - 16)) {
2405 cfg->code_size *= 2;
2406 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2407 code = cfg->native_code + offset;
2409 // if (ins->cil_code)
2410 // g_print ("cil code\n");
2411 mono_debug_record_line_number (cfg, ins, offset);
2413 switch (ins->opcode) {
2415 emit_tls_access (code, ins->dreg, ins->inst_offset);
2418 ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2419 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2422 ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2423 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2425 case OP_STOREI1_MEMBASE_IMM:
2426 ppc_li (code, ppc_r0, ins->inst_imm);
2427 if (ppc_is_imm16 (ins->inst_offset)) {
2428 ppc_stb (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg);
2430 ppc_load (code, ppc_r11, ins->inst_offset);
2431 ppc_stbx (code, ppc_r0, ppc_r11, ins->inst_destbasereg);
2434 case OP_STOREI2_MEMBASE_IMM:
2435 ppc_li (code, ppc_r0, ins->inst_imm);
2436 if (ppc_is_imm16 (ins->inst_offset)) {
2437 ppc_sth (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg);
2439 ppc_load (code, ppc_r11, ins->inst_offset);
2440 ppc_sthx (code, ppc_r0, ppc_r11, ins->inst_destbasereg);
2443 case OP_STORE_MEMBASE_IMM:
2444 case OP_STOREI4_MEMBASE_IMM:
2445 ppc_load (code, ppc_r0, ins->inst_imm);
2446 if (ppc_is_imm16 (ins->inst_offset)) {
2447 ppc_stw (code, ppc_r0, ins->inst_offset, ins->inst_destbasereg);
2449 ppc_load (code, ppc_r11, ins->inst_offset);
2450 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_destbasereg);
2453 case OP_STOREI1_MEMBASE_REG:
2454 if (ppc_is_imm16 (ins->inst_offset)) {
2455 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2457 ppc_load (code, ppc_r11, ins->inst_offset);
2458 ppc_stbx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg);
2461 case OP_STOREI2_MEMBASE_REG:
2462 if (ppc_is_imm16 (ins->inst_offset)) {
2463 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2465 ppc_load (code, ppc_r11, ins->inst_offset);
2466 ppc_sthx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg);
2469 case OP_STORE_MEMBASE_REG:
2470 case OP_STOREI4_MEMBASE_REG:
2471 if (ppc_is_imm16 (ins->inst_offset)) {
2472 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2474 ppc_load (code, ppc_r11, ins->inst_offset);
2475 ppc_stwx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg);
2481 g_assert_not_reached ();
2482 //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2485 g_assert_not_reached ();
2486 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2487 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2489 case OP_LOAD_MEMBASE:
2490 case OP_LOADI4_MEMBASE:
2491 case OP_LOADU4_MEMBASE:
2492 if (ppc_is_imm16 (ins->inst_offset)) {
2493 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2495 ppc_load (code, ppc_r11, ins->inst_offset);
2496 ppc_lwzx (code, ins->dreg, ppc_r11, ins->inst_basereg);
2499 case OP_LOADI1_MEMBASE:
2500 case OP_LOADU1_MEMBASE:
2501 if (ppc_is_imm16 (ins->inst_offset)) {
2502 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2504 ppc_load (code, ppc_r11, ins->inst_offset);
2505 ppc_lbzx (code, ins->dreg, ppc_r11, ins->inst_basereg);
2507 if (ins->opcode == OP_LOADI1_MEMBASE)
2508 ppc_extsb (code, ins->dreg, ins->dreg);
2510 case OP_LOADU2_MEMBASE:
2511 if (ppc_is_imm16 (ins->inst_offset)) {
2512 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2514 ppc_load (code, ppc_r11, ins->inst_offset);
2515 ppc_lhzx (code, ins->dreg, ppc_r11, ins->inst_basereg);
2518 case OP_LOADI2_MEMBASE:
2519 if (ppc_is_imm16 (ins->inst_offset)) {
2520 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2522 ppc_load (code, ppc_r11, ins->inst_offset);
2523 ppc_lhax (code, ins->dreg, ppc_r11, ins->inst_basereg);
2527 ppc_extsb (code, ins->dreg, ins->sreg1);
2530 ppc_extsh (code, ins->dreg, ins->sreg1);
2533 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2536 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2540 ((ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN) ||
2541 (ins->next->opcode >= OP_COND_EXC_NE_UN && ins->next->opcode <= OP_COND_EXC_LT_UN) ||
2542 (ins->next->opcode == OP_CLT_UN || ins->next->opcode == OP_CGT_UN)))
2543 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2545 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2547 case OP_COMPARE_IMM:
2549 ((ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN) ||
2550 (ins->next->opcode >= OP_COND_EXC_NE_UN && ins->next->opcode <= OP_COND_EXC_LT_UN) ||
2551 (ins->next->opcode == OP_CLT_UN || ins->next->opcode == OP_CGT_UN))) {
2552 if (ppc_is_uimm16 (ins->inst_imm)) {
2553 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2555 ppc_load (code, ppc_r11, ins->inst_imm);
2556 ppc_cmpl (code, 0, 0, ins->sreg1, ppc_r11);
2559 if (ppc_is_imm16 (ins->inst_imm)) {
2560 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2562 ppc_load (code, ppc_r11, ins->inst_imm);
2563 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2567 case OP_X86_TEST_NULL:
2568 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2574 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2577 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2580 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2583 if (ppc_is_imm16 (ins->inst_imm)) {
2584 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2586 ppc_load (code, ppc_r11, ins->inst_imm);
2587 ppc_addc (code, ins->dreg, ins->sreg1, ppc_r11);
2591 if (ppc_is_imm16 (ins->inst_imm)) {
2592 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2594 ppc_load (code, ppc_r11, ins->inst_imm);
2595 ppc_add (code, ins->dreg, ins->sreg1, ppc_r11);
2599 ppc_load (code, ppc_r11, ins->inst_imm);
2600 ppc_adde (code, ins->dreg, ins->sreg1, ppc_r11);
2603 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2605 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2606 ppc_mfspr (code, ppc_r0, ppc_xer);
2607 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2608 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2610 case CEE_ADD_OVF_UN:
2611 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2613 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2614 ppc_mfspr (code, ppc_r0, ppc_xer);
2615 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2616 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2619 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2621 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2622 ppc_mfspr (code, ppc_r0, ppc_xer);
2623 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2624 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2626 case CEE_SUB_OVF_UN:
2627 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2629 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2630 ppc_mfspr (code, ppc_r0, ppc_xer);
2631 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2632 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2634 case OP_ADD_OVF_CARRY:
2635 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2637 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2638 ppc_mfspr (code, ppc_r0, ppc_xer);
2639 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2640 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2642 case OP_ADD_OVF_UN_CARRY:
2643 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2645 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2646 ppc_mfspr (code, ppc_r0, ppc_xer);
2647 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2648 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2650 case OP_SUB_OVF_CARRY:
2651 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2653 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2654 ppc_mfspr (code, ppc_r0, ppc_xer);
2655 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2656 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2658 case OP_SUB_OVF_UN_CARRY:
2659 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2661 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2662 ppc_mfspr (code, ppc_r0, ppc_xer);
2663 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2664 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2667 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2670 ppc_load (code, ppc_r11, ins->inst_imm);
2671 ppc_subfc (code, ins->dreg, ppc_r11, ins->sreg1);
2674 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2677 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2680 // we add the negated value
2681 if (ppc_is_imm16 (-ins->inst_imm))
2682 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2684 ppc_load (code, ppc_r11, ins->inst_imm);
2685 ppc_sub (code, ins->dreg, ins->sreg1, ppc_r11);
2689 ppc_load (code, ppc_r11, ins->inst_imm);
2690 ppc_subfe (code, ins->dreg, ppc_r11, ins->sreg1);
2693 g_assert (ppc_is_imm16 (ins->inst_imm));
2694 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2697 ppc_subfze (code, ins->dreg, ins->sreg1);
2700 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2701 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2704 if (!(ins->inst_imm & 0xffff0000)) {
2705 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2706 } else if (!(ins->inst_imm & 0xffff)) {
2707 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2709 ppc_load (code, ppc_r11, ins->inst_imm);
2710 ppc_and (code, ins->sreg1, ins->dreg, ppc_r11);
2714 guint32 *divisor_is_m1;
2715 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2717 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2718 divisor_is_m1 = code;
2719 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2720 ppc_lis (code, ppc_r11, 0x8000);
2721 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2722 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2723 ppc_patch (divisor_is_m1, code);
2724 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2726 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2727 ppc_mfspr (code, ppc_r0, ppc_xer);
2728 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2729 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2733 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2734 ppc_mfspr (code, ppc_r0, ppc_xer);
2735 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2736 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2739 g_assert_not_reached ();
2741 ppc_load (code, ppc_r11, ins->inst_imm);
2742 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2743 ppc_mfspr (code, ppc_r0, ppc_xer);
2744 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2745 /* FIXME: use OverflowException for 0x80000000/-1 */
2746 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2750 guint32 *divisor_is_m1;
2751 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2752 divisor_is_m1 = code;
2753 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2754 ppc_lis (code, ppc_r11, 0x8000);
2755 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2756 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2757 ppc_patch (divisor_is_m1, code);
2758 ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2759 ppc_mfspr (code, ppc_r0, ppc_xer);
2760 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2761 /* FIXME: use OverflowException for 0x80000000/-1 */
2762 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2763 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2764 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2768 ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2769 ppc_mfspr (code, ppc_r0, ppc_xer);
2770 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2771 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2772 ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2773 ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2776 g_assert_not_reached ();
2778 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2781 if (!(ins->inst_imm & 0xffff0000)) {
2782 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2783 } else if (!(ins->inst_imm & 0xffff)) {
2784 ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2786 ppc_load (code, ppc_r11, ins->inst_imm);
2787 ppc_or (code, ins->sreg1, ins->dreg, ppc_r11);
2791 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2794 if (!(ins->inst_imm & 0xffff0000)) {
2795 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2796 } else if (!(ins->inst_imm & 0xffff)) {
2797 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2799 ppc_load (code, ppc_r11, ins->inst_imm);
2800 ppc_xor (code, ins->sreg1, ins->dreg, ppc_r11);
2804 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2807 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2808 //ppc_load (code, ppc_r11, ins->inst_imm);
2809 //ppc_slw (code, ins->sreg1, ins->dreg, ppc_r11);
2812 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2815 // there is also ppc_srawi
2816 //ppc_load (code, ppc_r11, ins->inst_imm);
2817 //ppc_sraw (code, ins->dreg, ins->sreg1, ppc_r11);
2818 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2821 /*ppc_load (code, ppc_r11, ins->inst_imm);
2822 ppc_srw (code, ins->dreg, ins->sreg1, ppc_r11);*/
2823 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2826 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2829 ppc_not (code, ins->dreg, ins->sreg1);
2832 ppc_neg (code, ins->dreg, ins->sreg1);
2835 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2838 if (ppc_is_imm16 (ins->inst_imm)) {
2839 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2841 ppc_load (code, ppc_r11, ins->inst_imm);
2842 ppc_mullw (code, ins->dreg, ins->sreg1, ppc_r11);
2846 /* we annot use mcrxr, since it's not implemented on some processors
2847 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2849 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2850 ppc_mfspr (code, ppc_r0, ppc_xer);
2851 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2852 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2854 case CEE_MUL_OVF_UN:
2855 /* we first multiply to get the high word and compare to 0
2856 * to set the flags, then the result is discarded and then
2857 * we multiply to get the lower * bits result
2859 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2860 ppc_cmpi (code, 0, 0, ppc_r0, 0);
2861 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2862 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2866 ppc_load (code, ins->dreg, ins->inst_c0);
2869 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2870 ppc_lis (code, ins->dreg, 0);
2871 ppc_ori (code, ins->dreg, ins->dreg, 0);
2877 ppc_mr (code, ins->dreg, ins->sreg1);
2880 int saved = ins->sreg1;
2881 if (ins->sreg1 == ppc_r3) {
2882 ppc_mr (code, ppc_r0, ins->sreg1);
2885 if (ins->sreg2 != ppc_r3)
2886 ppc_mr (code, ppc_r3, ins->sreg2);
2887 if (saved != ppc_r4)
2888 ppc_mr (code, ppc_r4, saved);
2893 ppc_fmr (code, ins->dreg, ins->sreg1);
2895 case OP_FCONV_TO_R4:
2896 ppc_frsp (code, ins->dreg, ins->sreg1);
2902 * Keep in sync with mono_arch_emit_epilog
2904 g_assert (!cfg->method->save_lmf);
2905 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2906 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2907 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2909 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2910 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2912 ppc_mtlr (code, ppc_r0);
2914 if (ppc_is_imm16 (cfg->stack_usage)) {
2915 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2917 ppc_load (code, ppc_r11, cfg->stack_usage);
2918 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2920 if (!cfg->method->save_lmf) {
2921 /*for (i = 31; i >= 14; --i) {
2922 if (cfg->used_float_regs & (1 << i)) {
2923 pos += sizeof (double);
2924 ppc_lfd (code, i, -pos, cfg->frame_reg);
2927 for (i = 31; i >= 13; --i) {
2928 if (cfg->used_int_regs & (1 << i)) {
2929 pos += sizeof (gulong);
2930 ppc_lwz (code, i, -pos, cfg->frame_reg);
2934 /* FIXME restore from MonoLMF: though this can't happen yet */
2936 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2941 /* ensure ins->sreg1 is not NULL */
2942 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2945 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2946 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2948 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2949 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2951 ppc_stw (code, ppc_r11, 0, ins->sreg1);
2959 call = (MonoCallInst*)ins;
2960 if (ins->flags & MONO_INST_HAS_METHOD)
2961 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2963 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2964 if (cfg->method->dynamic) {
2965 ppc_lis (code, ppc_r0, 0);
2966 ppc_ori (code, ppc_r0, ppc_r0, 0);
2967 ppc_mtlr (code, ppc_r0);
2976 case OP_VOIDCALL_REG:
2978 ppc_mtlr (code, ins->sreg1);
2981 case OP_FCALL_MEMBASE:
2982 case OP_LCALL_MEMBASE:
2983 case OP_VCALL_MEMBASE:
2984 case OP_VOIDCALL_MEMBASE:
2985 case OP_CALL_MEMBASE:
2986 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2987 ppc_mtlr (code, ppc_r0);
2991 g_assert_not_reached ();
2994 guint32 * zero_loop_jump, zero_loop_start;
2995 /* keep alignment */
2996 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2997 int area_offset = alloca_waste;
2999 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3000 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3001 /* use ctr to store the number of words to 0 if needed */
3002 if (ins->flags & MONO_INST_INIT) {
3003 /* we zero 4 bytes at a time */
3004 ppc_addi (code, ppc_r0, ins->sreg1, 3);
3005 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3006 ppc_mtctr (code, ppc_r0);
3008 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3009 ppc_neg (code, ppc_r11, ppc_r11);
3010 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3012 if (ins->flags & MONO_INST_INIT) {
3013 /* adjust the dest reg by -4 so we can use stwu */
3014 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
3015 ppc_li (code, ppc_r11, 0);
3016 zero_loop_start = code;
3017 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3018 zero_loop_jump = code;
3019 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3020 ppc_patch (zero_loop_jump, zero_loop_start);
3022 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3030 ppc_mr (code, ppc_r3, ins->sreg1);
3031 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3032 (gpointer)"mono_arch_throw_exception");
3033 if (cfg->method->dynamic) {
3034 ppc_lis (code, ppc_r0, 0);
3035 ppc_ori (code, ppc_r0, ppc_r0, 0);
3036 ppc_mtlr (code, ppc_r0);
3045 ppc_mr (code, ppc_r3, ins->sreg1);
3046 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3047 (gpointer)"mono_arch_rethrow_exception");
3048 if (cfg->method->dynamic) {
3049 ppc_lis (code, ppc_r0, 0);
3050 ppc_ori (code, ppc_r0, ppc_r0, 0);
3051 ppc_mtlr (code, ppc_r0);
3058 case OP_START_HANDLER:
3059 ppc_mflr (code, ppc_r0);
3060 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
3061 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
3063 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
3064 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
3068 if (ins->sreg1 != ppc_r3)
3069 ppc_mr (code, ppc_r3, ins->sreg1);
3070 if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
3071 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
3073 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
3074 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
3076 ppc_mtlr (code, ppc_r0);
3079 case CEE_ENDFINALLY:
3080 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
3081 ppc_mtlr (code, ppc_r0);
3084 case OP_CALL_HANDLER:
3085 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3089 ins->inst_c0 = code - cfg->native_code;
3092 //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
3093 //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
3095 if (ins->flags & MONO_INST_BRLABEL) {
3096 /*if (ins->inst_i0->inst_c0) {
3098 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3100 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3104 /*if (ins->inst_target_bb->native_offset) {
3106 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3108 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3114 ppc_mtctr (code, ins->sreg1);
3115 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3118 ppc_li (code, ins->dreg, 0);
3119 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3120 ppc_li (code, ins->dreg, 1);
3124 ppc_li (code, ins->dreg, 1);
3125 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3126 ppc_li (code, ins->dreg, 0);
3130 ppc_li (code, ins->dreg, 1);
3131 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3132 ppc_li (code, ins->dreg, 0);
3134 case OP_COND_EXC_EQ:
3135 case OP_COND_EXC_NE_UN:
3136 case OP_COND_EXC_LT:
3137 case OP_COND_EXC_LT_UN:
3138 case OP_COND_EXC_GT:
3139 case OP_COND_EXC_GT_UN:
3140 case OP_COND_EXC_GE:
3141 case OP_COND_EXC_GE_UN:
3142 case OP_COND_EXC_LE:
3143 case OP_COND_EXC_LE_UN:
3144 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3147 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3149 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3150 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3151 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3153 case OP_COND_EXC_OV:
3154 /*ppc_mcrxr (code, 0);
3155 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3157 case OP_COND_EXC_NC:
3158 case OP_COND_EXC_NO:
3159 g_assert_not_reached ();
3171 EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
3174 /* floating point opcodes */
3176 ppc_load (code, ppc_r11, ins->inst_p0);
3177 ppc_lfd (code, ins->dreg, 0, ppc_r11);
3180 ppc_load (code, ppc_r11, ins->inst_p0);
3181 ppc_lfs (code, ins->dreg, 0, ppc_r11);
3183 case OP_STORER8_MEMBASE_REG:
3184 if (ppc_is_imm16 (ins->inst_offset)) {
3185 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3187 ppc_load (code, ppc_r11, ins->inst_offset);
3188 ppc_stfdx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg);
3191 case OP_LOADR8_MEMBASE:
3192 if (ppc_is_imm16 (ins->inst_offset)) {
3193 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3195 ppc_load (code, ppc_r11, ins->inst_offset);
3196 ppc_lfdx (code, ins->dreg, ppc_r11, ins->inst_basereg);
3199 case OP_STORER4_MEMBASE_REG:
3200 if (ppc_is_imm16 (ins->inst_offset)) {
3201 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3203 ppc_load (code, ppc_r11, ins->inst_offset);
3204 ppc_stfsx (code, ins->sreg1, ppc_r11, ins->inst_destbasereg);
3207 case OP_LOADR4_MEMBASE:
3208 if (ppc_is_imm16 (ins->inst_offset)) {
3209 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3211 ppc_load (code, ppc_r11, ins->inst_offset);
3212 ppc_lfsx (code, ins->dreg, ppc_r11, ins->inst_basereg);
3215 case CEE_CONV_R_UN: {
3216 static const guint64 adjust_val = 0x4330000000000000ULL;
3217 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
3218 ppc_stw (code, ppc_r0, -8, ppc_sp);
3219 ppc_stw (code, ins->sreg1, -4, ppc_sp);
3220 ppc_load (code, ppc_r11, &adjust_val);
3221 ppc_lfd (code, ins->dreg, -8, ppc_sp);
3222 ppc_lfd (code, ppc_f0, 0, ppc_r11);
3223 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
3226 case CEE_CONV_R4: /* FIXME: change precision */
3228 static const guint64 adjust_val = 0x4330000080000000ULL;
3229 // addis is special for ppc_r0
3230 ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
3231 ppc_stw (code, ppc_r0, -8, ppc_sp);
3232 ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
3233 ppc_stw (code, ppc_r11, -4, ppc_sp);
3234 ppc_lfd (code, ins->dreg, -8, ppc_sp);
3235 ppc_load (code, ppc_r11, &adjust_val);
3236 ppc_lfd (code, ppc_f0, 0, ppc_r11);
3237 ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
3240 case OP_X86_FP_LOAD_I8:
3241 g_assert_not_reached ();
3242 /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);*/
3244 case OP_X86_FP_LOAD_I4:
3245 g_assert_not_reached ();
3246 /*x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);*/
3248 case OP_FCONV_TO_I1:
3249 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3251 case OP_FCONV_TO_U1:
3252 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3254 case OP_FCONV_TO_I2:
3255 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3257 case OP_FCONV_TO_U2:
3258 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3260 case OP_FCONV_TO_I4:
3262 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3264 case OP_FCONV_TO_U4:
3266 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3268 case OP_FCONV_TO_I8:
3269 case OP_FCONV_TO_U8:
3270 g_assert_not_reached ();
3271 /* Implemented as helper calls */
3273 case OP_LCONV_TO_R_UN:
3274 g_assert_not_reached ();
3275 /* Implemented as helper calls */
3277 case OP_LCONV_TO_OVF_I: {
3278 guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3279 // Check if its negative
3280 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3281 negative_branch = code;
3282 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3283 // Its positive msword == 0
3284 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3285 msword_positive_branch = code;
3286 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3288 ovf_ex_target = code;
3289 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3291 ppc_patch (negative_branch, code);
3292 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3293 msword_negative_branch = code;
3294 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3295 ppc_patch (msword_negative_branch, ovf_ex_target);
3297 ppc_patch (msword_positive_branch, code);
3298 if (ins->dreg != ins->sreg1)
3299 ppc_mr (code, ins->dreg, ins->sreg1);
3303 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3306 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3309 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3312 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3315 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3318 ppc_fneg (code, ins->dreg, ins->sreg1);
3322 g_assert_not_reached ();
3325 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3328 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3329 ppc_li (code, ins->dreg, 0);
3330 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3331 ppc_li (code, ins->dreg, 1);
3334 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3335 ppc_li (code, ins->dreg, 1);
3336 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3337 ppc_li (code, ins->dreg, 0);
3340 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3341 ppc_li (code, ins->dreg, 1);
3342 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3343 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3344 ppc_li (code, ins->dreg, 0);
3347 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3348 ppc_li (code, ins->dreg, 1);
3349 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3350 ppc_li (code, ins->dreg, 0);
3353 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3354 ppc_li (code, ins->dreg, 1);
3355 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3356 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3357 ppc_li (code, ins->dreg, 0);
3360 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3363 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3366 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3369 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3370 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3373 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3376 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3377 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3380 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3383 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3386 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3389 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3391 case CEE_CKFINITE: {
3392 ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3393 ppc_lwz (code, ppc_r11, -8, ppc_sp);
3394 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3395 ppc_addis (code, ppc_r11, ppc_r11, -32752);
3396 ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3397 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3401 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3402 g_assert_not_reached ();
3405 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3406 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3407 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3408 g_assert_not_reached ();
3414 last_offset = offset;
3419 cfg->code_len = code - cfg->native_code;
3423 mono_arch_register_lowlevel_calls (void)
3427 #define patch_lis_ori(ip,val) do {\
3428 guint16 *__lis_ori = (guint16*)(ip); \
3429 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3430 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3434 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3436 MonoJumpInfo *patch_info;
3438 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3439 unsigned char *ip = patch_info->ip.i + code;
3440 const unsigned char *target;
3442 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3444 switch (patch_info->type) {
3445 case MONO_PATCH_INFO_IP:
3446 patch_lis_ori (ip, ip);
3448 case MONO_PATCH_INFO_METHOD_REL:
3449 g_assert_not_reached ();
3450 *((gpointer *)(ip)) = code + patch_info->data.offset;
3452 case MONO_PATCH_INFO_SWITCH: {
3453 gpointer *table = (gpointer *)patch_info->data.table->table;
3456 // FIXME: inspect code to get the register
3457 ppc_load (ip, ppc_r11, table);
3458 //*((gconstpointer *)(ip + 2)) = patch_info->data.target;
3460 for (i = 0; i < patch_info->data.table->table_size; i++) {
3461 table [i] = (int)patch_info->data.table->table [i] + code;
3463 /* we put into the table the absolute address, no need for ppc_patch in this case */
3466 case MONO_PATCH_INFO_METHODCONST:
3467 case MONO_PATCH_INFO_CLASS:
3468 case MONO_PATCH_INFO_IMAGE:
3469 case MONO_PATCH_INFO_FIELD:
3470 case MONO_PATCH_INFO_VTABLE:
3471 case MONO_PATCH_INFO_IID:
3472 case MONO_PATCH_INFO_SFLDA:
3473 case MONO_PATCH_INFO_LDSTR:
3474 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3475 case MONO_PATCH_INFO_LDTOKEN:
3476 /* from OP_AOTCONST : lis + ori */
3477 patch_lis_ori (ip, target);
3479 case MONO_PATCH_INFO_R4:
3480 case MONO_PATCH_INFO_R8:
3481 g_assert_not_reached ();
3482 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3484 case MONO_PATCH_INFO_EXC_NAME:
3485 g_assert_not_reached ();
3486 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3488 case MONO_PATCH_INFO_NONE:
3489 case MONO_PATCH_INFO_BB_OVF:
3490 case MONO_PATCH_INFO_EXC_OVF:
3491 /* everything is dealt with at epilog output time */
3496 ppc_patch (ip, target);
3501 * Stack frame layout:
3503 * ------------------- sp
3504 * MonoLMF structure or saved registers
3505 * -------------------
3507 * -------------------
3509 * -------------------
3510 * optional 8 bytes for tracing
3511 * -------------------
3512 * param area size is cfg->param_area
3513 * -------------------
3514 * linkage area size is PPC_STACK_PARAM_OFFSET
3515 * ------------------- sp
3519 mono_arch_emit_prolog (MonoCompile *cfg)
3521 MonoMethod *method = cfg->method;
3523 MonoMethodSignature *sig;
3525 int alloc_size, pos, max_offset, i;
3531 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3534 sig = mono_method_signature (method);
3535 cfg->code_size = 256 + sig->param_count * 20;
3536 code = cfg->native_code = g_malloc (cfg->code_size);
3538 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3539 ppc_mflr (code, ppc_r0);
3540 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3542 if (cfg->max_ireg >= 29)
3543 cfg->used_int_regs |= USE_EXTRA_TEMPS;
3545 alloc_size = cfg->stack_offset;
3548 if (!method->save_lmf) {
3549 /*for (i = 31; i >= 14; --i) {
3550 if (cfg->used_float_regs & (1 << i)) {
3551 pos += sizeof (gdouble);
3552 ppc_stfd (code, i, -pos, ppc_sp);
3555 for (i = 31; i >= 13; --i) {
3556 if (cfg->used_int_regs & (1 << i)) {
3557 pos += sizeof (gulong);
3558 ppc_stw (code, i, -pos, ppc_sp);
3563 pos += sizeof (MonoLMF);
3565 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3566 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3567 for (i = 14; i < 32; i++) {
3568 ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3572 // align to PPC_STACK_ALIGNMENT bytes
3573 if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3574 alloc_size += PPC_STACK_ALIGNMENT - 1;
3575 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3578 cfg->stack_usage = alloc_size;
3579 g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3581 if (ppc_is_imm16 (-alloc_size)) {
3582 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3584 ppc_load (code, ppc_r11, -alloc_size);
3585 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3588 if (cfg->frame_reg != ppc_sp)
3589 ppc_mr (code, cfg->frame_reg, ppc_sp);
3591 /* compute max_offset in order to use short forward jumps
3592 * we always do it on ppc because the immediate displacement
3593 * for jumps is too small
3596 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3597 MonoInst *ins = bb->code;
3598 bb->max_offset = max_offset;
3600 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3604 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3609 /* load arguments allocated to register from the stack */
3612 cinfo = calculate_sizes (sig, sig->pinvoke);
3614 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3615 ArgInfo *ainfo = &cinfo->ret;
3617 if (ppc_is_imm16 (inst->inst_offset)) {
3618 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3620 ppc_load (code, ppc_r11, inst->inst_offset);
3621 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3624 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3625 ArgInfo *ainfo = cinfo->args + i;
3626 inst = cfg->varinfo [pos];
3628 if (cfg->verbose_level > 2)
3629 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3630 if (inst->opcode == OP_REGVAR) {
3631 if (ainfo->regtype == RegTypeGeneral)
3632 ppc_mr (code, inst->dreg, ainfo->reg);
3633 else if (ainfo->regtype == RegTypeFP)
3634 ppc_fmr (code, inst->dreg, ainfo->reg);
3635 else if (ainfo->regtype == RegTypeBase) {
3636 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3637 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3639 g_assert_not_reached ();
3641 if (cfg->verbose_level > 2)
3642 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3644 /* the argument should be put on the stack: FIXME handle size != word */
3645 if (ainfo->regtype == RegTypeGeneral) {
3646 switch (ainfo->size) {
3648 if (ppc_is_imm16 (inst->inst_offset)) {
3649 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3651 ppc_load (code, ppc_r11, inst->inst_offset);
3652 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3656 if (ppc_is_imm16 (inst->inst_offset)) {
3657 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3659 ppc_load (code, ppc_r11, inst->inst_offset);
3660 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3664 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3665 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3666 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3668 ppc_load (code, ppc_r11, inst->inst_offset);
3669 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3670 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3671 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3675 if (ppc_is_imm16 (inst->inst_offset)) {
3676 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3678 ppc_load (code, ppc_r11, inst->inst_offset);
3679 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3683 } else if (ainfo->regtype == RegTypeBase) {
3684 /* load the previous stack pointer in r11 */
3685 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3686 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3687 switch (ainfo->size) {
3689 if (ppc_is_imm16 (inst->inst_offset)) {
3690 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3692 ppc_load (code, ppc_r11, inst->inst_offset);
3693 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3697 if (ppc_is_imm16 (inst->inst_offset)) {
3698 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3700 ppc_load (code, ppc_r11, inst->inst_offset);
3701 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3705 if (ppc_is_imm16 (inst->inst_offset + 4)) {
3706 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3707 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3708 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3711 g_assert_not_reached ();
3715 if (ppc_is_imm16 (inst->inst_offset)) {
3716 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3718 ppc_load (code, ppc_r11, inst->inst_offset);
3719 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3723 } else if (ainfo->regtype == RegTypeFP) {
3724 g_assert (ppc_is_imm16 (inst->inst_offset));
3725 if (ainfo->size == 8)
3726 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3727 else if (ainfo->size == 4)
3728 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3730 g_assert_not_reached ();
3731 } else if (ainfo->regtype == RegTypeStructByVal) {
3732 int doffset = inst->inst_offset;
3736 g_assert (ppc_is_imm16 (inst->inst_offset));
3737 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3738 if (mono_class_from_mono_type (inst->inst_vtype))
3739 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3740 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3742 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3743 register. Should this case include linux/ppc?
3747 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3749 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3752 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3753 soffset += sizeof (gpointer);
3754 doffset += sizeof (gpointer);
3756 if (ainfo->vtsize) {
3757 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3758 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3759 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3760 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3762 } else if (ainfo->regtype == RegTypeStructByAddr) {
3763 g_assert (ppc_is_imm16 (inst->inst_offset));
3764 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3765 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3767 g_assert_not_reached ();
3772 if (method->save_lmf) {
3774 if (lmf_pthread_key != -1) {
3775 emit_tls_access (code, ppc_r3, lmf_pthread_key);
3776 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3777 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3779 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3780 (gpointer)"mono_get_lmf_addr");
3781 if (cfg->method->dynamic) {
3782 ppc_lis (code, ppc_r0, 0);
3783 ppc_ori (code, ppc_r0, ppc_r0, 0);
3784 ppc_mtlr (code, ppc_r0);
3790 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3791 /* lmf_offset is the offset from the previous stack pointer,
3792 * alloc_size is the total stack space allocated, so the offset
3793 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3794 * The pointer to the struct is put in ppc_r11 (new_lmf).
3795 * The callee-saved registers are already in the MonoLMF structure
3797 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3798 /* ppc_r3 is the result from mono_get_lmf_addr () */
3799 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3800 /* new_lmf->previous_lmf = *lmf_addr */
3801 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3802 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3803 /* *(lmf_addr) = r11 */
3804 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3805 /* save method info */
3806 ppc_load (code, ppc_r0, method);
3807 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3808 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3809 /* save the current IP */
3810 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3811 ppc_load (code, ppc_r0, 0x01010101);
3812 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3816 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3818 cfg->code_len = code - cfg->native_code;
3819 g_assert (cfg->code_len < cfg->code_size);
3826 mono_arch_emit_epilog (MonoCompile *cfg)
3828 MonoJumpInfo *patch_info;
3829 MonoMethod *method = cfg->method;
3831 int max_epilog_size = 16 + 20*4;
3834 if (cfg->method->save_lmf)
3835 max_epilog_size += 128;
3837 if (mono_jit_trace_calls != NULL)
3838 max_epilog_size += 50;
3840 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3841 max_epilog_size += 50;
3843 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3844 cfg->code_size *= 2;
3845 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3846 mono_jit_stats.code_reallocs++;
3850 * Keep in sync with CEE_JMP
3852 code = cfg->native_code + cfg->code_len;
3854 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3855 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3859 if (method->save_lmf) {
3861 pos += sizeof (MonoLMF);
3863 /* save the frame reg in r8 */
3864 ppc_mr (code, ppc_r8, cfg->frame_reg);
3865 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3866 /* r5 = previous_lmf */
3867 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3869 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3870 /* *(lmf_addr) = previous_lmf */
3871 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3872 /* FIXME: speedup: there is no actual need to restore the registers if
3873 * we didn't actually change them (idea from Zoltan).
3876 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3878 /*for (i = 14; i < 32; i++) {
3879 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3881 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3882 /* use the saved copy of the frame reg in r8 */
3883 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3884 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3885 ppc_mtlr (code, ppc_r0);
3887 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3889 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3890 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3891 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3893 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3894 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3896 ppc_mtlr (code, ppc_r0);
3898 if (ppc_is_imm16 (cfg->stack_usage)) {
3899 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3901 ppc_load (code, ppc_r11, cfg->stack_usage);
3902 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3905 /*for (i = 31; i >= 14; --i) {
3906 if (cfg->used_float_regs & (1 << i)) {
3907 pos += sizeof (double);
3908 ppc_lfd (code, i, -pos, ppc_sp);
3911 for (i = 31; i >= 13; --i) {
3912 if (cfg->used_int_regs & (1 << i)) {
3913 pos += sizeof (gulong);
3914 ppc_lwz (code, i, -pos, ppc_sp);
3920 cfg->code_len = code - cfg->native_code;
3922 g_assert (cfg->code_len < cfg->code_size);
3926 /* remove once throw_exception_by_name is eliminated */
3928 exception_id_by_name (const char *name)
3930 if (strcmp (name, "IndexOutOfRangeException") == 0)
3931 return MONO_EXC_INDEX_OUT_OF_RANGE;
3932 if (strcmp (name, "OverflowException") == 0)
3933 return MONO_EXC_OVERFLOW;
3934 if (strcmp (name, "ArithmeticException") == 0)
3935 return MONO_EXC_ARITHMETIC;
3936 if (strcmp (name, "DivideByZeroException") == 0)
3937 return MONO_EXC_DIVIDE_BY_ZERO;
3938 if (strcmp (name, "InvalidCastException") == 0)
3939 return MONO_EXC_INVALID_CAST;
3940 if (strcmp (name, "NullReferenceException") == 0)
3941 return MONO_EXC_NULL_REF;
3942 if (strcmp (name, "ArrayTypeMismatchException") == 0)
3943 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3944 g_error ("Unknown intrinsic exception %s\n", name);
3948 mono_arch_emit_exceptions (MonoCompile *cfg)
3950 MonoJumpInfo *patch_info;
3953 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3954 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3957 int max_epilog_size = 50;
3959 /* count the number of exception infos */
3962 * make sure we have enough space for exceptions
3963 * 24 is the simulated call to throw_exception_by_name
3965 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3966 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3967 i = exception_id_by_name (patch_info->data.target);
3968 if (!exc_throw_found [i]) {
3969 max_epilog_size += 12;
3970 exc_throw_found [i] = TRUE;
3972 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3973 max_epilog_size += 12;
3974 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF)
3975 max_epilog_size += 12;
3978 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3979 cfg->code_size *= 2;
3980 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3981 mono_jit_stats.code_reallocs++;
3984 code = cfg->native_code + cfg->code_len;
3986 /* add code to raise exceptions */
3987 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3988 switch (patch_info->type) {
3989 case MONO_PATCH_INFO_BB_OVF: {
3990 MonoOvfJump *ovfj = patch_info->data.target;
3991 unsigned char *ip = patch_info->ip.i + cfg->native_code;
3992 /* patch the initial jump */
3993 ppc_patch (ip, code);
3994 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3996 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3997 /* jump back to the true target */
3999 ip = ovfj->bb->native_offset + cfg->native_code;
4000 ppc_patch (code - 4, ip);
4003 case MONO_PATCH_INFO_EXC_OVF: {
4004 MonoOvfJump *ovfj = patch_info->data.target;
4005 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4006 /* patch the initial jump */
4007 ppc_patch (ip, code);
4008 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4010 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4011 /* jump back to the true target */
4013 ip = cfg->native_code + ovfj->ip_offset + 4;
4014 ppc_patch (code - 4, ip);
4017 case MONO_PATCH_INFO_EXC: {
4018 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4019 i = exception_id_by_name (patch_info->data.target);
4020 if (exc_throw_pos [i]) {
4021 ppc_patch (ip, exc_throw_pos [i]);
4022 patch_info->type = MONO_PATCH_INFO_NONE;
4025 exc_throw_pos [i] = code;
4027 ppc_patch (ip, code);
4028 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4029 ppc_load (code, ppc_r3, patch_info->data.target);
4030 /* we got here from a conditional call, so the calling ip is set in lr already */
4031 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4032 patch_info->data.name = "mono_arch_throw_exception_by_name";
4033 patch_info->ip.i = code - cfg->native_code;
4043 cfg->code_len = code - cfg->native_code;
4045 g_assert (cfg->code_len < cfg->code_size);
4050 try_offset_access (void *value, guint32 idx)
4052 register void* me __asm__ ("r2");
4053 void ***p = (void***)((char*)me + 284);
4054 int idx1 = idx / 32;
4055 int idx2 = idx % 32;
4058 if (value != p[idx1][idx2])
4064 setup_tls_access (void)
4067 guint32 *ins, *code;
4068 guint32 cmplwi_1023, li_0x48, blr_ins;
4069 if (tls_mode == TLS_MODE_FAILED)
4072 if (g_getenv ("MONO_NO_TLS")) {
4073 tls_mode = TLS_MODE_FAILED;
4077 if (tls_mode == TLS_MODE_DETECT) {
4078 ins = (guint32*)pthread_getspecific;
4079 /* uncond branch to the real method */
4080 if ((*ins >> 26) == 18) {
4082 val = (*ins & ~3) << 6;
4086 ins = (guint32*)val;
4088 ins = (guint32*) ((char*)ins + val);
4091 code = &cmplwi_1023;
4092 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4094 ppc_li (code, ppc_r4, 0x48);
4097 if (*ins == cmplwi_1023) {
4098 int found_lwz_284 = 0;
4099 for (ptk = 0; ptk < 20; ++ptk) {
4101 if (!*ins || *ins == blr_ins)
4103 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4108 if (!found_lwz_284) {
4109 tls_mode = TLS_MODE_FAILED;
4112 tls_mode = TLS_MODE_LTHREADS;
4113 } else if (*ins == li_0x48) {
4115 /* uncond branch to the real method */
4116 if ((*ins >> 26) == 18) {
4118 val = (*ins & ~3) << 6;
4122 ins = (guint32*)val;
4124 ins = (guint32*) ((char*)ins + val);
4127 ppc_li (code, ppc_r0, 0x7FF2);
4128 if (ins [1] == val) {
4129 /* Darwin on G4, implement */
4130 tls_mode = TLS_MODE_FAILED;
4134 ppc_mfspr (code, ppc_r3, 104);
4135 if (ins [1] != val) {
4136 tls_mode = TLS_MODE_FAILED;
4139 tls_mode = TLS_MODE_DARWIN_G5;
4142 tls_mode = TLS_MODE_FAILED;
4146 tls_mode = TLS_MODE_FAILED;
4150 if (monodomain_key == -1) {
4151 ptk = mono_domain_get_tls_key ();
4153 ptk = mono_pthread_key_for_tls (ptk);
4155 monodomain_key = ptk;
4159 if (lmf_pthread_key == -1) {
4160 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4162 /*g_print ("MonoLMF at: %d\n", ptk);*/
4163 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4164 init_tls_failed = 1;
4167 lmf_pthread_key = ptk;
4170 if (monothread_key == -1) {
4171 ptk = mono_thread_get_tls_key ();
4173 ptk = mono_pthread_key_for_tls (ptk);
4175 monothread_key = ptk;
4176 /*g_print ("thread inited: %d\n", ptk);*/
4179 /*g_print ("thread not inited yet %d\n", ptk);*/
4185 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4187 setup_tls_access ();
4191 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4196 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4198 int this_dreg = ppc_r3;
4203 /* add the this argument */
4204 if (this_reg != -1) {
4206 MONO_INST_NEW (cfg, this, OP_SETREG);
4207 this->type = this_type;
4208 this->sreg1 = this_reg;
4209 this->dreg = this_dreg;
4210 mono_bblock_add_inst (cfg->cbb, this);
4215 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
4216 vtarg->type = STACK_MP;
4217 vtarg->sreg1 = vt_reg;
4218 vtarg->dreg = ppc_r3;
4219 mono_bblock_add_inst (cfg->cbb, vtarg);
4224 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4227 MonoInst *ins = NULL;
4229 if (cmethod->klass == mono_defaults.math_class) {
4230 if (strcmp (cmethod->name, "Sqrt") == 0) {
4231 MONO_INST_NEW (cfg, ins, OP_SQRT);
4232 ins->inst_i0 = args [0];
4241 mono_arch_print_tree (MonoInst *tree, int arity)
4246 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4250 setup_tls_access ();
4251 if (monodomain_key == -1)
4254 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4255 ins->inst_offset = monodomain_key;
4260 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4264 setup_tls_access ();
4265 if (monothread_key == -1)
4268 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4269 ins->inst_offset = monothread_key;