2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
21 #include <sys/sysctl.h>
24 #define FORCE_INDIR_CALL 1
35 /* This mutex protects architecture specific caches */
36 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
37 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
38 static CRITICAL_SECTION mini_arch_mutex;
40 int mono_exc_esp_offset = 0;
41 static int tls_mode = TLS_MODE_DETECT;
42 static int lmf_pthread_key = -1;
43 static int monothread_key = -1;
44 static int monodomain_key = -1;
47 offsets_from_pthread_key (guint32 key, int *offset2)
51 *offset2 = idx2 * sizeof (gpointer);
52 return 284 + idx1 * sizeof (gpointer);
55 #define emit_linuxthreads_tls(code,dreg,key) do {\
57 off1 = offsets_from_pthread_key ((key), &off2); \
58 ppc_lwz ((code), (dreg), off1, ppc_r2); \
59 ppc_lwz ((code), (dreg), off2, (dreg)); \
62 #define emit_darwing5_tls(code,dreg,key) do {\
63 int off1 = 0x48 + key * sizeof (gpointer); \
64 ppc_mfspr ((code), (dreg), 104); \
65 ppc_lwz ((code), (dreg), off1, (dreg)); \
68 /* FIXME: ensure the sc call preserves all but r3 */
69 #define emit_darwing4_tls(code,dreg,key) do {\
70 int off1 = 0x48 + key * sizeof (gpointer); \
71 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
72 ppc_li ((code), ppc_r0, 0x7FF2); \
74 ppc_lwz ((code), (dreg), off1, ppc_r3); \
75 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
78 #define emit_tls_access(code,dreg,key) do { \
80 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
81 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
82 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
83 default: g_assert_not_reached (); \
87 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
90 inst->type = STACK_R8; \
92 inst->inst_p0 = (void*)(addr); \
93 mono_bblock_add_inst (cfg->cbb, inst); \
97 mono_arch_regname (int reg) {
98 static const char rnames[][4] = {
99 "r0", "sp", "r2", "r3", "r4",
100 "r5", "r6", "r7", "r8", "r9",
101 "r10", "r11", "r12", "r13", "r14",
102 "r15", "r16", "r17", "r18", "r19",
103 "r20", "r21", "r22", "r23", "r24",
104 "r25", "r26", "r27", "r28", "r29",
107 if (reg >= 0 && reg < 32)
113 mono_arch_fregname (int reg) {
114 static const char rnames[][4] = {
115 "f0", "f1", "f2", "f3", "f4",
116 "f5", "f6", "f7", "f8", "f9",
117 "f10", "f11", "f12", "f13", "f14",
118 "f15", "f16", "f17", "f18", "f19",
119 "f20", "f21", "f22", "f23", "f24",
120 "f25", "f26", "f27", "f28", "f29",
123 if (reg >= 0 && reg < 32)
128 /* this function overwrites r0, r11, r12 */
130 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
132 /* unrolled, use the counter in big */
133 if (size > sizeof (gpointer) * 5) {
134 int shifted = size >> 2;
135 guint8 *copy_loop_start, *copy_loop_jump;
137 ppc_load (code, ppc_r0, shifted);
138 ppc_mtctr (code, ppc_r0);
139 g_assert (sreg == ppc_r11);
140 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
141 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
142 copy_loop_start = code;
143 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
144 ppc_stwu (code, ppc_r0, 4, ppc_r12);
145 copy_loop_jump = code;
146 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
147 ppc_patch (copy_loop_jump, copy_loop_start);
149 doffset = soffset = 0;
153 ppc_lwz (code, ppc_r0, soffset, sreg);
154 ppc_stw (code, ppc_r0, doffset, dreg);
160 ppc_lhz (code, ppc_r0, soffset, sreg);
161 ppc_sth (code, ppc_r0, doffset, dreg);
167 ppc_lbz (code, ppc_r0, soffset, sreg);
168 ppc_stb (code, ppc_r0, doffset, dreg);
177 * mono_arch_get_argument_info:
178 * @csig: a method signature
179 * @param_count: the number of parameters to consider
180 * @arg_info: an array to store the result infos
182 * Gathers information on parameters such as size, alignment and
183 * padding. arg_info should be large enought to hold param_count + 1 entries.
185 * Returns the size of the activation frame.
188 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
190 int k, frame_size = 0;
191 int size, align, pad;
194 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
195 frame_size += sizeof (gpointer);
199 arg_info [0].offset = offset;
202 frame_size += sizeof (gpointer);
206 arg_info [0].size = frame_size;
208 for (k = 0; k < param_count; k++) {
211 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
213 size = mini_type_stack_size (NULL, csig->params [k], &align);
215 /* ignore alignment for now */
218 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
219 arg_info [k].pad = pad;
221 arg_info [k + 1].pad = 0;
222 arg_info [k + 1].size = size;
224 arg_info [k + 1].offset = offset;
228 align = MONO_ARCH_FRAME_ALIGNMENT;
229 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
230 arg_info [k].pad = pad;
235 /* code must point to the blrl */
237 mono_ppc_is_direct_call_sequence (guint32 *code)
239 g_assert(*code == 0x4e800021);
241 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
242 return ppc_opcode (code [-1]) == 31 &&
243 ppc_opcode (code [-2]) == 24 &&
244 ppc_opcode (code [-3]) == 15;
248 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
252 guint32* code = (guint32*)code_ptr;
256 /* This is the 'blrl' instruction */
259 /* Sanity check: instruction must be 'blrl' */
260 if (*code != 0x4e800021)
263 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
264 if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
268 /* OK, we're now at the 'blrl' instruction. Now walk backwards
269 till we get to a 'mtlr rA' */
271 if((*code & 0x7c0803a6) == 0x7c0803a6) {
273 /* Here we are: we reached the 'mtlr rA'.
274 Extract the register from the instruction */
275 reg = (*code & 0x03e00000) >> 21;
277 /* ok, this is a lwz reg, offset (vtreg)
278 * it is emitted with:
279 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
281 soff = (*code & 0xffff);
283 reg = (*code >> 16) & 0x1f;
284 g_assert (reg != ppc_r1);
285 /*g_print ("patching reg is %d\n", reg);*/
287 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
288 /* saved in the MonoLMF structure */
289 o = (gpointer)lmf->iregs [reg - 13];
296 *displacement = offset;
301 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
305 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
308 return (gpointer*)((char*)vt + displacement);
311 #define MAX_ARCH_DELEGATE_PARAMS 7
314 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
316 guint8 *code, *start;
318 /* FIXME: Support more cases */
319 if (MONO_TYPE_ISSTRUCT (sig->ret))
323 static guint8* cached = NULL;
324 mono_mini_arch_lock ();
326 mono_mini_arch_unlock ();
330 start = code = mono_global_codeman_reserve (16);
332 /* Replace the this argument with the target */
333 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
334 ppc_mtctr (code, ppc_r0);
335 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
336 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
338 g_assert ((code - start) <= 16);
340 mono_arch_flush_icache (start, 16);
342 mono_mini_arch_unlock ();
345 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
348 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
350 for (i = 0; i < sig->param_count; ++i)
351 if (!mono_is_regsize_var (sig->params [i]))
354 mono_mini_arch_lock ();
355 code = cache [sig->param_count];
357 mono_mini_arch_unlock ();
361 size = 12 + sig->param_count * 4;
362 start = code = mono_global_codeman_reserve (size);
364 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
365 ppc_mtctr (code, ppc_r0);
366 /* slide down the arguments */
367 for (i = 0; i < sig->param_count; ++i) {
368 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
370 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
372 g_assert ((code - start) <= size);
374 mono_arch_flush_icache (start, size);
375 cache [sig->param_count] = start;
376 mono_mini_arch_unlock ();
383 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
385 /* FIXME: handle returning a struct */
386 if (MONO_TYPE_ISSTRUCT (sig->ret))
387 return (gpointer)regs [ppc_r4];
388 return (gpointer)regs [ppc_r3];
392 * Initialize the cpu to execute managed code.
395 mono_arch_cpu_init (void)
400 * Initialize architecture specific code.
403 mono_arch_init (void)
405 InitializeCriticalSection (&mini_arch_mutex);
409 * Cleanup architecture specific code.
412 mono_arch_cleanup (void)
414 DeleteCriticalSection (&mini_arch_mutex);
418 * This function returns the optimizations supported on this cpu.
421 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
425 /* no ppc-specific optimizations yet */
431 is_regsize_var (MonoType *t) {
434 t = mini_type_get_underlying_type (NULL, t);
441 case MONO_TYPE_FNPTR:
443 case MONO_TYPE_OBJECT:
444 case MONO_TYPE_STRING:
445 case MONO_TYPE_CLASS:
446 case MONO_TYPE_SZARRAY:
447 case MONO_TYPE_ARRAY:
449 case MONO_TYPE_GENERICINST:
450 if (!mono_type_generic_inst_is_valuetype (t))
453 case MONO_TYPE_VALUETYPE:
460 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
465 for (i = 0; i < cfg->num_varinfo; i++) {
466 MonoInst *ins = cfg->varinfo [i];
467 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
470 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
473 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
476 /* we can only allocate 32 bit values */
477 if (is_regsize_var (ins->inst_vtype)) {
478 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
479 g_assert (i == vmv->idx);
480 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
488 mono_arch_get_global_int_regs (MonoCompile *cfg)
492 if (cfg->frame_reg != ppc_sp)
494 /* ppc_r13 is used by the system on PPC EABI */
495 for (i = 14; i < top; ++i)
496 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
502 * mono_arch_regalloc_cost:
504 * Return the cost, in number of memory references, of the action of
505 * allocating the variable VMV into a register during global register
509 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
521 mono_arch_flush_icache (guint8 *code, gint size)
524 guint8 *endp, *start;
525 static int cachelinesize = 0;
526 static int cachelineinc = 16;
528 if (!cachelinesize) {
533 mib [1] = HW_CACHELINE;
534 len = sizeof (cachelinesize);
535 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
539 cachelineinc = cachelinesize;
540 /*g_print ("setting cl size to %d\n", cachelinesize);*/
542 #elif defined(__linux__)
543 /* sadly this will work only with 2.6 kernels... */
544 FILE* f = fopen ("/proc/self/auxv", "rb");
547 while (fread (&vec, sizeof (vec), 1, f) == 1) {
548 if (vec.type == 19) {
549 cachelinesize = vec.value;
557 #elif defined(G_COMPILER_CODEWARRIOR)
561 #warning Need a way to get cache line size
567 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
568 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
569 #if defined(G_COMPILER_CODEWARRIOR)
571 for (p = start; p < endp; p += cachelineinc) {
575 for (p = start; p < endp; p += cachelineinc) {
581 for (p = start; p < endp; p += cachelineinc) {
593 for (p = start; p < endp; p += cachelineinc) {
594 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
597 for (p = start; p < endp; p += cachelineinc) {
598 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
603 for (p = start; p < endp; p += cachelineinc) {
604 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
612 mono_arch_flush_register_windows (void)
617 #define ALWAYS_ON_STACK(s) s
618 #define FP_ALSO_IN_REG(s) s
620 #define ALWAYS_ON_STACK(s)
621 #define FP_ALSO_IN_REG(s)
622 #define ALIGN_DOUBLES
635 guint32 vtsize; /* in param area */
637 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
638 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
653 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
656 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
657 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
658 ainfo->reg = ppc_sp; /* in the caller */
659 ainfo->regtype = RegTypeBase;
662 ALWAYS_ON_STACK (*stack_size += 4);
666 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
668 //*stack_size += (*stack_size % 8);
670 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
671 ainfo->reg = ppc_sp; /* in the caller */
672 ainfo->regtype = RegTypeBase;
679 ALWAYS_ON_STACK (*stack_size += 8);
689 has_only_a_r48_field (MonoClass *klass)
693 gboolean have_field = FALSE;
695 while ((f = mono_class_get_fields (klass, &iter))) {
696 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
699 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
710 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
713 int n = sig->hasthis + sig->param_count;
715 guint32 stack_size = 0;
716 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
718 fr = PPC_FIRST_FPARG_REG;
719 gr = PPC_FIRST_ARG_REG;
721 /* FIXME: handle returning a struct */
722 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
723 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
724 cinfo->struct_ret = PPC_FIRST_ARG_REG;
729 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
732 DEBUG(printf("params: %d\n", sig->param_count));
733 for (i = 0; i < sig->param_count; ++i) {
734 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
735 /* Prevent implicit arguments and sig_cookie from
736 being passed in registers */
737 gr = PPC_LAST_ARG_REG + 1;
738 /* FIXME: don't we have to set fr, too? */
739 /* Emit the signature cookie just before the implicit arguments */
740 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
742 DEBUG(printf("param %d: ", i));
743 if (sig->params [i]->byref) {
744 DEBUG(printf("byref\n"));
745 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
749 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
750 switch (simpletype) {
751 case MONO_TYPE_BOOLEAN:
754 cinfo->args [n].size = 1;
755 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
761 cinfo->args [n].size = 2;
762 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
767 cinfo->args [n].size = 4;
768 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
774 case MONO_TYPE_FNPTR:
775 case MONO_TYPE_CLASS:
776 case MONO_TYPE_OBJECT:
777 case MONO_TYPE_STRING:
778 case MONO_TYPE_SZARRAY:
779 case MONO_TYPE_ARRAY:
780 cinfo->args [n].size = sizeof (gpointer);
781 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
784 case MONO_TYPE_GENERICINST:
785 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
786 cinfo->args [n].size = sizeof (gpointer);
787 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
792 case MONO_TYPE_VALUETYPE: {
795 klass = mono_class_from_mono_type (sig->params [i]);
797 size = mono_class_native_size (klass, NULL);
799 size = mono_class_value_size (klass, NULL);
801 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
802 cinfo->args [n].size = size;
804 /* It was 7, now it is 8 in LinuxPPC */
805 if (fr <= PPC_LAST_FPARG_REG) {
806 cinfo->args [n].regtype = RegTypeFP;
807 cinfo->args [n].reg = fr;
809 FP_ALSO_IN_REG (gr ++);
811 FP_ALSO_IN_REG (gr ++);
812 ALWAYS_ON_STACK (stack_size += size);
814 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
815 cinfo->args [n].regtype = RegTypeBase;
816 cinfo->args [n].reg = ppc_sp; /* in the caller*/
823 DEBUG(printf ("load %d bytes struct\n",
824 mono_class_native_size (sig->params [i]->data.klass, NULL)));
825 #if PPC_PASS_STRUCTS_BY_VALUE
827 int align_size = size;
829 int rest = PPC_LAST_ARG_REG - gr + 1;
831 align_size += (sizeof (gpointer) - 1);
832 align_size &= ~(sizeof (gpointer) - 1);
833 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
834 n_in_regs = rest >= nwords? nwords: rest;
835 cinfo->args [n].regtype = RegTypeStructByVal;
836 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
837 cinfo->args [n].size = 0;
838 cinfo->args [n].vtsize = nwords;
840 cinfo->args [n].size = n_in_regs;
841 cinfo->args [n].vtsize = nwords - n_in_regs;
842 cinfo->args [n].reg = gr;
845 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
846 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
847 stack_size += nwords * sizeof (gpointer);
850 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
851 cinfo->args [n].regtype = RegTypeStructByAddr;
852 cinfo->args [n].vtsize = size;
857 case MONO_TYPE_TYPEDBYREF: {
858 int size = sizeof (MonoTypedRef);
859 /* keep in sync or merge with the valuetype case */
860 #if PPC_PASS_STRUCTS_BY_VALUE
862 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
863 cinfo->args [n].regtype = RegTypeStructByVal;
864 if (gr <= PPC_LAST_ARG_REG) {
865 int rest = PPC_LAST_ARG_REG - gr + 1;
866 int n_in_regs = rest >= nwords? nwords: rest;
867 cinfo->args [n].size = n_in_regs;
868 cinfo->args [n].vtsize = nwords - n_in_regs;
869 cinfo->args [n].reg = gr;
872 cinfo->args [n].size = 0;
873 cinfo->args [n].vtsize = nwords;
875 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
876 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
877 stack_size += nwords * sizeof (gpointer);
880 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
881 cinfo->args [n].regtype = RegTypeStructByAddr;
882 cinfo->args [n].vtsize = size;
889 cinfo->args [n].size = 8;
890 add_general (&gr, &stack_size, cinfo->args + n, FALSE);
894 cinfo->args [n].size = 4;
896 /* It was 7, now it is 8 in LinuxPPC */
897 if (fr <= PPC_LAST_FPARG_REG) {
898 cinfo->args [n].regtype = RegTypeFP;
899 cinfo->args [n].reg = fr;
901 FP_ALSO_IN_REG (gr ++);
902 ALWAYS_ON_STACK (stack_size += 4);
904 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
905 cinfo->args [n].regtype = RegTypeBase;
906 cinfo->args [n].reg = ppc_sp; /* in the caller*/
912 cinfo->args [n].size = 8;
913 /* It was 7, now it is 8 in LinuxPPC */
914 if (fr <= PPC_LAST_FPARG_REG) {
915 cinfo->args [n].regtype = RegTypeFP;
916 cinfo->args [n].reg = fr;
918 FP_ALSO_IN_REG (gr += 2);
919 ALWAYS_ON_STACK (stack_size += 8);
921 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
922 cinfo->args [n].regtype = RegTypeBase;
923 cinfo->args [n].reg = ppc_sp; /* in the caller*/
929 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
933 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
934 /* Prevent implicit arguments and sig_cookie from
935 being passed in registers */
936 gr = PPC_LAST_ARG_REG + 1;
937 /* Emit the signature cookie just before the implicit arguments */
938 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
942 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
943 switch (simpletype) {
944 case MONO_TYPE_BOOLEAN:
955 case MONO_TYPE_FNPTR:
956 case MONO_TYPE_CLASS:
957 case MONO_TYPE_OBJECT:
958 case MONO_TYPE_SZARRAY:
959 case MONO_TYPE_ARRAY:
960 case MONO_TYPE_STRING:
961 cinfo->ret.reg = ppc_r3;
965 cinfo->ret.reg = ppc_r3;
969 cinfo->ret.reg = ppc_f1;
970 cinfo->ret.regtype = RegTypeFP;
972 case MONO_TYPE_GENERICINST:
973 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
974 cinfo->ret.reg = ppc_r3;
978 case MONO_TYPE_VALUETYPE:
980 case MONO_TYPE_TYPEDBYREF:
984 g_error ("Can't handle as return value 0x%x", sig->ret->type);
988 /* align stack size to 16 */
989 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
990 stack_size = (stack_size + 15) & ~15;
992 cinfo->stack_usage = stack_size;
997 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
999 #if !PPC_PASS_STRUCTS_BY_VALUE
1000 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1001 int num_structs = 0;
1004 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1007 for (i = 0; i < sig->param_count; ++i) {
1008 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1009 if (type->type == MONO_TYPE_VALUETYPE)
1014 cfg->tailcall_valuetype_addrs =
1015 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1016 for (i = 0; i < num_structs; ++i) {
1017 cfg->tailcall_valuetype_addrs [i] =
1018 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1019 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1026 * Set var information according to the calling convention. ppc version.
1027 * The locals var stuff should most likely be split in another method.
1030 mono_arch_allocate_vars (MonoCompile *m)
1032 MonoMethodSignature *sig;
1033 MonoMethodHeader *header;
1035 int i, offset, size, align, curinst;
1036 int frame_reg = ppc_sp;
1038 guint32 locals_stack_size, locals_stack_align;
1040 allocate_tailcall_valuetype_addrs (m);
1042 m->flags |= MONO_CFG_HAS_SPILLUP;
1044 /* allow room for the vararg method args: void* and long/double */
1045 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1046 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1047 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1048 * call convs needs to be handled this way.
1050 if (m->flags & MONO_CFG_HAS_VARARGS)
1051 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1052 /* gtk-sharp and other broken code will dllimport vararg functions even with
1053 * non-varargs signatures. Since there is little hope people will get this right
1054 * we assume they won't.
1056 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1057 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1059 header = mono_method_get_header (m->method);
1062 * We use the frame register also for any method that has
1063 * exception clauses. This way, when the handlers are called,
1064 * the code will reference local variables using the frame reg instead of
1065 * the stack pointer: if we had to restore the stack pointer, we'd
1066 * corrupt the method frames that are already on the stack (since
1067 * filters get called before stack unwinding happens) when the filter
1068 * code would call any method (this also applies to finally etc.).
1070 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1071 frame_reg = ppc_r31;
1072 m->frame_reg = frame_reg;
1073 if (frame_reg != ppc_sp) {
1074 m->used_int_regs |= 1 << frame_reg;
1077 sig = mono_method_signature (m->method);
1081 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1082 m->ret->opcode = OP_REGVAR;
1083 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1085 /* FIXME: handle long values? */
1086 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1087 case MONO_TYPE_VOID:
1091 m->ret->opcode = OP_REGVAR;
1092 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1095 m->ret->opcode = OP_REGVAR;
1096 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1100 /* local vars are at a positive offset from the stack pointer */
1102 * also note that if the function uses alloca, we use ppc_r31
1103 * to point at the local variables.
1105 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1106 /* align the offset to 16 bytes: not sure this is needed here */
1108 //offset &= ~(16 - 1);
1110 /* add parameter area size for called functions */
1111 offset += m->param_area;
1113 offset &= ~(16 - 1);
1115 /* allow room to save the return value */
1116 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1119 /* the MonoLMF structure is stored just below the stack pointer */
1122 /* this stuff should not be needed on ppc and the new jit,
1123 * because a call on ppc to the handlers doesn't change the
1124 * stack pointer and the jist doesn't manipulate the stack pointer
1125 * for operations involving valuetypes.
1127 /* reserve space to store the esp */
1128 offset += sizeof (gpointer);
1130 /* this is a global constant */
1131 mono_exc_esp_offset = offset;
1133 if (sig->call_convention == MONO_CALL_VARARG) {
1134 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1137 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1138 offset += sizeof(gpointer) - 1;
1139 offset &= ~(sizeof(gpointer) - 1);
1141 m->vret_addr->opcode = OP_REGOFFSET;
1142 m->vret_addr->inst_basereg = frame_reg;
1143 m->vret_addr->inst_offset = offset;
1145 if (G_UNLIKELY (m->verbose_level > 1)) {
1146 printf ("vret_addr =");
1147 mono_print_ins (m->vret_addr);
1150 offset += sizeof(gpointer);
1151 if (sig->call_convention == MONO_CALL_VARARG)
1152 m->sig_cookie += sizeof (gpointer);
1155 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1156 if (locals_stack_align) {
1157 offset += (locals_stack_align - 1);
1158 offset &= ~(locals_stack_align - 1);
1160 for (i = m->locals_start; i < m->num_varinfo; i++) {
1161 if (offsets [i] != -1) {
1162 MonoInst *inst = m->varinfo [i];
1163 inst->opcode = OP_REGOFFSET;
1164 inst->inst_basereg = frame_reg;
1165 inst->inst_offset = offset + offsets [i];
1167 g_print ("allocating local %d (%s) to %d\n",
1168 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1172 offset += locals_stack_size;
1176 inst = m->args [curinst];
1177 if (inst->opcode != OP_REGVAR) {
1178 inst->opcode = OP_REGOFFSET;
1179 inst->inst_basereg = frame_reg;
1180 offset += sizeof (gpointer) - 1;
1181 offset &= ~(sizeof (gpointer) - 1);
1182 inst->inst_offset = offset;
1183 offset += sizeof (gpointer);
1184 if (sig->call_convention == MONO_CALL_VARARG)
1185 m->sig_cookie += sizeof (gpointer);
1190 for (i = 0; i < sig->param_count; ++i) {
1191 inst = m->args [curinst];
1192 if (inst->opcode != OP_REGVAR) {
1193 inst->opcode = OP_REGOFFSET;
1194 inst->inst_basereg = frame_reg;
1196 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1197 inst->backend.is_pinvoke = 1;
1199 size = mono_type_size (sig->params [i], &align);
1201 offset += align - 1;
1202 offset &= ~(align - 1);
1203 inst->inst_offset = offset;
1205 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1206 m->sig_cookie += size;
1211 /* some storage for fp conversions */
1214 m->arch.fp_conv_var_offset = offset;
1217 /* align the offset to 16 bytes */
1219 offset &= ~(16 - 1);
1222 m->stack_offset = offset;
1224 if (sig->call_convention == MONO_CALL_VARARG) {
1225 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1227 m->sig_cookie = cinfo->sig_cookie.offset;
1234 mono_arch_create_vars (MonoCompile *cfg)
1236 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1238 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1239 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1243 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1244 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1248 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1250 int sig_reg = mono_alloc_ireg (cfg);
1252 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1253 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1254 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1258 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1261 MonoMethodSignature *sig;
1265 sig = call->signature;
1266 n = sig->param_count + sig->hasthis;
1268 cinfo = calculate_sizes (sig, sig->pinvoke);
1270 for (i = 0; i < n; ++i) {
1271 ArgInfo *ainfo = cinfo->args + i;
1274 if (i >= sig->hasthis)
1275 t = sig->params [i - sig->hasthis];
1277 t = &mono_defaults.int_class->byval_arg;
1278 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1280 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1281 emit_sig_cookie (cfg, call, cinfo);
1283 in = call->args [i];
1285 if (ainfo->regtype == RegTypeGeneral) {
1286 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1287 MONO_INST_NEW (cfg, ins, OP_MOVE);
1288 ins->dreg = mono_alloc_ireg (cfg);
1289 ins->sreg1 = in->dreg + 1;
1290 MONO_ADD_INS (cfg->cbb, ins);
1291 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1293 MONO_INST_NEW (cfg, ins, OP_MOVE);
1294 ins->dreg = mono_alloc_ireg (cfg);
1295 ins->sreg1 = in->dreg + 2;
1296 MONO_ADD_INS (cfg->cbb, ins);
1297 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1299 MONO_INST_NEW (cfg, ins, OP_MOVE);
1300 ins->dreg = mono_alloc_ireg (cfg);
1301 ins->sreg1 = in->dreg;
1302 MONO_ADD_INS (cfg->cbb, ins);
1304 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1306 } else if (ainfo->regtype == RegTypeStructByAddr) {
1307 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1308 ins->opcode = OP_OUTARG_VT;
1309 ins->sreg1 = in->dreg;
1310 ins->klass = in->klass;
1311 ins->inst_p0 = call;
1312 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1313 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1314 MONO_ADD_INS (cfg->cbb, ins);
1315 } else if (ainfo->regtype == RegTypeStructByVal) {
1316 /* this is further handled in mono_arch_emit_outarg_vt () */
1317 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1318 ins->opcode = OP_OUTARG_VT;
1319 ins->sreg1 = in->dreg;
1320 ins->klass = in->klass;
1321 ins->inst_p0 = call;
1322 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1323 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1324 MONO_ADD_INS (cfg->cbb, ins);
1325 } else if (ainfo->regtype == RegTypeBase) {
1326 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1327 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1328 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1329 if (t->type == MONO_TYPE_R8)
1330 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1332 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1334 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1336 } else if (ainfo->regtype == RegTypeFP) {
1337 if (t->type == MONO_TYPE_VALUETYPE) {
1338 /* this is further handled in mono_arch_emit_outarg_vt () */
1339 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1340 ins->opcode = OP_OUTARG_VT;
1341 ins->sreg1 = in->dreg;
1342 ins->klass = in->klass;
1343 ins->inst_p0 = call;
1344 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1345 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1346 MONO_ADD_INS (cfg->cbb, ins);
1348 cfg->flags |= MONO_CFG_HAS_FPOUT;
1350 int dreg = mono_alloc_freg (cfg);
1352 if (ainfo->size == 4) {
1353 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1355 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1357 ins->sreg1 = in->dreg;
1358 MONO_ADD_INS (cfg->cbb, ins);
1361 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1362 cfg->flags |= MONO_CFG_HAS_FPOUT;
1365 g_assert_not_reached ();
1369 /* Emit the signature cookie in the case that there is no
1370 additional argument */
1371 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1372 emit_sig_cookie (cfg, call, cinfo);
1374 if (cinfo->struct_ret) {
1377 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1378 vtarg->sreg1 = call->vret_var->dreg;
1379 vtarg->dreg = mono_alloc_preg (cfg);
1380 MONO_ADD_INS (cfg->cbb, vtarg);
1382 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1385 call->stack_usage = cinfo->stack_usage;
1386 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1387 cfg->flags |= MONO_CFG_HAS_CALLS;
1393 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1395 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1396 ArgInfo *ainfo = ins->inst_p1;
1397 int ovf_size = ainfo->vtsize;
1398 int doffset = ainfo->offset;
1399 int i, soffset, dreg;
1401 if (ainfo->regtype == RegTypeStructByVal) {
1406 * Darwin pinvokes needs some special handling for 1
1407 * and 2 byte arguments
1409 g_assert (ins->klass);
1410 if (call->signature->pinvoke)
1411 size = mono_class_native_size (ins->klass, NULL);
1412 if (size == 2 || size == 1) {
1413 int tmpr = mono_alloc_ireg (cfg);
1415 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1417 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1418 dreg = mono_alloc_ireg (cfg);
1419 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1420 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1423 for (i = 0; i < ainfo->size; ++i) {
1424 dreg = mono_alloc_ireg (cfg);
1425 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1426 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1427 soffset += sizeof (gpointer);
1430 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1431 } else if (ainfo->regtype == RegTypeFP) {
1432 int tmpr = mono_alloc_freg (cfg);
1433 if (ainfo->size == 4)
1434 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1436 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1437 dreg = mono_alloc_freg (cfg);
1438 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1439 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1441 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1445 /* FIXME: alignment? */
1446 if (call->signature->pinvoke) {
1447 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1448 vtcopy->backend.is_pinvoke = 1;
1450 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1453 g_assert (ovf_size > 0);
1455 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1456 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1459 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1461 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1466 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1468 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1469 mono_method_signature (method)->ret);
1472 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1475 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1476 ins->sreg1 = val->dreg + 1;
1477 ins->sreg2 = val->dreg + 2;
1478 MONO_ADD_INS (cfg->cbb, ins);
1481 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1482 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1486 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1489 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1491 mono_arch_is_inst_imm (gint64 imm)
1497 * Allow tracing to work with this interface (with an optional argument)
1501 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1505 ppc_load (code, ppc_r3, cfg->method);
1506 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1507 ppc_load (code, ppc_r0, func);
1508 ppc_mtlr (code, ppc_r0);
1522 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1525 int save_mode = SAVE_NONE;
1527 MonoMethod *method = cfg->method;
1528 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1529 mono_method_signature (method)->ret)->type;
1530 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1534 offset = code - cfg->native_code;
1535 /* we need about 16 instructions */
1536 if (offset > (cfg->code_size - 16 * 4)) {
1537 cfg->code_size *= 2;
1538 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1539 code = cfg->native_code + offset;
1543 case MONO_TYPE_VOID:
1544 /* special case string .ctor icall */
1545 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1546 save_mode = SAVE_ONE;
1548 save_mode = SAVE_NONE;
1552 save_mode = SAVE_TWO;
1556 save_mode = SAVE_FP;
1558 case MONO_TYPE_VALUETYPE:
1559 save_mode = SAVE_STRUCT;
1562 save_mode = SAVE_ONE;
1566 switch (save_mode) {
1568 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1569 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1570 if (enable_arguments) {
1571 ppc_mr (code, ppc_r5, ppc_r4);
1572 ppc_mr (code, ppc_r4, ppc_r3);
1576 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1577 if (enable_arguments) {
1578 ppc_mr (code, ppc_r4, ppc_r3);
1582 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1583 if (enable_arguments) {
1584 /* FIXME: what reg? */
1585 ppc_fmr (code, ppc_f3, ppc_f1);
1586 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1587 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1591 if (enable_arguments) {
1592 /* FIXME: get the actual address */
1593 ppc_mr (code, ppc_r4, ppc_r3);
1601 ppc_load (code, ppc_r3, cfg->method);
1602 ppc_load (code, ppc_r0, func);
1603 ppc_mtlr (code, ppc_r0);
1606 switch (save_mode) {
1608 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1609 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1612 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1615 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1625 * Conditional branches have a small offset, so if it is likely overflowed,
1626 * we do a branch to the end of the method (uncond branches have much larger
1627 * offsets) where we perform the conditional and jump back unconditionally.
1628 * It's slightly slower, since we add two uncond branches, but it's very simple
1629 * with the current patch implementation and such large methods are likely not
1630 * going to be perf critical anyway.
1635 const char *exception;
1642 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1643 if (ins->flags & MONO_INST_BRLABEL) { \
1644 if (0 && ins->inst_i0->inst_c0) { \
1645 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1647 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1648 ppc_bc (code, (b0), (b1), 0); \
1651 if (0 && ins->inst_true_bb->native_offset) { \
1652 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1654 int br_disp = ins->inst_true_bb->max_offset - offset; \
1655 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1656 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1657 ovfj->data.bb = ins->inst_true_bb; \
1658 ovfj->ip_offset = 0; \
1659 ovfj->b0_cond = (b0); \
1660 ovfj->b1_cond = (b1); \
1661 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1664 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1665 ppc_bc (code, (b0), (b1), 0); \
1670 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1672 /* emit an exception if condition is fail
1674 * We assign the extra code used to throw the implicit exceptions
1675 * to cfg->bb_exit as far as the big branch handling is concerned
1677 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1679 int br_disp = cfg->bb_exit->max_offset - offset; \
1680 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1681 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1682 ovfj->data.exception = (exc_name); \
1683 ovfj->ip_offset = code - cfg->native_code; \
1684 ovfj->b0_cond = (b0); \
1685 ovfj->b1_cond = (b1); \
1686 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1688 cfg->bb_exit->max_offset += 24; \
1690 mono_add_patch_info (cfg, code - cfg->native_code, \
1691 MONO_PATCH_INFO_EXC, exc_name); \
1692 ppc_bcl (code, (b0), (b1), 0); \
1696 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1699 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1704 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1706 MonoInst *ins, *n, *last_ins = NULL;
1708 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1709 switch (ins->opcode) {
1711 /* remove unnecessary multiplication with 1 */
1712 if (ins->inst_imm == 1) {
1713 if (ins->dreg != ins->sreg1) {
1714 ins->opcode = OP_MOVE;
1716 MONO_DELETE_INS (bb, ins);
1720 int power2 = mono_is_power_of_two (ins->inst_imm);
1722 ins->opcode = OP_SHL_IMM;
1723 ins->inst_imm = power2;
1727 case OP_LOAD_MEMBASE:
1728 case OP_LOADI4_MEMBASE:
1730 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1731 * OP_LOAD_MEMBASE offset(basereg), reg
1733 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1734 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1735 ins->inst_basereg == last_ins->inst_destbasereg &&
1736 ins->inst_offset == last_ins->inst_offset) {
1737 if (ins->dreg == last_ins->sreg1) {
1738 MONO_DELETE_INS (bb, ins);
1741 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1742 ins->opcode = OP_MOVE;
1743 ins->sreg1 = last_ins->sreg1;
1747 * Note: reg1 must be different from the basereg in the second load
1748 * OP_LOAD_MEMBASE offset(basereg), reg1
1749 * OP_LOAD_MEMBASE offset(basereg), reg2
1751 * OP_LOAD_MEMBASE offset(basereg), reg1
1752 * OP_MOVE reg1, reg2
1754 } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1755 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1756 ins->inst_basereg != last_ins->dreg &&
1757 ins->inst_basereg == last_ins->inst_basereg &&
1758 ins->inst_offset == last_ins->inst_offset) {
1760 if (ins->dreg == last_ins->dreg) {
1761 MONO_DELETE_INS (bb, ins);
1764 ins->opcode = OP_MOVE;
1765 ins->sreg1 = last_ins->dreg;
1768 //g_assert_not_reached ();
1772 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1773 * OP_LOAD_MEMBASE offset(basereg), reg
1775 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1776 * OP_ICONST reg, imm
1778 } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1779 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1780 ins->inst_basereg == last_ins->inst_destbasereg &&
1781 ins->inst_offset == last_ins->inst_offset) {
1782 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1783 ins->opcode = OP_ICONST;
1784 ins->inst_c0 = last_ins->inst_imm;
1785 g_assert_not_reached (); // check this rule
1789 case OP_LOADU1_MEMBASE:
1790 case OP_LOADI1_MEMBASE:
1791 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1792 ins->inst_basereg == last_ins->inst_destbasereg &&
1793 ins->inst_offset == last_ins->inst_offset) {
1794 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1795 ins->sreg1 = last_ins->sreg1;
1798 case OP_LOADU2_MEMBASE:
1799 case OP_LOADI2_MEMBASE:
1800 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1801 ins->inst_basereg == last_ins->inst_destbasereg &&
1802 ins->inst_offset == last_ins->inst_offset) {
1803 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1804 ins->sreg1 = last_ins->sreg1;
1808 ins->opcode = OP_MOVE;
1812 if (ins->dreg == ins->sreg1) {
1813 MONO_DELETE_INS (bb, ins);
1817 * OP_MOVE sreg, dreg
1818 * OP_MOVE dreg, sreg
1820 if (last_ins && last_ins->opcode == OP_MOVE &&
1821 ins->sreg1 == last_ins->dreg &&
1822 ins->dreg == last_ins->sreg1) {
1823 MONO_DELETE_INS (bb, ins);
1831 bb->last_ins = last_ins;
1835 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1837 switch (ins->opcode) {
1838 case OP_ICONV_TO_R_UN: {
1839 static const guint64 adjust_val = 0x4330000000000000ULL;
1840 int msw_reg = mono_alloc_ireg (cfg);
1841 int adj_reg = mono_alloc_freg (cfg);
1842 int tmp_reg = mono_alloc_freg (cfg);
1843 int basereg = ppc_sp;
1845 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1846 if (!ppc_is_imm16 (offset + 4)) {
1847 basereg = mono_alloc_ireg (cfg);
1848 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1850 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1851 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
1852 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1853 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1854 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1855 ins->opcode = OP_NOP;
1858 case OP_ICONV_TO_R4:
1859 case OP_ICONV_TO_R8: {
1860 /* FIXME: change precision for CEE_CONV_R4 */
1861 static const guint64 adjust_val = 0x4330000080000000ULL;
1862 int msw_reg = mono_alloc_ireg (cfg);
1863 int xored = mono_alloc_ireg (cfg);
1864 int adj_reg = mono_alloc_freg (cfg);
1865 int tmp_reg = mono_alloc_freg (cfg);
1866 int basereg = ppc_sp;
1868 if (!ppc_is_imm16 (offset + 4)) {
1869 basereg = mono_alloc_ireg (cfg);
1870 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1872 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1873 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1874 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
1875 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
1876 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
1877 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1878 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1879 if (ins->opcode == OP_ICONV_TO_R4)
1880 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
1881 ins->opcode = OP_NOP;
1885 int msw_reg = mono_alloc_ireg (cfg);
1886 int basereg = ppc_sp;
1888 if (!ppc_is_imm16 (offset + 4)) {
1889 basereg = mono_alloc_ireg (cfg);
1890 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1892 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
1893 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
1894 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
1895 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1896 ins->opcode = OP_NOP;
1903 * the branch_b0_table should maintain the order of these
1917 branch_b0_table [] = {
1932 branch_b1_table [] = {
1946 #define NEW_INS(cfg,dest,op) do { \
1947 MONO_INST_NEW((cfg), (dest), (op)); \
1948 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
1952 map_to_reg_reg_op (int op)
1961 case OP_COMPARE_IMM:
1963 case OP_ICOMPARE_IMM:
1979 case OP_LOAD_MEMBASE:
1980 return OP_LOAD_MEMINDEX;
1981 case OP_LOADI4_MEMBASE:
1982 return OP_LOADI4_MEMINDEX;
1983 case OP_LOADU4_MEMBASE:
1984 return OP_LOADU4_MEMINDEX;
1985 case OP_LOADU1_MEMBASE:
1986 return OP_LOADU1_MEMINDEX;
1987 case OP_LOADI2_MEMBASE:
1988 return OP_LOADI2_MEMINDEX;
1989 case OP_LOADU2_MEMBASE:
1990 return OP_LOADU2_MEMINDEX;
1991 case OP_LOADI1_MEMBASE:
1992 return OP_LOADI1_MEMINDEX;
1993 case OP_LOADR4_MEMBASE:
1994 return OP_LOADR4_MEMINDEX;
1995 case OP_LOADR8_MEMBASE:
1996 return OP_LOADR8_MEMINDEX;
1997 case OP_STOREI1_MEMBASE_REG:
1998 return OP_STOREI1_MEMINDEX;
1999 case OP_STOREI2_MEMBASE_REG:
2000 return OP_STOREI2_MEMINDEX;
2001 case OP_STOREI4_MEMBASE_REG:
2002 return OP_STOREI4_MEMINDEX;
2003 case OP_STORE_MEMBASE_REG:
2004 return OP_STORE_MEMINDEX;
2005 case OP_STORER4_MEMBASE_REG:
2006 return OP_STORER4_MEMINDEX;
2007 case OP_STORER8_MEMBASE_REG:
2008 return OP_STORER8_MEMINDEX;
2009 case OP_STORE_MEMBASE_IMM:
2010 return OP_STORE_MEMBASE_REG;
2011 case OP_STOREI1_MEMBASE_IMM:
2012 return OP_STOREI1_MEMBASE_REG;
2013 case OP_STOREI2_MEMBASE_IMM:
2014 return OP_STOREI2_MEMBASE_REG;
2015 case OP_STOREI4_MEMBASE_IMM:
2016 return OP_STOREI4_MEMBASE_REG;
2018 return mono_op_imm_to_op (op);
2021 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2023 #define compare_opcode_is_unsigned(opcode) \
2024 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2025 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2026 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2027 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2028 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2030 * Remove from the instruction list the instructions that can't be
2031 * represented with very simple instructions with no register
2035 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2037 MonoInst *ins, *next, *temp, *last_ins = NULL;
2040 MONO_BB_FOR_EACH_INS (bb, ins) {
2042 switch (ins->opcode) {
2043 case OP_IDIV_UN_IMM:
2046 case OP_IREM_UN_IMM:
2047 NEW_INS (cfg, temp, OP_ICONST);
2048 temp->inst_c0 = ins->inst_imm;
2049 temp->dreg = mono_alloc_ireg (cfg);
2050 ins->sreg2 = temp->dreg;
2051 if (ins->opcode == OP_IDIV_IMM)
2052 ins->opcode = OP_IDIV;
2053 else if (ins->opcode == OP_IREM_IMM)
2054 ins->opcode = OP_IREM;
2055 else if (ins->opcode == OP_IDIV_UN_IMM)
2056 ins->opcode = OP_IDIV_UN;
2057 else if (ins->opcode == OP_IREM_UN_IMM)
2058 ins->opcode = OP_IREM_UN;
2060 /* handle rem separately */
2065 /* we change a rem dest, src1, src2 to
2066 * div temp1, src1, src2
2067 * mul temp2, temp1, src2
2068 * sub dest, src1, temp2
2070 NEW_INS (cfg, mul, OP_IMUL);
2071 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2072 temp->sreg1 = ins->sreg1;
2073 temp->sreg2 = ins->sreg2;
2074 temp->dreg = mono_alloc_ireg (cfg);
2075 mul->sreg1 = temp->dreg;
2076 mul->sreg2 = ins->sreg2;
2077 mul->dreg = mono_alloc_ireg (cfg);
2078 ins->opcode = OP_ISUB;
2079 ins->sreg2 = mul->dreg;
2085 if (!ppc_is_imm16 (ins->inst_imm)) {
2086 NEW_INS (cfg, temp, OP_ICONST);
2087 temp->inst_c0 = ins->inst_imm;
2088 temp->dreg = mono_alloc_ireg (cfg);
2089 ins->sreg2 = temp->dreg;
2090 ins->opcode = map_to_reg_reg_op (ins->opcode);
2095 if (!ppc_is_imm16 (-ins->inst_imm)) {
2096 NEW_INS (cfg, temp, OP_ICONST);
2097 temp->inst_c0 = ins->inst_imm;
2098 temp->dreg = mono_alloc_ireg (cfg);
2099 ins->sreg2 = temp->dreg;
2100 ins->opcode = map_to_reg_reg_op (ins->opcode);
2109 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2110 NEW_INS (cfg, temp, OP_ICONST);
2111 temp->inst_c0 = ins->inst_imm;
2112 temp->dreg = mono_alloc_ireg (cfg);
2113 ins->sreg2 = temp->dreg;
2114 ins->opcode = map_to_reg_reg_op (ins->opcode);
2122 NEW_INS (cfg, temp, OP_ICONST);
2123 temp->inst_c0 = ins->inst_imm;
2124 temp->dreg = mono_alloc_ireg (cfg);
2125 ins->sreg2 = temp->dreg;
2126 ins->opcode = map_to_reg_reg_op (ins->opcode);
2128 case OP_COMPARE_IMM:
2129 case OP_ICOMPARE_IMM:
2131 /* Branch opts can eliminate the branch */
2132 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2133 ins->opcode = OP_NOP;
2137 if (compare_opcode_is_unsigned (next->opcode)) {
2138 if (!ppc_is_uimm16 (ins->inst_imm)) {
2139 NEW_INS (cfg, temp, OP_ICONST);
2140 temp->inst_c0 = ins->inst_imm;
2141 temp->dreg = mono_alloc_ireg (cfg);
2142 ins->sreg2 = temp->dreg;
2143 ins->opcode = map_to_reg_reg_op (ins->opcode);
2146 if (!ppc_is_imm16 (ins->inst_imm)) {
2147 NEW_INS (cfg, temp, OP_ICONST);
2148 temp->inst_c0 = ins->inst_imm;
2149 temp->dreg = mono_alloc_ireg (cfg);
2150 ins->sreg2 = temp->dreg;
2151 ins->opcode = map_to_reg_reg_op (ins->opcode);
2157 if (ins->inst_imm == 1) {
2158 ins->opcode = OP_MOVE;
2161 if (ins->inst_imm == 0) {
2162 ins->opcode = OP_ICONST;
2166 imm = mono_is_power_of_two (ins->inst_imm);
2168 ins->opcode = OP_SHL_IMM;
2169 ins->inst_imm = imm;
2172 if (!ppc_is_imm16 (ins->inst_imm)) {
2173 NEW_INS (cfg, temp, OP_ICONST);
2174 temp->inst_c0 = ins->inst_imm;
2175 temp->dreg = mono_alloc_ireg (cfg);
2176 ins->sreg2 = temp->dreg;
2177 ins->opcode = map_to_reg_reg_op (ins->opcode);
2180 case OP_LOCALLOC_IMM:
2181 NEW_INS (cfg, temp, OP_ICONST);
2182 temp->inst_c0 = ins->inst_imm;
2183 temp->dreg = mono_alloc_ireg (cfg);
2184 ins->sreg1 = temp->dreg;
2185 ins->opcode = OP_LOCALLOC;
2187 case OP_LOAD_MEMBASE:
2188 case OP_LOADI4_MEMBASE:
2189 case OP_LOADU4_MEMBASE:
2190 case OP_LOADI2_MEMBASE:
2191 case OP_LOADU2_MEMBASE:
2192 case OP_LOADI1_MEMBASE:
2193 case OP_LOADU1_MEMBASE:
2194 case OP_LOADR4_MEMBASE:
2195 case OP_LOADR8_MEMBASE:
2196 case OP_STORE_MEMBASE_REG:
2197 case OP_STOREI4_MEMBASE_REG:
2198 case OP_STOREI2_MEMBASE_REG:
2199 case OP_STOREI1_MEMBASE_REG:
2200 case OP_STORER4_MEMBASE_REG:
2201 case OP_STORER8_MEMBASE_REG:
2202 /* we can do two things: load the immed in a register
2203 * and use an indexed load, or see if the immed can be
2204 * represented as an ad_imm + a load with a smaller offset
2205 * that fits. We just do the first for now, optimize later.
2207 if (ppc_is_imm16 (ins->inst_offset))
2209 NEW_INS (cfg, temp, OP_ICONST);
2210 temp->inst_c0 = ins->inst_offset;
2211 temp->dreg = mono_alloc_ireg (cfg);
2212 ins->sreg2 = temp->dreg;
2213 ins->opcode = map_to_reg_reg_op (ins->opcode);
2215 case OP_STORE_MEMBASE_IMM:
2216 case OP_STOREI1_MEMBASE_IMM:
2217 case OP_STOREI2_MEMBASE_IMM:
2218 case OP_STOREI4_MEMBASE_IMM:
2219 NEW_INS (cfg, temp, OP_ICONST);
2220 temp->inst_c0 = ins->inst_imm;
2221 temp->dreg = mono_alloc_ireg (cfg);
2222 ins->sreg1 = temp->dreg;
2223 ins->opcode = map_to_reg_reg_op (ins->opcode);
2225 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2228 NEW_INS (cfg, temp, OP_ICONST);
2229 temp->inst_c0 = (guint32)ins->inst_p0;
2230 temp->dreg = mono_alloc_ireg (cfg);
2231 ins->inst_basereg = temp->dreg;
2232 ins->inst_offset = 0;
2233 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2235 /* make it handle the possibly big ins->inst_offset
2236 * later optimize to use lis + load_membase
2242 bb->last_ins = last_ins;
2243 bb->max_vreg = cfg->next_vreg;
2247 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2249 int offset = cfg->arch.fp_conv_var_offset;
2250 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2251 ppc_fctiwz (code, ppc_f0, sreg);
2252 if (ppc_is_imm16 (offset + 4)) {
2253 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2254 ppc_lwz (code, dreg, offset + 4, cfg->frame_reg);
2256 ppc_load (code, dreg, offset);
2257 ppc_add (code, dreg, dreg, cfg->frame_reg);
2258 ppc_stfd (code, ppc_f0, 0, dreg);
2259 ppc_lwz (code, dreg, 4, dreg);
2263 ppc_andid (code, dreg, dreg, 0xff);
2265 ppc_andid (code, dreg, dreg, 0xffff);
2268 ppc_extsb (code, dreg, dreg);
2270 ppc_extsh (code, dreg, dreg);
2277 const guchar *target;
2282 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2285 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2286 PatchData *pdata = (PatchData*)user_data;
2287 guchar *code = data;
2288 guint32 *thunks = data;
2289 guint32 *endthunks = (guint32*)(code + bsize);
2293 int difflow, diffhigh;
2295 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2296 difflow = (char*)pdata->code - (char*)thunks;
2297 diffhigh = (char*)pdata->code - (char*)endthunks;
2298 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2301 templ = (guchar*)load;
2302 ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2303 ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2305 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2306 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2307 while (thunks < endthunks) {
2308 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2309 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2310 ppc_patch (pdata->code, (guchar*)thunks);
2311 mono_arch_flush_icache (pdata->code, 4);
2314 static int num_thunks = 0;
2316 if ((num_thunks % 20) == 0)
2317 g_print ("num_thunks lookup: %d\n", num_thunks);
2320 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2321 /* found a free slot instead: emit thunk */
2322 code = (guchar*)thunks;
2323 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2324 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2325 ppc_mtctr (code, ppc_r0);
2326 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2327 mono_arch_flush_icache ((guchar*)thunks, 16);
2329 ppc_patch (pdata->code, (guchar*)thunks);
2330 mono_arch_flush_icache (pdata->code, 4);
2333 static int num_thunks = 0;
2335 if ((num_thunks % 20) == 0)
2336 g_print ("num_thunks: %d\n", num_thunks);
2340 /* skip 16 bytes, the size of the thunk */
2344 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2350 handle_thunk (int absolute, guchar *code, const guchar *target) {
2351 MonoDomain *domain = mono_domain_get ();
2355 pdata.target = target;
2356 pdata.absolute = absolute;
2359 mono_domain_lock (domain);
2360 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2363 /* this uses the first available slot */
2365 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2367 mono_domain_unlock (domain);
2369 if (pdata.found != 1)
2370 g_print ("thunk failed for %p from %p\n", target, code);
2371 g_assert (pdata.found == 1);
2375 ppc_patch (guchar *code, const guchar *target)
2377 guint32 ins = *(guint32*)code;
2378 guint32 prim = ins >> 26;
2381 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2383 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2384 gint diff = target - code;
2386 if (diff <= 33554431){
2387 ins = (18 << 26) | (diff) | (ins & 1);
2388 *(guint32*)code = ins;
2392 /* diff between 0 and -33554432 */
2393 if (diff >= -33554432){
2394 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2395 *(guint32*)code = ins;
2400 if ((glong)target >= 0){
2401 if ((glong)target <= 33554431){
2402 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2403 *(guint32*)code = ins;
2407 if ((glong)target >= -33554432){
2408 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2409 *(guint32*)code = ins;
2414 handle_thunk (TRUE, code, target);
2417 g_assert_not_reached ();
2424 guint32 li = (guint32)target;
2425 ins = (ins & 0xffff0000) | (ins & 3);
2426 ovf = li & 0xffff0000;
2427 if (ovf != 0 && ovf != 0xffff0000)
2428 g_assert_not_reached ();
2431 // FIXME: assert the top bits of li are 0
2433 gint diff = target - code;
2434 ins = (ins & 0xffff0000) | (ins & 3);
2435 ovf = diff & 0xffff0000;
2436 if (ovf != 0 && ovf != 0xffff0000)
2437 g_assert_not_reached ();
2441 *(guint32*)code = ins;
2445 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2447 /* the trampoline code will try to patch the blrl, blr, bcctr */
2448 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2451 /* this is the lis/ori/mtlr/blrl sequence */
2452 seq = (guint32*)code;
2453 g_assert ((seq [0] >> 26) == 15);
2454 g_assert ((seq [1] >> 26) == 24);
2455 g_assert ((seq [2] >> 26) == 31);
2456 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2457 /* FIXME: make this thread safe */
2458 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2459 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2460 mono_arch_flush_icache (code - 8, 8);
2462 g_assert_not_reached ();
2464 // g_print ("patched with 0x%08x\n", ins);
2468 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2470 switch (ins->opcode) {
2473 case OP_FCALL_MEMBASE:
2474 if (ins->dreg != ppc_f1)
2475 ppc_fmr (code, ins->dreg, ppc_f1);
2483 * emit_load_volatile_arguments:
2485 * Load volatile arguments from the stack to the original input registers.
2486 * Required before a tail call.
2489 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2491 MonoMethod *method = cfg->method;
2492 MonoMethodSignature *sig;
2496 int struct_index = 0;
2498 /* FIXME: Generate intermediate code instead */
2500 sig = mono_method_signature (method);
2502 /* This is the opposite of the code in emit_prolog */
2506 cinfo = calculate_sizes (sig, sig->pinvoke);
2508 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2509 ArgInfo *ainfo = &cinfo->ret;
2510 inst = cfg->vret_addr;
2511 g_assert (ppc_is_imm16 (inst->inst_offset));
2512 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2514 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2515 ArgInfo *ainfo = cinfo->args + i;
2516 inst = cfg->args [pos];
2518 g_assert (inst->opcode != OP_REGVAR);
2519 g_assert (ppc_is_imm16 (inst->inst_offset));
2521 switch (ainfo->regtype) {
2522 case RegTypeGeneral:
2523 switch (ainfo->size) {
2525 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2528 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2531 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2537 switch (ainfo->size) {
2539 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2542 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2545 g_assert_not_reached ();
2550 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
2551 &inst->klass->byval_arg);
2553 if (!MONO_TYPE_IS_REFERENCE (type) && type->type != MONO_TYPE_I4)
2556 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2557 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
2561 case RegTypeStructByVal: {
2570 * Darwin pinvokes needs some special handling
2571 * for 1 and 2 byte arguments
2573 if (method->signature->pinvoke)
2574 size = mono_class_native_size (inst->klass, NULL);
2575 if (size == 1 || size == 2) {
2580 for (j = 0; j < ainfo->size; ++j) {
2581 ppc_lwz (code, ainfo->reg + j,
2582 inst->inst_offset + j * sizeof (gpointer), inst->inst_basereg);
2587 case RegTypeStructByAddr: {
2588 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2590 g_assert (ppc_is_imm16 (addr->inst_offset));
2591 g_assert (!ainfo->offset);
2592 ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2599 g_assert_not_reached ();
2610 /* This must be kept in sync with emit_load_volatile_arguments(). */
2612 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2614 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2615 MonoMethodSignature *sig;
2620 if (ins->opcode != OP_JMP)
2623 call = (MonoCallInst*)ins;
2624 sig = mono_method_signature (cfg->method);
2625 cinfo = calculate_sizes (sig, sig->pinvoke);
2627 if (MONO_TYPE_ISSTRUCT (sig->ret))
2629 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2630 ArgInfo *ainfo = cinfo->args + i;
2632 switch (ainfo->regtype) {
2633 case RegTypeGeneral:
2642 case RegTypeStructByVal:
2643 len += 4 * ainfo->size;
2646 case RegTypeStructByAddr:
2651 g_assert_not_reached ();
2661 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2663 int size = cfg->param_area;
2665 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2666 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2671 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2672 if (ppc_is_imm16 (-size)) {
2673 ppc_stwu (code, ppc_r0, -size, ppc_sp);
2675 ppc_load (code, ppc_r11, -size);
2676 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2683 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
2685 int size = cfg->param_area;
2687 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2688 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2693 ppc_lwz (code, ppc_r0, 0, ppc_sp);
2694 if (ppc_is_imm16 (size)) {
2695 ppc_stwu (code, ppc_r0, size, ppc_sp);
2697 ppc_load (code, ppc_r11, size);
2698 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2705 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2707 MonoInst *ins, *next;
2710 guint8 *code = cfg->native_code + cfg->code_len;
2711 MonoInst *last_ins = NULL;
2712 guint last_offset = 0;
2715 /* we don't align basic blocks of loops on ppc */
2717 if (cfg->verbose_level > 2)
2718 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2720 cpos = bb->max_offset;
2722 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2723 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2724 //g_assert (!mono_compile_aot);
2727 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2728 /* this is not thread save, but good enough */
2729 /* fixme: howto handle overflows? */
2730 //x86_inc_mem (code, &cov->data [bb->dfn].count);
2733 MONO_BB_FOR_EACH_INS (bb, ins) {
2734 offset = code - cfg->native_code;
2736 max_len = ins_native_length (cfg, ins);
2738 if (offset > (cfg->code_size - max_len - 16)) {
2739 cfg->code_size *= 2;
2740 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2741 code = cfg->native_code + offset;
2743 // if (ins->cil_code)
2744 // g_print ("cil code\n");
2745 mono_debug_record_line_number (cfg, ins, offset);
2747 switch (ins->opcode) {
2748 case OP_RELAXED_NOP:
2751 case OP_DUMMY_STORE:
2752 case OP_NOT_REACHED:
2756 emit_tls_access (code, ins->dreg, ins->inst_offset);
2759 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2760 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2761 ppc_mr (code, ppc_r4, ppc_r0);
2764 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2765 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2766 ppc_mr (code, ppc_r4, ppc_r0);
2768 case OP_MEMORY_BARRIER:
2771 case OP_STOREI1_MEMBASE_REG:
2772 if (ppc_is_imm16 (ins->inst_offset)) {
2773 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2775 ppc_load (code, ppc_r0, ins->inst_offset);
2776 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2779 case OP_STOREI2_MEMBASE_REG:
2780 if (ppc_is_imm16 (ins->inst_offset)) {
2781 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2783 ppc_load (code, ppc_r0, ins->inst_offset);
2784 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2787 case OP_STORE_MEMBASE_REG:
2788 case OP_STOREI4_MEMBASE_REG:
2789 if (ppc_is_imm16 (ins->inst_offset)) {
2790 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2792 ppc_load (code, ppc_r0, ins->inst_offset);
2793 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2796 case OP_STOREI1_MEMINDEX:
2797 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2799 case OP_STOREI2_MEMINDEX:
2800 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2802 case OP_STORE_MEMINDEX:
2803 case OP_STOREI4_MEMINDEX:
2804 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2807 g_assert_not_reached ();
2809 case OP_LOAD_MEMBASE:
2810 case OP_LOADI4_MEMBASE:
2811 case OP_LOADU4_MEMBASE:
2812 if (ppc_is_imm16 (ins->inst_offset)) {
2813 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2815 ppc_load (code, ppc_r0, ins->inst_offset);
2816 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2819 case OP_LOADI1_MEMBASE:
2820 case OP_LOADU1_MEMBASE:
2821 if (ppc_is_imm16 (ins->inst_offset)) {
2822 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2824 ppc_load (code, ppc_r0, ins->inst_offset);
2825 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2827 if (ins->opcode == OP_LOADI1_MEMBASE)
2828 ppc_extsb (code, ins->dreg, ins->dreg);
2830 case OP_LOADU2_MEMBASE:
2831 if (ppc_is_imm16 (ins->inst_offset)) {
2832 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2834 ppc_load (code, ppc_r0, ins->inst_offset);
2835 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2838 case OP_LOADI2_MEMBASE:
2839 if (ppc_is_imm16 (ins->inst_offset)) {
2840 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2842 ppc_load (code, ppc_r0, ins->inst_offset);
2843 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2846 case OP_LOAD_MEMINDEX:
2847 case OP_LOADI4_MEMINDEX:
2848 case OP_LOADU4_MEMINDEX:
2849 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2851 case OP_LOADU2_MEMINDEX:
2852 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2854 case OP_LOADI2_MEMINDEX:
2855 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2857 case OP_LOADU1_MEMINDEX:
2858 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2860 case OP_LOADI1_MEMINDEX:
2861 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2862 ppc_extsb (code, ins->dreg, ins->dreg);
2864 case OP_ICONV_TO_I1:
2865 ppc_extsb (code, ins->dreg, ins->sreg1);
2867 case OP_ICONV_TO_I2:
2868 ppc_extsh (code, ins->dreg, ins->sreg1);
2870 case OP_ICONV_TO_U1:
2871 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2873 case OP_ICONV_TO_U2:
2874 ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2879 if (next && compare_opcode_is_unsigned (next->opcode))
2880 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2882 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2884 case OP_COMPARE_IMM:
2885 case OP_ICOMPARE_IMM:
2887 if (next && compare_opcode_is_unsigned (next->opcode)) {
2888 if (ppc_is_uimm16 (ins->inst_imm)) {
2889 ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2891 g_assert_not_reached ();
2894 if (ppc_is_imm16 (ins->inst_imm)) {
2895 ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2897 g_assert_not_reached ();
2906 ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2909 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2913 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2916 if (ppc_is_imm16 (ins->inst_imm)) {
2917 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2919 g_assert_not_reached ();
2924 if (ppc_is_imm16 (ins->inst_imm)) {
2925 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2927 g_assert_not_reached ();
2931 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2933 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2934 ppc_mfspr (code, ppc_r0, ppc_xer);
2935 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2936 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2938 case OP_IADD_OVF_UN:
2939 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2941 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2942 ppc_mfspr (code, ppc_r0, ppc_xer);
2943 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2944 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2947 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2949 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2950 ppc_mfspr (code, ppc_r0, ppc_xer);
2951 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2952 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2954 case OP_ISUB_OVF_UN:
2955 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2957 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2958 ppc_mfspr (code, ppc_r0, ppc_xer);
2959 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2960 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2962 case OP_ADD_OVF_CARRY:
2963 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2965 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2966 ppc_mfspr (code, ppc_r0, ppc_xer);
2967 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2968 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2970 case OP_ADD_OVF_UN_CARRY:
2971 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2973 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2974 ppc_mfspr (code, ppc_r0, ppc_xer);
2975 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2976 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2978 case OP_SUB_OVF_CARRY:
2979 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2981 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2982 ppc_mfspr (code, ppc_r0, ppc_xer);
2983 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2984 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2986 case OP_SUB_OVF_UN_CARRY:
2987 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2989 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2990 ppc_mfspr (code, ppc_r0, ppc_xer);
2991 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2992 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2996 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2999 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3003 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3007 // we add the negated value
3008 if (ppc_is_imm16 (-ins->inst_imm))
3009 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3011 g_assert_not_reached ();
3015 g_assert (ppc_is_imm16 (ins->inst_imm));
3016 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3019 ppc_subfze (code, ins->dreg, ins->sreg1);
3022 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3023 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3027 if (!(ins->inst_imm & 0xffff0000)) {
3028 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3029 } else if (!(ins->inst_imm & 0xffff)) {
3030 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3032 g_assert_not_reached ();
3036 guint8 *divisor_is_m1;
3037 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3039 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3040 divisor_is_m1 = code;
3041 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3042 ppc_lis (code, ppc_r0, 0x8000);
3043 ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3044 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3045 ppc_patch (divisor_is_m1, code);
3046 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3048 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3049 ppc_mfspr (code, ppc_r0, ppc_xer);
3050 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3051 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3055 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3056 ppc_mfspr (code, ppc_r0, ppc_xer);
3057 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3058 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3064 g_assert_not_reached ();
3066 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3070 if (!(ins->inst_imm & 0xffff0000)) {
3071 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3072 } else if (!(ins->inst_imm & 0xffff)) {
3073 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3075 g_assert_not_reached ();
3079 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3083 if (!(ins->inst_imm & 0xffff0000)) {
3084 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3085 } else if (!(ins->inst_imm & 0xffff)) {
3086 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3088 g_assert_not_reached ();
3092 ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3096 ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3099 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3103 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3106 case OP_ISHR_UN_IMM:
3108 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3110 ppc_mr (code, ins->dreg, ins->sreg1);
3113 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3116 ppc_not (code, ins->dreg, ins->sreg1);
3119 ppc_neg (code, ins->dreg, ins->sreg1);
3122 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3126 if (ppc_is_imm16 (ins->inst_imm)) {
3127 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3129 g_assert_not_reached ();
3133 /* we annot use mcrxr, since it's not implemented on some processors
3134 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3136 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3137 ppc_mfspr (code, ppc_r0, ppc_xer);
3138 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3139 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3141 case OP_IMUL_OVF_UN:
3142 /* we first multiply to get the high word and compare to 0
3143 * to set the flags, then the result is discarded and then
3144 * we multiply to get the lower * bits result
3146 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3147 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3148 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3149 ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3152 ppc_load (code, ins->dreg, ins->inst_c0);
3155 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3156 ppc_lis (code, ins->dreg, 0);
3157 ppc_ori (code, ins->dreg, ins->dreg, 0);
3159 case OP_ICONV_TO_I4:
3160 case OP_ICONV_TO_U4:
3162 ppc_mr (code, ins->dreg, ins->sreg1);
3165 int saved = ins->sreg1;
3166 if (ins->sreg1 == ppc_r3) {
3167 ppc_mr (code, ppc_r0, ins->sreg1);
3170 if (ins->sreg2 != ppc_r3)
3171 ppc_mr (code, ppc_r3, ins->sreg2);
3172 if (saved != ppc_r4)
3173 ppc_mr (code, ppc_r4, saved);
3177 ppc_fmr (code, ins->dreg, ins->sreg1);
3179 case OP_FCONV_TO_R4:
3180 ppc_frsp (code, ins->dreg, ins->sreg1);
3186 * Keep in sync with mono_arch_emit_epilog
3188 g_assert (!cfg->method->save_lmf);
3190 * Note: we can use ppc_r11 here because it is dead anyway:
3191 * we're leaving the method.
3193 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3194 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3195 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3197 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3198 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3200 ppc_mtlr (code, ppc_r0);
3203 code = emit_load_volatile_arguments (cfg, code);
3205 if (ppc_is_imm16 (cfg->stack_usage)) {
3206 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3208 ppc_load (code, ppc_r11, cfg->stack_usage);
3209 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3211 if (!cfg->method->save_lmf) {
3212 /*for (i = 31; i >= 14; --i) {
3213 if (cfg->used_float_regs & (1 << i)) {
3214 pos += sizeof (double);
3215 ppc_lfd (code, i, -pos, cfg->frame_reg);
3218 /* FIXME: restore registers before changing ppc_sp */
3219 for (i = 31; i >= 13; --i) {
3220 if (cfg->used_int_regs & (1 << i)) {
3221 pos += sizeof (gulong);
3222 ppc_lwz (code, i, -pos, ppc_sp);
3226 /* FIXME restore from MonoLMF: though this can't happen yet */
3228 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3233 /* ensure ins->sreg1 is not NULL */
3234 ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3237 if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3238 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3240 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3241 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3243 ppc_stw (code, ppc_r0, 0, ins->sreg1);
3252 call = (MonoCallInst*)ins;
3253 if (ins->flags & MONO_INST_HAS_METHOD)
3254 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3256 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3257 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3258 ppc_lis (code, ppc_r0, 0);
3259 ppc_ori (code, ppc_r0, ppc_r0, 0);
3260 ppc_mtlr (code, ppc_r0);
3265 /* FIXME: this should be handled somewhere else in the new jit */
3266 code = emit_move_return_value (cfg, ins, code);
3272 case OP_VOIDCALL_REG:
3274 ppc_mtlr (code, ins->sreg1);
3276 /* FIXME: this should be handled somewhere else in the new jit */
3277 code = emit_move_return_value (cfg, ins, code);
3279 case OP_FCALL_MEMBASE:
3280 case OP_LCALL_MEMBASE:
3281 case OP_VCALL_MEMBASE:
3282 case OP_VCALL2_MEMBASE:
3283 case OP_VOIDCALL_MEMBASE:
3284 case OP_CALL_MEMBASE:
3285 ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3286 ppc_mtlr (code, ppc_r0);
3288 /* FIXME: this should be handled somewhere else in the new jit */
3289 code = emit_move_return_value (cfg, ins, code);
3292 guint8 * zero_loop_jump, * zero_loop_start;
3293 /* keep alignment */
3294 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3295 int area_offset = alloca_waste;
3297 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3298 ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3299 /* use ctr to store the number of words to 0 if needed */
3300 if (ins->flags & MONO_INST_INIT) {
3301 /* we zero 4 bytes at a time:
3302 * we add 7 instead of 3 so that we set the counter to
3303 * at least 1, otherwise the bdnz instruction will make
3304 * it negative and iterate billions of times.
3306 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3307 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3308 ppc_mtctr (code, ppc_r0);
3310 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3311 ppc_neg (code, ppc_r11, ppc_r11);
3312 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3314 if (ins->flags & MONO_INST_INIT) {
3315 /* adjust the dest reg by -4 so we can use stwu */
3316 /* we actually adjust -8 because we let the loop
3319 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3320 ppc_li (code, ppc_r11, 0);
3321 zero_loop_start = code;
3322 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3323 zero_loop_jump = code;
3324 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3325 ppc_patch (zero_loop_jump, zero_loop_start);
3327 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3332 ppc_mr (code, ppc_r3, ins->sreg1);
3333 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3334 (gpointer)"mono_arch_throw_exception");
3335 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3336 ppc_lis (code, ppc_r0, 0);
3337 ppc_ori (code, ppc_r0, ppc_r0, 0);
3338 ppc_mtlr (code, ppc_r0);
3347 ppc_mr (code, ppc_r3, ins->sreg1);
3348 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3349 (gpointer)"mono_arch_rethrow_exception");
3350 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3351 ppc_lis (code, ppc_r0, 0);
3352 ppc_ori (code, ppc_r0, ppc_r0, 0);
3353 ppc_mtlr (code, ppc_r0);
3360 case OP_START_HANDLER: {
3361 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3362 g_assert (spvar->inst_basereg != ppc_sp);
3363 code = emit_reserve_param_area (cfg, code);
3364 ppc_mflr (code, ppc_r0);
3365 if (ppc_is_imm16 (spvar->inst_offset)) {
3366 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3368 ppc_load (code, ppc_r11, spvar->inst_offset);
3369 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3373 case OP_ENDFILTER: {
3374 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3375 g_assert (spvar->inst_basereg != ppc_sp);
3376 code = emit_unreserve_param_area (cfg, code);
3377 if (ins->sreg1 != ppc_r3)
3378 ppc_mr (code, ppc_r3, ins->sreg1);
3379 if (ppc_is_imm16 (spvar->inst_offset)) {
3380 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3382 ppc_load (code, ppc_r11, spvar->inst_offset);
3383 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3385 ppc_mtlr (code, ppc_r0);
3389 case OP_ENDFINALLY: {
3390 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3391 g_assert (spvar->inst_basereg != ppc_sp);
3392 code = emit_unreserve_param_area (cfg, code);
3393 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3394 ppc_mtlr (code, ppc_r0);
3398 case OP_CALL_HANDLER:
3399 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3403 ins->inst_c0 = code - cfg->native_code;
3406 if (ins->flags & MONO_INST_BRLABEL) {
3407 /*if (ins->inst_i0->inst_c0) {
3409 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3411 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3415 /*if (ins->inst_target_bb->native_offset) {
3417 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3419 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3425 ppc_mtctr (code, ins->sreg1);
3426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3430 ppc_li (code, ins->dreg, 0);
3431 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3432 ppc_li (code, ins->dreg, 1);
3438 ppc_li (code, ins->dreg, 1);
3439 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3440 ppc_li (code, ins->dreg, 0);
3446 ppc_li (code, ins->dreg, 1);
3447 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3448 ppc_li (code, ins->dreg, 0);
3450 case OP_COND_EXC_EQ:
3451 case OP_COND_EXC_NE_UN:
3452 case OP_COND_EXC_LT:
3453 case OP_COND_EXC_LT_UN:
3454 case OP_COND_EXC_GT:
3455 case OP_COND_EXC_GT_UN:
3456 case OP_COND_EXC_GE:
3457 case OP_COND_EXC_GE_UN:
3458 case OP_COND_EXC_LE:
3459 case OP_COND_EXC_LE_UN:
3460 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3462 case OP_COND_EXC_IEQ:
3463 case OP_COND_EXC_INE_UN:
3464 case OP_COND_EXC_ILT:
3465 case OP_COND_EXC_ILT_UN:
3466 case OP_COND_EXC_IGT:
3467 case OP_COND_EXC_IGT_UN:
3468 case OP_COND_EXC_IGE:
3469 case OP_COND_EXC_IGE_UN:
3470 case OP_COND_EXC_ILE:
3471 case OP_COND_EXC_ILE_UN:
3472 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3475 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3477 /*ppc_mfspr (code, ppc_r0, ppc_xer);
3478 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3479 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3481 case OP_COND_EXC_OV:
3482 /*ppc_mcrxr (code, 0);
3483 EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3485 case OP_COND_EXC_NC:
3486 case OP_COND_EXC_NO:
3487 g_assert_not_reached ();
3499 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3502 /* floating point opcodes */
3505 g_assert_not_reached ();
3506 case OP_STORER8_MEMBASE_REG:
3507 if (ppc_is_imm16 (ins->inst_offset)) {
3508 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3510 ppc_load (code, ppc_r0, ins->inst_offset);
3511 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3514 case OP_LOADR8_MEMBASE:
3515 if (ppc_is_imm16 (ins->inst_offset)) {
3516 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3518 ppc_load (code, ppc_r0, ins->inst_offset);
3519 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3522 case OP_STORER4_MEMBASE_REG:
3523 ppc_frsp (code, ins->sreg1, ins->sreg1);
3524 if (ppc_is_imm16 (ins->inst_offset)) {
3525 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3527 ppc_load (code, ppc_r0, ins->inst_offset);
3528 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3531 case OP_LOADR4_MEMBASE:
3532 if (ppc_is_imm16 (ins->inst_offset)) {
3533 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3535 ppc_load (code, ppc_r0, ins->inst_offset);
3536 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3539 case OP_LOADR4_MEMINDEX:
3540 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3542 case OP_LOADR8_MEMINDEX:
3543 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3545 case OP_STORER4_MEMINDEX:
3546 ppc_frsp (code, ins->sreg1, ins->sreg1);
3547 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3549 case OP_STORER8_MEMINDEX:
3550 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3553 case CEE_CONV_R4: /* FIXME: change precision */
3555 g_assert_not_reached ();
3556 case OP_FCONV_TO_I1:
3557 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3559 case OP_FCONV_TO_U1:
3560 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3562 case OP_FCONV_TO_I2:
3563 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3565 case OP_FCONV_TO_U2:
3566 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3568 case OP_FCONV_TO_I4:
3570 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3572 case OP_FCONV_TO_U4:
3574 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3576 case OP_FCONV_TO_I8:
3577 case OP_FCONV_TO_U8:
3578 g_assert_not_reached ();
3579 /* Implemented as helper calls */
3581 case OP_LCONV_TO_R_UN:
3582 g_assert_not_reached ();
3583 /* Implemented as helper calls */
3585 case OP_LCONV_TO_OVF_I4_2:
3586 case OP_LCONV_TO_OVF_I: {
3587 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3588 // Check if its negative
3589 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3590 negative_branch = code;
3591 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3592 // Its positive msword == 0
3593 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3594 msword_positive_branch = code;
3595 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3597 ovf_ex_target = code;
3598 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3600 ppc_patch (negative_branch, code);
3601 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3602 msword_negative_branch = code;
3603 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3604 ppc_patch (msword_negative_branch, ovf_ex_target);
3606 ppc_patch (msword_positive_branch, code);
3607 if (ins->dreg != ins->sreg1)
3608 ppc_mr (code, ins->dreg, ins->sreg1);
3612 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3615 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3618 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3621 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 ppc_fneg (code, ins->dreg, ins->sreg1);
3631 g_assert_not_reached ();
3634 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3637 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3638 ppc_li (code, ins->dreg, 0);
3639 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3640 ppc_li (code, ins->dreg, 1);
3643 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3644 ppc_li (code, ins->dreg, 1);
3645 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3646 ppc_li (code, ins->dreg, 0);
3649 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3650 ppc_li (code, ins->dreg, 1);
3651 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3652 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3653 ppc_li (code, ins->dreg, 0);
3656 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3657 ppc_li (code, ins->dreg, 1);
3658 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3659 ppc_li (code, ins->dreg, 0);
3662 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3663 ppc_li (code, ins->dreg, 1);
3664 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3665 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3666 ppc_li (code, ins->dreg, 0);
3669 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3672 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3675 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3676 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3679 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3680 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3683 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3684 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3687 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3688 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3691 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3692 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3695 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3698 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3699 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3702 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3705 g_assert_not_reached ();
3706 case OP_CHECK_FINITE: {
3707 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3708 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3709 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3710 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3713 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3714 ppc_load (code, ins->dreg, 0x0f0f0f0f);
3718 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3719 g_assert_not_reached ();
3722 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3723 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3724 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3725 g_assert_not_reached ();
3731 last_offset = offset;
3734 cfg->code_len = code - cfg->native_code;
3738 mono_arch_register_lowlevel_calls (void)
3742 #define patch_lis_ori(ip,val) do {\
3743 guint16 *__lis_ori = (guint16*)(ip); \
3744 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff; \
3745 __lis_ori [3] = ((guint32)(val)) & 0xffff; \
3749 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3751 MonoJumpInfo *patch_info;
3753 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3754 unsigned char *ip = patch_info->ip.i + code;
3755 unsigned char *target;
3757 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3759 switch (patch_info->type) {
3760 case MONO_PATCH_INFO_IP:
3761 patch_lis_ori (ip, ip);
3763 case MONO_PATCH_INFO_METHOD_REL:
3764 g_assert_not_reached ();
3765 *((gpointer *)(ip)) = code + patch_info->data.offset;
3767 case MONO_PATCH_INFO_SWITCH: {
3768 gpointer *table = (gpointer *)patch_info->data.table->table;
3771 patch_lis_ori (ip, table);
3773 for (i = 0; i < patch_info->data.table->table_size; i++) {
3774 table [i] = (int)patch_info->data.table->table [i] + code;
3776 /* we put into the table the absolute address, no need for ppc_patch in this case */
3779 case MONO_PATCH_INFO_METHODCONST:
3780 case MONO_PATCH_INFO_CLASS:
3781 case MONO_PATCH_INFO_IMAGE:
3782 case MONO_PATCH_INFO_FIELD:
3783 case MONO_PATCH_INFO_VTABLE:
3784 case MONO_PATCH_INFO_IID:
3785 case MONO_PATCH_INFO_SFLDA:
3786 case MONO_PATCH_INFO_LDSTR:
3787 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3788 case MONO_PATCH_INFO_LDTOKEN:
3789 /* from OP_AOTCONST : lis + ori */
3790 patch_lis_ori (ip, target);
3792 case MONO_PATCH_INFO_R4:
3793 case MONO_PATCH_INFO_R8:
3794 g_assert_not_reached ();
3795 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3797 case MONO_PATCH_INFO_EXC_NAME:
3798 g_assert_not_reached ();
3799 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3801 case MONO_PATCH_INFO_NONE:
3802 case MONO_PATCH_INFO_BB_OVF:
3803 case MONO_PATCH_INFO_EXC_OVF:
3804 /* everything is dealt with at epilog output time */
3809 ppc_patch (ip, target);
3814 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
3815 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
3816 * the instruction offset immediate for all the registers.
3819 save_registers (guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs)
3823 for (i = 13; i <= 31; i++) {
3824 if (used_int_regs & (1 << i)) {
3825 ppc_stw (code, i, pos, base_reg);
3826 pos += sizeof (gulong);
3830 /* pos is the start of the MonoLMF structure */
3831 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
3832 for (i = 13; i <= 31; i++) {
3833 ppc_stw (code, i, offset, base_reg);
3834 offset += sizeof (gulong);
3836 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
3837 for (i = 14; i < 32; i++) {
3838 ppc_stfd (code, i, offset, base_reg);
3839 offset += sizeof (gdouble);
3846 * Stack frame layout:
3848 * ------------------- sp
3849 * MonoLMF structure or saved registers
3850 * -------------------
3852 * -------------------
3854 * -------------------
3855 * optional 8 bytes for tracing
3856 * -------------------
3857 * param area size is cfg->param_area
3858 * -------------------
3859 * linkage area size is PPC_STACK_PARAM_OFFSET
3860 * ------------------- sp
3864 mono_arch_emit_prolog (MonoCompile *cfg)
3866 MonoMethod *method = cfg->method;
3868 MonoMethodSignature *sig;
3870 int alloc_size, pos, max_offset, i;
3875 int tailcall_struct_index;
3877 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3880 sig = mono_method_signature (method);
3881 cfg->code_size = 256 + sig->param_count * 20;
3882 code = cfg->native_code = g_malloc (cfg->code_size);
3884 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3885 ppc_mflr (code, ppc_r0);
3886 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3889 alloc_size = cfg->stack_offset;
3892 if (!method->save_lmf) {
3893 for (i = 31; i >= 13; --i) {
3894 if (cfg->used_int_regs & (1 << i)) {
3895 pos += sizeof (gulong);
3899 pos += sizeof (MonoLMF);
3903 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
3904 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
3905 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3906 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
3909 cfg->stack_usage = alloc_size;
3910 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
3912 if (ppc_is_imm16 (-alloc_size)) {
3913 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3914 code = save_registers (code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs);
3917 ppc_addi (code, ppc_r11, ppc_sp, -pos);
3918 ppc_load (code, ppc_r0, -alloc_size);
3919 ppc_stwux (code, ppc_sp, ppc_sp, ppc_r0);
3920 code = save_registers (code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs);
3923 if (cfg->frame_reg != ppc_sp)
3924 ppc_mr (code, cfg->frame_reg, ppc_sp);
3926 /* store runtime generic context */
3927 if (cfg->rgctx_var) {
3928 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3929 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3931 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3934 /* compute max_offset in order to use short forward jumps
3935 * we always do it on ppc because the immediate displacement
3936 * for jumps is too small
3939 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3941 bb->max_offset = max_offset;
3943 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3946 MONO_BB_FOR_EACH_INS (bb, ins)
3947 max_offset += ins_native_length (cfg, ins);
3950 /* load arguments allocated to register from the stack */
3953 cinfo = calculate_sizes (sig, sig->pinvoke);
3955 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3956 ArgInfo *ainfo = &cinfo->ret;
3958 inst = cfg->vret_addr;
3961 if (ppc_is_imm16 (inst->inst_offset)) {
3962 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3964 ppc_load (code, ppc_r11, inst->inst_offset);
3965 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3969 tailcall_struct_index = 0;
3970 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3971 ArgInfo *ainfo = cinfo->args + i;
3972 inst = cfg->args [pos];
3974 if (cfg->verbose_level > 2)
3975 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3976 if (inst->opcode == OP_REGVAR) {
3977 if (ainfo->regtype == RegTypeGeneral)
3978 ppc_mr (code, inst->dreg, ainfo->reg);
3979 else if (ainfo->regtype == RegTypeFP)
3980 ppc_fmr (code, inst->dreg, ainfo->reg);
3981 else if (ainfo->regtype == RegTypeBase) {
3982 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3983 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3985 g_assert_not_reached ();
3987 if (cfg->verbose_level > 2)
3988 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3990 /* the argument should be put on the stack: FIXME handle size != word */
3991 if (ainfo->regtype == RegTypeGeneral) {
3992 switch (ainfo->size) {
3994 if (ppc_is_imm16 (inst->inst_offset)) {
3995 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3997 ppc_load (code, ppc_r11, inst->inst_offset);
3998 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4002 if (ppc_is_imm16 (inst->inst_offset)) {
4003 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4005 ppc_load (code, ppc_r11, inst->inst_offset);
4006 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4010 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4011 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4012 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4014 ppc_load (code, ppc_r11, inst->inst_offset);
4015 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4016 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4017 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4021 if (ppc_is_imm16 (inst->inst_offset)) {
4022 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4024 ppc_load (code, ppc_r11, inst->inst_offset);
4025 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4029 } else if (ainfo->regtype == RegTypeBase) {
4030 /* load the previous stack pointer in r11 */
4031 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4032 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4033 switch (ainfo->size) {
4035 if (ppc_is_imm16 (inst->inst_offset)) {
4036 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4038 ppc_load (code, ppc_r11, inst->inst_offset);
4039 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4043 if (ppc_is_imm16 (inst->inst_offset)) {
4044 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4046 ppc_load (code, ppc_r11, inst->inst_offset);
4047 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4051 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4052 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4053 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4054 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4057 g_assert_not_reached ();
4061 if (ppc_is_imm16 (inst->inst_offset)) {
4062 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4064 ppc_load (code, ppc_r11, inst->inst_offset);
4065 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4069 } else if (ainfo->regtype == RegTypeFP) {
4070 g_assert (ppc_is_imm16 (inst->inst_offset));
4071 if (ainfo->size == 8)
4072 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4073 else if (ainfo->size == 4)
4074 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4076 g_assert_not_reached ();
4077 } else if (ainfo->regtype == RegTypeStructByVal) {
4078 int doffset = inst->inst_offset;
4082 g_assert (ppc_is_imm16 (inst->inst_offset));
4083 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4084 /* FIXME: what if there is no class? */
4085 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4086 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4087 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4090 * Darwin handles 1 and 2 byte
4091 * structs specially by
4092 * loading h/b into the arg
4093 * register. Only done for
4097 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4099 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4102 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4103 soffset += sizeof (gpointer);
4104 doffset += sizeof (gpointer);
4106 if (ainfo->vtsize) {
4107 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4108 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4109 if ((size & 3) != 0) {
4110 code = emit_memcpy (code, size - soffset,
4111 inst->inst_basereg, doffset,
4112 ppc_r11, ainfo->offset + soffset);
4114 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4115 inst->inst_basereg, doffset,
4116 ppc_r11, ainfo->offset + soffset);
4119 } else if (ainfo->regtype == RegTypeStructByAddr) {
4120 /* if it was originally a RegTypeBase */
4121 if (ainfo->offset) {
4122 /* load the previous stack pointer in r11 */
4123 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4124 ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4126 ppc_mr (code, ppc_r11, ainfo->reg);
4129 if (cfg->tailcall_valuetype_addrs) {
4130 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4132 g_assert (ppc_is_imm16 (addr->inst_offset));
4133 ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4135 tailcall_struct_index++;
4138 g_assert (ppc_is_imm16 (inst->inst_offset));
4139 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4140 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4142 g_assert_not_reached ();
4147 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4148 ppc_load (code, ppc_r3, cfg->domain);
4149 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4150 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4151 ppc_lis (code, ppc_r0, 0);
4152 ppc_ori (code, ppc_r0, ppc_r0, 0);
4153 ppc_mtlr (code, ppc_r0);
4160 if (method->save_lmf) {
4161 if (lmf_pthread_key != -1) {
4162 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4163 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4164 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4166 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4167 (gpointer)"mono_get_lmf_addr");
4168 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4169 ppc_lis (code, ppc_r0, 0);
4170 ppc_ori (code, ppc_r0, ppc_r0, 0);
4171 ppc_mtlr (code, ppc_r0);
4177 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4178 /* lmf_offset is the offset from the previous stack pointer,
4179 * alloc_size is the total stack space allocated, so the offset
4180 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4181 * The pointer to the struct is put in ppc_r11 (new_lmf).
4182 * The callee-saved registers are already in the MonoLMF structure
4184 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4185 /* ppc_r3 is the result from mono_get_lmf_addr () */
4186 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4187 /* new_lmf->previous_lmf = *lmf_addr */
4188 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4189 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4190 /* *(lmf_addr) = r11 */
4191 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4192 /* save method info */
4193 ppc_load (code, ppc_r0, method);
4194 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4195 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4196 /* save the current IP */
4197 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4198 ppc_load (code, ppc_r0, 0x01010101);
4199 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4203 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4205 cfg->code_len = code - cfg->native_code;
4206 g_assert (cfg->code_len < cfg->code_size);
4213 mono_arch_emit_epilog (MonoCompile *cfg)
4215 MonoMethod *method = cfg->method;
4217 int max_epilog_size = 16 + 20*4;
4220 if (cfg->method->save_lmf)
4221 max_epilog_size += 128;
4223 if (mono_jit_trace_calls != NULL)
4224 max_epilog_size += 50;
4226 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4227 max_epilog_size += 50;
4229 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4230 cfg->code_size *= 2;
4231 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4232 mono_jit_stats.code_reallocs++;
4236 * Keep in sync with OP_JMP
4238 code = cfg->native_code + cfg->code_len;
4240 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4241 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4245 if (method->save_lmf) {
4247 pos += sizeof (MonoLMF);
4249 /* save the frame reg in r8 */
4250 ppc_mr (code, ppc_r8, cfg->frame_reg);
4251 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4252 /* r5 = previous_lmf */
4253 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4255 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4256 /* *(lmf_addr) = previous_lmf */
4257 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4258 /* FIXME: speedup: there is no actual need to restore the registers if
4259 * we didn't actually change them (idea from Zoltan).
4262 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4264 /*for (i = 14; i < 32; i++) {
4265 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4267 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4268 /* use the saved copy of the frame reg in r8 */
4269 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4270 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4271 ppc_mtlr (code, ppc_r0);
4273 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4275 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4276 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4277 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4279 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4280 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4282 ppc_mtlr (code, ppc_r0);
4284 if (ppc_is_imm16 (cfg->stack_usage)) {
4285 int offset = cfg->stack_usage;
4286 for (i = 13; i <= 31; i++) {
4287 if (cfg->used_int_regs & (1 << i))
4288 offset -= sizeof (gulong);
4290 if (cfg->frame_reg != ppc_sp)
4291 ppc_mr (code, ppc_r11, cfg->frame_reg);
4292 /* note r31 (possibly the frame register) is restored last */
4293 for (i = 13; i <= 31; i++) {
4294 if (cfg->used_int_regs & (1 << i)) {
4295 ppc_lwz (code, i, offset, cfg->frame_reg);
4296 offset += sizeof (gulong);
4299 if (cfg->frame_reg != ppc_sp)
4300 ppc_addic (code, ppc_sp, ppc_r11, cfg->stack_usage);
4302 ppc_addic (code, ppc_sp, ppc_sp, cfg->stack_usage);
4304 ppc_load (code, ppc_r11, cfg->stack_usage);
4305 if (cfg->used_int_regs) {
4306 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
4307 for (i = 31; i >= 13; --i) {
4308 if (cfg->used_int_regs & (1 << i)) {
4309 pos += sizeof (gulong);
4310 ppc_lwz (code, i, -pos, ppc_r11);
4313 ppc_mr (code, ppc_sp, ppc_r11);
4315 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4322 cfg->code_len = code - cfg->native_code;
4324 g_assert (cfg->code_len < cfg->code_size);
4328 /* remove once throw_exception_by_name is eliminated */
4330 exception_id_by_name (const char *name)
4332 if (strcmp (name, "IndexOutOfRangeException") == 0)
4333 return MONO_EXC_INDEX_OUT_OF_RANGE;
4334 if (strcmp (name, "OverflowException") == 0)
4335 return MONO_EXC_OVERFLOW;
4336 if (strcmp (name, "ArithmeticException") == 0)
4337 return MONO_EXC_ARITHMETIC;
4338 if (strcmp (name, "DivideByZeroException") == 0)
4339 return MONO_EXC_DIVIDE_BY_ZERO;
4340 if (strcmp (name, "InvalidCastException") == 0)
4341 return MONO_EXC_INVALID_CAST;
4342 if (strcmp (name, "NullReferenceException") == 0)
4343 return MONO_EXC_NULL_REF;
4344 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4345 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4346 g_error ("Unknown intrinsic exception %s\n", name);
4351 mono_arch_emit_exceptions (MonoCompile *cfg)
4353 MonoJumpInfo *patch_info;
4356 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4357 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4358 int max_epilog_size = 50;
4360 /* count the number of exception infos */
4363 * make sure we have enough space for exceptions
4364 * 24 is the simulated call to throw_exception_by_name
4366 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4367 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4368 i = exception_id_by_name (patch_info->data.target);
4369 if (!exc_throw_found [i]) {
4370 max_epilog_size += 24;
4371 exc_throw_found [i] = TRUE;
4373 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4374 max_epilog_size += 12;
4375 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4376 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4377 i = exception_id_by_name (ovfj->data.exception);
4378 if (!exc_throw_found [i]) {
4379 max_epilog_size += 24;
4380 exc_throw_found [i] = TRUE;
4382 max_epilog_size += 8;
4386 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4387 cfg->code_size *= 2;
4388 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4389 mono_jit_stats.code_reallocs++;
4392 code = cfg->native_code + cfg->code_len;
4394 /* add code to raise exceptions */
4395 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4396 switch (patch_info->type) {
4397 case MONO_PATCH_INFO_BB_OVF: {
4398 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4399 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4400 /* patch the initial jump */
4401 ppc_patch (ip, code);
4402 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4404 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4405 /* jump back to the true target */
4407 ip = ovfj->data.bb->native_offset + cfg->native_code;
4408 ppc_patch (code - 4, ip);
4411 case MONO_PATCH_INFO_EXC_OVF: {
4412 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4413 MonoJumpInfo *newji;
4414 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4415 unsigned char *bcl = code;
4416 /* patch the initial jump: we arrived here with a call */
4417 ppc_patch (ip, code);
4418 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4420 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4421 /* patch the conditional jump to the right handler */
4422 /* make it processed next */
4423 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4424 newji->type = MONO_PATCH_INFO_EXC;
4425 newji->ip.i = bcl - cfg->native_code;
4426 newji->data.target = ovfj->data.exception;
4427 newji->next = patch_info->next;
4428 patch_info->next = newji;
4431 case MONO_PATCH_INFO_EXC: {
4432 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4433 i = exception_id_by_name (patch_info->data.target);
4434 if (exc_throw_pos [i]) {
4435 ppc_patch (ip, exc_throw_pos [i]);
4436 patch_info->type = MONO_PATCH_INFO_NONE;
4439 exc_throw_pos [i] = code;
4441 ppc_patch (ip, code);
4442 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4443 ppc_load (code, ppc_r3, patch_info->data.target);
4444 /* we got here from a conditional call, so the calling ip is set in lr already */
4445 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4446 patch_info->data.name = "mono_arch_throw_exception_by_name";
4447 patch_info->ip.i = code - cfg->native_code;
4448 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4449 ppc_lis (code, ppc_r0, 0);
4450 ppc_ori (code, ppc_r0, ppc_r0, 0);
4451 ppc_mtctr (code, ppc_r0);
4452 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4464 cfg->code_len = code - cfg->native_code;
4466 g_assert (cfg->code_len < cfg->code_size);
4471 try_offset_access (void *value, guint32 idx)
4473 register void* me __asm__ ("r2");
4474 void ***p = (void***)((char*)me + 284);
4475 int idx1 = idx / 32;
4476 int idx2 = idx % 32;
4479 if (value != p[idx1][idx2])
4485 setup_tls_access (void)
4488 guint32 *ins, *code;
4489 guint32 cmplwi_1023, li_0x48, blr_ins;
4490 if (tls_mode == TLS_MODE_FAILED)
4493 if (g_getenv ("MONO_NO_TLS")) {
4494 tls_mode = TLS_MODE_FAILED;
4498 if (tls_mode == TLS_MODE_DETECT) {
4499 ins = (guint32*)pthread_getspecific;
4500 /* uncond branch to the real method */
4501 if ((*ins >> 26) == 18) {
4503 val = (*ins & ~3) << 6;
4507 ins = (guint32*)val;
4509 ins = (guint32*) ((char*)ins + val);
4512 code = &cmplwi_1023;
4513 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4515 ppc_li (code, ppc_r4, 0x48);
4518 if (*ins == cmplwi_1023) {
4519 int found_lwz_284 = 0;
4520 for (ptk = 0; ptk < 20; ++ptk) {
4522 if (!*ins || *ins == blr_ins)
4524 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4529 if (!found_lwz_284) {
4530 tls_mode = TLS_MODE_FAILED;
4533 tls_mode = TLS_MODE_LTHREADS;
4534 } else if (*ins == li_0x48) {
4536 /* uncond branch to the real method */
4537 if ((*ins >> 26) == 18) {
4539 val = (*ins & ~3) << 6;
4543 ins = (guint32*)val;
4545 ins = (guint32*) ((char*)ins + val);
4547 code = (guint32*)&val;
4548 ppc_li (code, ppc_r0, 0x7FF2);
4549 if (ins [1] == val) {
4550 /* Darwin on G4, implement */
4551 tls_mode = TLS_MODE_FAILED;
4554 code = (guint32*)&val;
4555 ppc_mfspr (code, ppc_r3, 104);
4556 if (ins [1] != val) {
4557 tls_mode = TLS_MODE_FAILED;
4560 tls_mode = TLS_MODE_DARWIN_G5;
4563 tls_mode = TLS_MODE_FAILED;
4567 tls_mode = TLS_MODE_FAILED;
4571 if (monodomain_key == -1) {
4572 ptk = mono_domain_get_tls_key ();
4574 ptk = mono_pthread_key_for_tls (ptk);
4576 monodomain_key = ptk;
4580 if (lmf_pthread_key == -1) {
4581 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4583 /*g_print ("MonoLMF at: %d\n", ptk);*/
4584 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4585 init_tls_failed = 1;
4588 lmf_pthread_key = ptk;
4591 if (monothread_key == -1) {
4592 ptk = mono_thread_get_tls_key ();
4594 ptk = mono_pthread_key_for_tls (ptk);
4596 monothread_key = ptk;
4597 /*g_print ("thread inited: %d\n", ptk);*/
4600 /*g_print ("thread not inited yet %d\n", ptk);*/
4606 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4608 setup_tls_access ();
4612 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4616 #ifdef MONO_ARCH_HAVE_IMT
4620 #define JUMP_IMM_SIZE 12
4621 #define JUMP_IMM32_SIZE 16
4622 #define ENABLE_WRONG_METHOD_CHECK 0
4625 * LOCKING: called with the domain lock held
4628 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4629 gpointer fail_tramp)
4633 guint8 *code, *start;
4635 for (i = 0; i < count; ++i) {
4636 MonoIMTCheckItem *item = imt_entries [i];
4637 if (item->is_equals) {
4638 if (item->check_target_idx) {
4639 if (!item->compare_done)
4640 item->chunk_size += CMP_SIZE;
4642 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4644 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4647 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4649 item->chunk_size += JUMP_IMM_SIZE;
4650 #if ENABLE_WRONG_METHOD_CHECK
4651 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4656 item->chunk_size += CMP_SIZE + BR_SIZE;
4657 imt_entries [item->check_target_idx]->compare_done = TRUE;
4659 size += item->chunk_size;
4662 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4664 /* the initial load of the vtable address */
4666 code = mono_code_manager_reserve (domain->code_mp, size);
4670 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4671 for (i = 0; i < count; ++i) {
4672 MonoIMTCheckItem *item = imt_entries [i];
4673 item->code_target = code;
4674 if (item->is_equals) {
4675 if (item->check_target_idx) {
4676 if (!item->compare_done) {
4677 ppc_load (code, ppc_r0, (guint32)item->key);
4678 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4680 item->jmp_code = code;
4681 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4683 ppc_load (code, ppc_r0, item->value.target_code);
4685 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4686 ppc_mtctr (code, ppc_r0);
4687 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4690 ppc_load (code, ppc_r0, (guint32)item->key);
4691 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4692 item->jmp_code = code;
4693 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4694 ppc_load (code, ppc_r0, item->value.target_code);
4695 ppc_mtctr (code, ppc_r0);
4696 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4697 ppc_patch (item->jmp_code, code);
4698 ppc_load (code, ppc_r0, fail_tramp);
4699 ppc_mtctr (code, ppc_r0);
4700 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4701 item->jmp_code = NULL;
4703 /* enable the commented code to assert on wrong method */
4704 #if ENABLE_WRONG_METHOD_CHECK
4705 ppc_load (code, ppc_r0, (guint32)item->key);
4706 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4707 item->jmp_code = code;
4708 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4710 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4711 ppc_mtctr (code, ppc_r0);
4712 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4713 #if ENABLE_WRONG_METHOD_CHECK
4714 ppc_patch (item->jmp_code, code);
4716 item->jmp_code = NULL;
4721 ppc_load (code, ppc_r0, (guint32)item->key);
4722 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4723 item->jmp_code = code;
4724 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4727 /* patch the branches to get to the target items */
4728 for (i = 0; i < count; ++i) {
4729 MonoIMTCheckItem *item = imt_entries [i];
4730 if (item->jmp_code) {
4731 if (item->check_target_idx) {
4732 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4738 mono_stats.imt_thunks_size += code - start;
4739 g_assert (code - start <= size);
4740 mono_arch_flush_icache (start, size);
4745 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4747 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4751 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4753 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4758 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4760 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4764 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4771 mono_arch_print_tree (MonoInst *tree, int arity)
4776 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4780 setup_tls_access ();
4781 if (monodomain_key == -1)
4784 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4785 ins->inst_offset = monodomain_key;
4790 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4794 setup_tls_access ();
4795 if (monothread_key == -1)
4798 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4799 ins->inst_offset = monothread_key;
4804 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4806 g_assert (reg >= ppc_r13);
4808 return (gpointer)ctx->regs [reg - ppc_r13];