2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
20 #include "cpu-ppc64.h"
27 #include <sys/sysctl.h>
30 #define FORCE_INDIR_CALL 1
41 /* This mutex protects architecture specific caches */
42 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
43 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
44 static CRITICAL_SECTION mini_arch_mutex;
46 int mono_exc_esp_offset = 0;
47 static int tls_mode = TLS_MODE_DETECT;
48 static int lmf_pthread_key = -1;
49 static int monothread_key = -1;
50 static int monodomain_key = -1;
53 offsets_from_pthread_key (guint32 key, int *offset2)
57 *offset2 = idx2 * sizeof (gpointer);
58 return 284 + idx1 * sizeof (gpointer);
61 #define emit_linuxthreads_tls(code,dreg,key) do {\
63 off1 = offsets_from_pthread_key ((key), &off2); \
64 ppc_load_reg ((code), (dreg), off1, ppc_r2); \
65 ppc_load_reg ((code), (dreg), off2, (dreg)); \
68 #define emit_darwing5_tls(code,dreg,key) do {\
69 int off1 = 0x48 + key * sizeof (gpointer); \
70 ppc_mfspr ((code), (dreg), 104); \
71 ppc_load_reg ((code), (dreg), off1, (dreg)); \
74 /* FIXME: ensure the sc call preserves all but r3 */
75 #define emit_darwing4_tls(code,dreg,key) do {\
76 int off1 = 0x48 + key * sizeof (gpointer); \
77 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
78 ppc_li ((code), ppc_r0, 0x7FF2); \
80 ppc_lwz ((code), (dreg), off1, ppc_r3); \
81 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
84 #define emit_tls_access(code,dreg,key) do { \
86 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
87 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
88 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
89 default: g_assert_not_reached (); \
93 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
95 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
96 inst->type = STACK_R8; \
98 inst->inst_p0 = (void*)(addr); \
99 mono_bblock_add_inst (cfg->cbb, inst); \
103 mono_arch_regname (int reg) {
104 static const char rnames[][4] = {
105 "r0", "sp", "r2", "r3", "r4",
106 "r5", "r6", "r7", "r8", "r9",
107 "r10", "r11", "r12", "r13", "r14",
108 "r15", "r16", "r17", "r18", "r19",
109 "r20", "r21", "r22", "r23", "r24",
110 "r25", "r26", "r27", "r28", "r29",
113 if (reg >= 0 && reg < 32)
119 mono_arch_fregname (int reg) {
120 static const char rnames[][4] = {
121 "f0", "f1", "f2", "f3", "f4",
122 "f5", "f6", "f7", "f8", "f9",
123 "f10", "f11", "f12", "f13", "f14",
124 "f15", "f16", "f17", "f18", "f19",
125 "f20", "f21", "f22", "f23", "f24",
126 "f25", "f26", "f27", "f28", "f29",
129 if (reg >= 0 && reg < 32)
134 /* this function overwrites r0, r11, r12 */
136 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
138 /* unrolled, use the counter in big */
139 if (size > sizeof (gpointer) * 5) {
140 long shifted = size >> MONO_PPC_32_64_CASE (2, 3);
141 guint8 *copy_loop_start, *copy_loop_jump;
143 ppc_load (code, ppc_r0, shifted);
144 ppc_mtctr (code, ppc_r0);
145 g_assert (sreg == ppc_r11);
146 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
147 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
148 copy_loop_start = code;
149 ppc_load_reg_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
150 ppc_store_reg_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
151 copy_loop_jump = code;
152 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
153 ppc_patch (copy_loop_jump, copy_loop_start);
154 size -= shifted * sizeof (gpointer);
155 doffset = soffset = 0;
158 #ifdef __mono_ppc64__
160 ppc_load_reg (code, ppc_r0, soffset, sreg);
161 ppc_store_reg (code, ppc_r0, doffset, dreg);
168 ppc_lwz (code, ppc_r0, soffset, sreg);
169 ppc_stw (code, ppc_r0, doffset, dreg);
175 ppc_lhz (code, ppc_r0, soffset, sreg);
176 ppc_sth (code, ppc_r0, doffset, dreg);
182 ppc_lbz (code, ppc_r0, soffset, sreg);
183 ppc_stb (code, ppc_r0, doffset, dreg);
192 * mono_arch_get_argument_info:
193 * @csig: a method signature
194 * @param_count: the number of parameters to consider
195 * @arg_info: an array to store the result infos
197 * Gathers information on parameters such as size, alignment and
198 * padding. arg_info should be large enought to hold param_count + 1 entries.
200 * Returns the size of the activation frame.
203 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
205 #ifdef __mono_ppc64__
209 int k, frame_size = 0;
210 int size, align, pad;
213 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
214 frame_size += sizeof (gpointer);
218 arg_info [0].offset = offset;
221 frame_size += sizeof (gpointer);
225 arg_info [0].size = frame_size;
227 for (k = 0; k < param_count; k++) {
230 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
232 size = mini_type_stack_size (NULL, csig->params [k], &align);
234 /* ignore alignment for now */
237 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
238 arg_info [k].pad = pad;
240 arg_info [k + 1].pad = 0;
241 arg_info [k + 1].size = size;
243 arg_info [k + 1].offset = offset;
247 align = MONO_ARCH_FRAME_ALIGNMENT;
248 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
249 arg_info [k].pad = pad;
255 #ifdef __mono_ppc64__
257 is_load_sequence (guint32 *seq)
259 return ppc_opcode (seq [0]) == 15 && /* lis */
260 ppc_opcode (seq [1]) == 24 && /* ori */
261 ppc_opcode (seq [2]) == 30 && /* sldi */
262 ppc_opcode (seq [3]) == 25 && /* oris */
263 ppc_opcode (seq [4]) == 24; /* ori */
266 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
267 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
270 /* code must point to the blrl */
272 mono_ppc_is_direct_call_sequence (guint32 *code)
274 #ifdef __mono_ppc64__
275 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
277 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
278 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
279 if (ppc_opcode (code [-2]) == 58 && ppc_opcode (code [-3]) == 58) { /* ld/ld */
280 if (!is_load_sequence (&code [-8]))
282 /* one of the loads must be "ld r2,8(rX)" */
283 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == 8) ||
284 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == 8);
286 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
287 return is_load_sequence (&code [-8]);
289 return is_load_sequence (&code [-6]);
293 g_assert(*code == 0x4e800021);
295 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
296 return ppc_opcode (code [-1]) == 31 &&
297 ppc_opcode (code [-2]) == 24 &&
298 ppc_opcode (code [-3]) == 15;
303 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
307 guint32* code = (guint32*)code_ptr;
311 /* This is the 'blrl' instruction */
314 /* Sanity check: instruction must be 'blrl' */
315 if (*code != 0x4e800021)
318 if (mono_ppc_is_direct_call_sequence (code))
321 /* FIXME: more sanity checks here */
322 /* OK, we're now at the 'blrl' instruction. Now walk backwards
323 till we get to a 'mtlr rA' */
325 if((*code & 0x7c0803a6) == 0x7c0803a6) {
327 /* Here we are: we reached the 'mtlr rA'.
328 Extract the register from the instruction */
329 reg = (*code & 0x03e00000) >> 21;
331 /* ok, this is a lwz reg, offset (vtreg)
332 * it is emitted with:
333 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
335 soff = (*code & 0xffff);
337 reg = (*code >> 16) & 0x1f;
338 g_assert (reg != ppc_r1);
339 /*g_print ("patching reg is %d\n", reg);*/
341 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gpointer)));
342 /* saved in the MonoLMF structure */
343 o = (gpointer)lmf->iregs [reg - 13];
350 *displacement = offset;
355 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
359 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
362 return (gpointer*)((char*)vt + displacement);
365 #define MAX_ARCH_DELEGATE_PARAMS 7
368 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
370 guint8 *code, *start;
372 /* FIXME: Support more cases */
373 if (MONO_TYPE_ISSTRUCT (sig->ret))
377 static guint8* cached = NULL;
378 int size = MONO_PPC_32_64_CASE (16, 20) + PPC_FTNPTR_SIZE;
379 mono_mini_arch_lock ();
381 mono_mini_arch_unlock ();
385 start = code = mono_global_codeman_reserve (size);
386 code = mono_ppc_create_pre_code_ftnptr (code);
388 /* Replace the this argument with the target */
389 ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
390 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
391 /* it's a function descriptor */
392 ppc_ldx (code, ppc_r0, 0, ppc_r0);
394 ppc_mtctr (code, ppc_r0);
395 ppc_load_reg (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
396 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
398 g_assert ((code - start) <= size);
400 mono_arch_flush_icache (start, size);
402 mono_mini_arch_unlock ();
405 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
408 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
410 for (i = 0; i < sig->param_count; ++i)
411 if (!mono_is_regsize_var (sig->params [i]))
414 mono_mini_arch_lock ();
415 code = cache [sig->param_count];
417 mono_mini_arch_unlock ();
421 size = MONO_PPC_32_64_CASE (12, 16) + sig->param_count * 4 + PPC_FTNPTR_SIZE;
422 start = code = mono_global_codeman_reserve (size);
423 code = mono_ppc_create_pre_code_ftnptr (code);
425 ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
426 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
427 /* it's a function descriptor */
428 ppc_ldx (code, ppc_r0, 0, ppc_r0);
430 ppc_mtctr (code, ppc_r0);
431 /* slide down the arguments */
432 for (i = 0; i < sig->param_count; ++i) {
433 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
435 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
437 g_assert ((code - start) <= size);
439 mono_arch_flush_icache (start, size);
440 cache [sig->param_count] = start;
441 mono_mini_arch_unlock ();
448 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
450 /* FIXME: handle returning a struct */
451 if (MONO_TYPE_ISSTRUCT (sig->ret))
452 return (gpointer)regs [ppc_r4];
453 return (gpointer)regs [ppc_r3];
457 * Initialize the cpu to execute managed code.
460 mono_arch_cpu_init (void)
465 * Initialize architecture specific code.
468 mono_arch_init (void)
470 InitializeCriticalSection (&mini_arch_mutex);
474 * Cleanup architecture specific code.
477 mono_arch_cleanup (void)
479 DeleteCriticalSection (&mini_arch_mutex);
483 * This function returns the optimizations supported on this cpu.
486 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
490 /* no ppc-specific optimizations yet */
495 #ifdef __mono_ppc64__
496 #define CASE_PPC32(c)
497 #define CASE_PPC64(c) case c:
499 #define CASE_PPC32(c) case c:
500 #define CASE_PPC64(c)
504 is_regsize_var (MonoType *t) {
507 t = mini_type_get_underlying_type (NULL, t);
511 CASE_PPC64 (MONO_TYPE_I8)
512 CASE_PPC64 (MONO_TYPE_U8)
516 case MONO_TYPE_FNPTR:
518 case MONO_TYPE_OBJECT:
519 case MONO_TYPE_STRING:
520 case MONO_TYPE_CLASS:
521 case MONO_TYPE_SZARRAY:
522 case MONO_TYPE_ARRAY:
524 case MONO_TYPE_GENERICINST:
525 if (!mono_type_generic_inst_is_valuetype (t))
528 case MONO_TYPE_VALUETYPE:
535 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
540 for (i = 0; i < cfg->num_varinfo; i++) {
541 MonoInst *ins = cfg->varinfo [i];
542 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
545 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
548 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
551 /* we can only allocate 32 bit values */
552 if (is_regsize_var (ins->inst_vtype)) {
553 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
554 g_assert (i == vmv->idx);
555 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
563 mono_arch_get_global_int_regs (MonoCompile *cfg)
567 if (cfg->frame_reg != ppc_sp)
569 /* ppc_r13 is used by the system on PPC EABI */
570 for (i = 14; i < top; ++i)
571 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
577 * mono_arch_regalloc_cost:
579 * Return the cost, in number of memory references, of the action of
580 * allocating the variable VMV into a register during global register
584 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
596 mono_arch_flush_icache (guint8 *code, gint size)
599 guint8 *endp, *start;
600 static int cachelinesize = 0;
601 static int cachelineinc = 16;
603 if (!cachelinesize) {
608 mib [1] = HW_CACHELINE;
609 len = sizeof (cachelinesize);
610 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
614 cachelineinc = cachelinesize;
615 /*g_print ("setting cl size to %d\n", cachelinesize);*/
617 #elif defined(__linux__)
618 /* sadly this will work only with 2.6 kernels... */
619 FILE* f = fopen ("/proc/self/auxv", "rb");
622 while (fread (&vec, sizeof (vec), 1, f) == 1) {
623 if (vec.type == 19) {
624 cachelinesize = vec.value;
632 #elif defined(G_COMPILER_CODEWARRIOR)
636 #warning Need a way to get cache line size
642 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
643 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
644 #if defined(G_COMPILER_CODEWARRIOR)
646 for (p = start; p < endp; p += cachelineinc) {
650 for (p = start; p < endp; p += cachelineinc) {
656 for (p = start; p < endp; p += cachelineinc) {
668 for (p = start; p < endp; p += cachelineinc) {
669 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
672 for (p = start; p < endp; p += cachelineinc) {
673 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
678 for (p = start; p < endp; p += cachelineinc) {
679 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
687 mono_arch_flush_register_windows (void)
692 #define ALWAYS_ON_STACK(s) s
693 #define FP_ALSO_IN_REG(s) s
695 #ifdef __mono_ppc64__
696 #define ALWAYS_ON_STACK(s) s
697 #define FP_ALSO_IN_REG(s) s
699 #define ALWAYS_ON_STACK(s)
700 #define FP_ALSO_IN_REG(s)
702 #define ALIGN_DOUBLES
715 guint32 vtsize; /* in param area */
717 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
718 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
719 guint8 bytes : 4; /* size in bytes - only valid for
720 RegTypeStructByVal if the struct fits
721 in one word, otherwise it's 0*/
736 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
738 #ifdef __mono_ppc64__
743 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
744 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
745 ainfo->reg = ppc_sp; /* in the caller */
746 ainfo->regtype = RegTypeBase;
747 *stack_size += sizeof (gpointer);
749 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
753 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
755 //*stack_size += (*stack_size % 8);
757 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
758 ainfo->reg = ppc_sp; /* in the caller */
759 ainfo->regtype = RegTypeBase;
766 ALWAYS_ON_STACK (*stack_size += 8);
774 #if defined(__APPLE__) || defined(__mono_ppc64__)
776 has_only_a_r48_field (MonoClass *klass)
780 gboolean have_field = FALSE;
782 while ((f = mono_class_get_fields (klass, &iter))) {
783 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
786 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
797 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
800 int n = sig->hasthis + sig->param_count;
802 guint32 stack_size = 0;
803 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
805 fr = PPC_FIRST_FPARG_REG;
806 gr = PPC_FIRST_ARG_REG;
808 /* FIXME: handle returning a struct */
809 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
810 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
811 cinfo->struct_ret = PPC_FIRST_ARG_REG;
816 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
819 DEBUG(printf("params: %d\n", sig->param_count));
820 for (i = 0; i < sig->param_count; ++i) {
821 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
822 /* Prevent implicit arguments and sig_cookie from
823 being passed in registers */
824 gr = PPC_LAST_ARG_REG + 1;
825 /* FIXME: don't we have to set fr, too? */
826 /* Emit the signature cookie just before the implicit arguments */
827 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
829 DEBUG(printf("param %d: ", i));
830 if (sig->params [i]->byref) {
831 DEBUG(printf("byref\n"));
832 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
836 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
837 switch (simpletype) {
838 case MONO_TYPE_BOOLEAN:
841 cinfo->args [n].size = 1;
842 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
848 cinfo->args [n].size = 2;
849 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
854 cinfo->args [n].size = 4;
855 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
861 case MONO_TYPE_FNPTR:
862 case MONO_TYPE_CLASS:
863 case MONO_TYPE_OBJECT:
864 case MONO_TYPE_STRING:
865 case MONO_TYPE_SZARRAY:
866 case MONO_TYPE_ARRAY:
867 cinfo->args [n].size = sizeof (gpointer);
868 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
871 case MONO_TYPE_GENERICINST:
872 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
873 cinfo->args [n].size = sizeof (gpointer);
874 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
879 case MONO_TYPE_VALUETYPE: {
882 klass = mono_class_from_mono_type (sig->params [i]);
884 size = mono_class_native_size (klass, NULL);
886 size = mono_class_value_size (klass, NULL);
887 #if defined(__APPLE__) || defined(__mono_ppc64__)
888 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
889 cinfo->args [n].size = size;
891 /* It was 7, now it is 8 in LinuxPPC */
892 if (fr <= PPC_LAST_FPARG_REG) {
893 cinfo->args [n].regtype = RegTypeFP;
894 cinfo->args [n].reg = fr;
896 FP_ALSO_IN_REG (gr ++);
898 FP_ALSO_IN_REG (gr ++);
899 ALWAYS_ON_STACK (stack_size += size);
901 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
902 cinfo->args [n].regtype = RegTypeBase;
903 cinfo->args [n].reg = ppc_sp; /* in the caller*/
910 DEBUG(printf ("load %d bytes struct\n",
911 mono_class_native_size (sig->params [i]->data.klass, NULL)));
912 #if PPC_PASS_STRUCTS_BY_VALUE
914 int align_size = size;
916 int rest = PPC_LAST_ARG_REG - gr + 1;
918 align_size += (sizeof (gpointer) - 1);
919 align_size &= ~(sizeof (gpointer) - 1);
920 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
921 n_in_regs = MIN (rest, nwords);
922 cinfo->args [n].regtype = RegTypeStructByVal;
923 if (gr > PPC_LAST_ARG_REG
925 /* FIXME: check this */
926 || (size >= 3 && size % 4 != 0)
929 cinfo->args [n].size = 0;
930 cinfo->args [n].vtsize = nwords;
932 cinfo->args [n].size = n_in_regs;
933 cinfo->args [n].vtsize = nwords - n_in_regs;
934 cinfo->args [n].reg = gr;
936 #ifdef __mono_ppc64__
937 if (nwords == 1 && is_pinvoke)
938 cinfo->args [n].bytes = size;
941 cinfo->args [n].bytes = 0;
943 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
944 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
945 stack_size += nwords * sizeof (gpointer);
948 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
949 cinfo->args [n].regtype = RegTypeStructByAddr;
950 cinfo->args [n].vtsize = size;
955 case MONO_TYPE_TYPEDBYREF: {
956 int size = sizeof (MonoTypedRef);
957 /* keep in sync or merge with the valuetype case */
958 #if PPC_PASS_STRUCTS_BY_VALUE
960 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
961 cinfo->args [n].regtype = RegTypeStructByVal;
962 if (gr <= PPC_LAST_ARG_REG) {
963 int rest = PPC_LAST_ARG_REG - gr + 1;
964 int n_in_regs = rest >= nwords? nwords: rest;
965 cinfo->args [n].size = n_in_regs;
966 cinfo->args [n].vtsize = nwords - n_in_regs;
967 cinfo->args [n].reg = gr;
970 cinfo->args [n].size = 0;
971 cinfo->args [n].vtsize = nwords;
973 #ifdef __mono_ppc64__
974 if (nwords == 1 && is_pinvoke)
975 cinfo->args [n].bytes = size;
978 cinfo->args [n].bytes = 0;
979 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
980 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
981 stack_size += nwords * sizeof (gpointer);
984 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
985 cinfo->args [n].regtype = RegTypeStructByAddr;
986 cinfo->args [n].vtsize = size;
993 cinfo->args [n].size = 8;
994 add_general (&gr, &stack_size, cinfo->args + n, sizeof (gpointer) == 8);
998 cinfo->args [n].size = 4;
1000 /* It was 7, now it is 8 in LinuxPPC */
1001 if (fr <= PPC_LAST_FPARG_REG) {
1002 cinfo->args [n].regtype = RegTypeFP;
1003 cinfo->args [n].reg = fr;
1005 FP_ALSO_IN_REG (gr ++);
1006 ALWAYS_ON_STACK (stack_size += sizeof (gpointer));
1008 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1009 cinfo->args [n].regtype = RegTypeBase;
1010 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1011 stack_size += sizeof (gpointer);
1016 cinfo->args [n].size = 8;
1017 /* It was 7, now it is 8 in LinuxPPC */
1018 if (fr <= PPC_LAST_FPARG_REG) {
1019 cinfo->args [n].regtype = RegTypeFP;
1020 cinfo->args [n].reg = fr;
1022 FP_ALSO_IN_REG (gr += sizeof (double) / sizeof (gpointer));
1023 ALWAYS_ON_STACK (stack_size += 8);
1025 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1026 cinfo->args [n].regtype = RegTypeBase;
1027 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1033 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1037 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1038 /* Prevent implicit arguments and sig_cookie from
1039 being passed in registers */
1040 gr = PPC_LAST_ARG_REG + 1;
1041 /* Emit the signature cookie just before the implicit arguments */
1042 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1046 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
1047 switch (simpletype) {
1048 case MONO_TYPE_BOOLEAN:
1053 case MONO_TYPE_CHAR:
1059 case MONO_TYPE_FNPTR:
1060 case MONO_TYPE_CLASS:
1061 case MONO_TYPE_OBJECT:
1062 case MONO_TYPE_SZARRAY:
1063 case MONO_TYPE_ARRAY:
1064 case MONO_TYPE_STRING:
1065 cinfo->ret.reg = ppc_r3;
1069 cinfo->ret.reg = ppc_r3;
1073 cinfo->ret.reg = ppc_f1;
1074 cinfo->ret.regtype = RegTypeFP;
1076 case MONO_TYPE_GENERICINST:
1077 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
1078 cinfo->ret.reg = ppc_r3;
1082 case MONO_TYPE_VALUETYPE:
1084 case MONO_TYPE_TYPEDBYREF:
1085 case MONO_TYPE_VOID:
1088 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1092 /* align stack size to 16 */
1093 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1094 stack_size = (stack_size + 15) & ~15;
1096 cinfo->stack_usage = stack_size;
1101 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1103 #if !PPC_PASS_STRUCTS_BY_VALUE
1104 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1105 int num_structs = 0;
1108 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1111 for (i = 0; i < sig->param_count; ++i) {
1112 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1113 if (type->type == MONO_TYPE_VALUETYPE)
1118 cfg->tailcall_valuetype_addrs =
1119 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1120 for (i = 0; i < num_structs; ++i) {
1121 cfg->tailcall_valuetype_addrs [i] =
1122 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1123 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1130 * Set var information according to the calling convention. ppc version.
1131 * The locals var stuff should most likely be split in another method.
1134 mono_arch_allocate_vars (MonoCompile *m)
1136 MonoMethodSignature *sig;
1137 MonoMethodHeader *header;
1139 int i, offset, size, align, curinst;
1140 int frame_reg = ppc_sp;
1142 guint32 locals_stack_size, locals_stack_align;
1144 allocate_tailcall_valuetype_addrs (m);
1146 m->flags |= MONO_CFG_HAS_SPILLUP;
1148 /* allow room for the vararg method args: void* and long/double */
1149 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1150 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1151 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1152 * call convs needs to be handled this way.
1154 if (m->flags & MONO_CFG_HAS_VARARGS)
1155 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1156 /* gtk-sharp and other broken code will dllimport vararg functions even with
1157 * non-varargs signatures. Since there is little hope people will get this right
1158 * we assume they won't.
1160 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1161 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1163 header = mono_method_get_header (m->method);
1166 * We use the frame register also for any method that has
1167 * exception clauses. This way, when the handlers are called,
1168 * the code will reference local variables using the frame reg instead of
1169 * the stack pointer: if we had to restore the stack pointer, we'd
1170 * corrupt the method frames that are already on the stack (since
1171 * filters get called before stack unwinding happens) when the filter
1172 * code would call any method (this also applies to finally etc.).
1174 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1175 frame_reg = ppc_r31;
1176 m->frame_reg = frame_reg;
1177 if (frame_reg != ppc_sp) {
1178 m->used_int_regs |= 1 << frame_reg;
1181 sig = mono_method_signature (m->method);
1185 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1186 m->ret->opcode = OP_REGVAR;
1187 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1189 /* FIXME: handle long values? */
1190 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1191 case MONO_TYPE_VOID:
1195 m->ret->opcode = OP_REGVAR;
1196 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1199 m->ret->opcode = OP_REGVAR;
1200 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1204 /* local vars are at a positive offset from the stack pointer */
1206 * also note that if the function uses alloca, we use ppc_r31
1207 * to point at the local variables.
1209 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1210 /* align the offset to 16 bytes: not sure this is needed here */
1212 //offset &= ~(16 - 1);
1214 /* add parameter area size for called functions */
1215 offset += m->param_area;
1217 offset &= ~(16 - 1);
1219 /* allow room to save the return value */
1220 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1223 /* the MonoLMF structure is stored just below the stack pointer */
1226 /* this stuff should not be needed on ppc and the new jit,
1227 * because a call on ppc to the handlers doesn't change the
1228 * stack pointer and the jist doesn't manipulate the stack pointer
1229 * for operations involving valuetypes.
1231 /* reserve space to store the esp */
1232 offset += sizeof (gpointer);
1234 /* this is a global constant */
1235 mono_exc_esp_offset = offset;
1238 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1239 offset += sizeof(gpointer) - 1;
1240 offset &= ~(sizeof(gpointer) - 1);
1242 m->vret_addr->opcode = OP_REGOFFSET;
1243 m->vret_addr->inst_basereg = frame_reg;
1244 m->vret_addr->inst_offset = offset;
1246 if (G_UNLIKELY (m->verbose_level > 1)) {
1247 printf ("vret_addr =");
1248 mono_print_ins (m->vret_addr);
1251 offset += sizeof(gpointer);
1254 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1255 if (locals_stack_align) {
1256 offset += (locals_stack_align - 1);
1257 offset &= ~(locals_stack_align - 1);
1259 for (i = m->locals_start; i < m->num_varinfo; i++) {
1260 if (offsets [i] != -1) {
1261 MonoInst *inst = m->varinfo [i];
1262 inst->opcode = OP_REGOFFSET;
1263 inst->inst_basereg = frame_reg;
1264 inst->inst_offset = offset + offsets [i];
1266 g_print ("allocating local %d (%s) to %d\n",
1267 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1271 offset += locals_stack_size;
1275 inst = m->args [curinst];
1276 if (inst->opcode != OP_REGVAR) {
1277 inst->opcode = OP_REGOFFSET;
1278 inst->inst_basereg = frame_reg;
1279 offset += sizeof (gpointer) - 1;
1280 offset &= ~(sizeof (gpointer) - 1);
1281 inst->inst_offset = offset;
1282 offset += sizeof (gpointer);
1287 for (i = 0; i < sig->param_count; ++i) {
1288 inst = m->args [curinst];
1289 if (inst->opcode != OP_REGVAR) {
1290 inst->opcode = OP_REGOFFSET;
1291 inst->inst_basereg = frame_reg;
1293 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1294 inst->backend.is_pinvoke = 1;
1296 size = mono_type_size (sig->params [i], &align);
1298 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1299 size = align = sizeof (gpointer);
1300 offset += align - 1;
1301 offset &= ~(align - 1);
1302 inst->inst_offset = offset;
1308 /* some storage for fp conversions */
1311 m->arch.fp_conv_var_offset = offset;
1314 /* align the offset to 16 bytes */
1316 offset &= ~(16 - 1);
1319 m->stack_offset = offset;
1321 if (sig->call_convention == MONO_CALL_VARARG) {
1322 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1324 m->sig_cookie = cinfo->sig_cookie.offset;
1331 mono_arch_create_vars (MonoCompile *cfg)
1333 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1335 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1336 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1340 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1341 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1345 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1347 int sig_reg = mono_alloc_ireg (cfg);
1349 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1350 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1351 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1355 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1358 MonoMethodSignature *sig;
1362 sig = call->signature;
1363 n = sig->param_count + sig->hasthis;
1365 cinfo = calculate_sizes (sig, sig->pinvoke);
1367 for (i = 0; i < n; ++i) {
1368 ArgInfo *ainfo = cinfo->args + i;
1371 if (i >= sig->hasthis)
1372 t = sig->params [i - sig->hasthis];
1374 t = &mono_defaults.int_class->byval_arg;
1375 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1377 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1378 emit_sig_cookie (cfg, call, cinfo);
1380 in = call->args [i];
1382 if (ainfo->regtype == RegTypeGeneral) {
1383 #ifndef __mono_ppc64__
1384 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1385 MONO_INST_NEW (cfg, ins, OP_MOVE);
1386 ins->dreg = mono_alloc_ireg (cfg);
1387 ins->sreg1 = in->dreg + 1;
1388 MONO_ADD_INS (cfg->cbb, ins);
1389 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1391 MONO_INST_NEW (cfg, ins, OP_MOVE);
1392 ins->dreg = mono_alloc_ireg (cfg);
1393 ins->sreg1 = in->dreg + 2;
1394 MONO_ADD_INS (cfg->cbb, ins);
1395 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1399 MONO_INST_NEW (cfg, ins, OP_MOVE);
1400 ins->dreg = mono_alloc_ireg (cfg);
1401 ins->sreg1 = in->dreg;
1402 MONO_ADD_INS (cfg->cbb, ins);
1404 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1406 } else if (ainfo->regtype == RegTypeStructByAddr) {
1407 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1408 ins->opcode = OP_OUTARG_VT;
1409 ins->sreg1 = in->dreg;
1410 ins->klass = in->klass;
1411 ins->inst_p0 = call;
1412 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1413 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1414 MONO_ADD_INS (cfg->cbb, ins);
1415 } else if (ainfo->regtype == RegTypeStructByVal) {
1416 /* this is further handled in mono_arch_emit_outarg_vt () */
1417 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1418 ins->opcode = OP_OUTARG_VT;
1419 ins->sreg1 = in->dreg;
1420 ins->klass = in->klass;
1421 ins->inst_p0 = call;
1422 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1423 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1424 MONO_ADD_INS (cfg->cbb, ins);
1425 } else if (ainfo->regtype == RegTypeBase) {
1426 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1427 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1428 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1429 if (t->type == MONO_TYPE_R8)
1430 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1432 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1434 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1436 } else if (ainfo->regtype == RegTypeFP) {
1437 if (t->type == MONO_TYPE_VALUETYPE) {
1438 /* this is further handled in mono_arch_emit_outarg_vt () */
1439 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1440 ins->opcode = OP_OUTARG_VT;
1441 ins->sreg1 = in->dreg;
1442 ins->klass = in->klass;
1443 ins->inst_p0 = call;
1444 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1445 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1446 MONO_ADD_INS (cfg->cbb, ins);
1448 cfg->flags |= MONO_CFG_HAS_FPOUT;
1450 int dreg = mono_alloc_freg (cfg);
1452 if (ainfo->size == 4) {
1453 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1455 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1457 ins->sreg1 = in->dreg;
1458 MONO_ADD_INS (cfg->cbb, ins);
1461 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1462 cfg->flags |= MONO_CFG_HAS_FPOUT;
1465 g_assert_not_reached ();
1469 /* Emit the signature cookie in the case that there is no
1470 additional argument */
1471 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1472 emit_sig_cookie (cfg, call, cinfo);
1474 if (cinfo->struct_ret) {
1477 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1478 vtarg->sreg1 = call->vret_var->dreg;
1479 vtarg->dreg = mono_alloc_preg (cfg);
1480 MONO_ADD_INS (cfg->cbb, vtarg);
1482 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1485 call->stack_usage = cinfo->stack_usage;
1486 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1487 cfg->flags |= MONO_CFG_HAS_CALLS;
1493 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1495 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1496 ArgInfo *ainfo = ins->inst_p1;
1497 int ovf_size = ainfo->vtsize;
1498 int doffset = ainfo->offset;
1499 int i, soffset, dreg;
1501 if (ainfo->regtype == RegTypeStructByVal) {
1508 * Darwin pinvokes needs some special handling for 1
1509 * and 2 byte arguments
1511 g_assert (ins->klass);
1512 if (call->signature->pinvoke)
1513 size = mono_class_native_size (ins->klass, NULL);
1514 if (size == 2 || size == 1) {
1515 int tmpr = mono_alloc_ireg (cfg);
1517 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1519 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1520 dreg = mono_alloc_ireg (cfg);
1521 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1522 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1525 for (i = 0; i < ainfo->size; ++i) {
1526 int antipadding = 0;
1529 antipadding = sizeof (gpointer) - ainfo->bytes;
1531 dreg = mono_alloc_ireg (cfg);
1532 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1534 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1535 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1536 soffset += sizeof (gpointer);
1539 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1540 } else if (ainfo->regtype == RegTypeFP) {
1541 int tmpr = mono_alloc_freg (cfg);
1542 if (ainfo->size == 4)
1543 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1545 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1546 dreg = mono_alloc_freg (cfg);
1547 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1548 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1550 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1554 /* FIXME: alignment? */
1555 if (call->signature->pinvoke) {
1556 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1557 vtcopy->backend.is_pinvoke = 1;
1559 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1562 g_assert (ovf_size > 0);
1564 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1565 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1568 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1570 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1575 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1577 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1578 mono_method_signature (method)->ret);
1581 #ifndef __mono_ppc64__
1582 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1585 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1586 ins->sreg1 = val->dreg + 1;
1587 ins->sreg2 = val->dreg + 2;
1588 MONO_ADD_INS (cfg->cbb, ins);
1592 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1593 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1597 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1600 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1602 mono_arch_is_inst_imm (gint64 imm)
1608 * Allow tracing to work with this interface (with an optional argument)
1612 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1616 ppc_load (code, ppc_r3, cfg->method);
1617 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1618 ppc_load_func (code, ppc_r0, func);
1619 ppc_mtlr (code, ppc_r0);
1633 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1636 int save_mode = SAVE_NONE;
1638 MonoMethod *method = cfg->method;
1639 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1640 mono_method_signature (method)->ret)->type;
1641 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1645 offset = code - cfg->native_code;
1646 /* we need about 16 instructions */
1647 if (offset > (cfg->code_size - 16 * 4)) {
1648 cfg->code_size *= 2;
1649 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1650 code = cfg->native_code + offset;
1654 case MONO_TYPE_VOID:
1655 /* special case string .ctor icall */
1656 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1657 save_mode = SAVE_ONE;
1659 save_mode = SAVE_NONE;
1661 #ifndef __mono_ppc64__
1664 save_mode = SAVE_TWO;
1669 save_mode = SAVE_FP;
1671 case MONO_TYPE_VALUETYPE:
1672 save_mode = SAVE_STRUCT;
1675 save_mode = SAVE_ONE;
1679 switch (save_mode) {
1681 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1682 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1683 if (enable_arguments) {
1684 ppc_mr (code, ppc_r5, ppc_r4);
1685 ppc_mr (code, ppc_r4, ppc_r3);
1689 ppc_store_reg (code, ppc_r3, save_offset, cfg->frame_reg);
1690 if (enable_arguments) {
1691 ppc_mr (code, ppc_r4, ppc_r3);
1695 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1696 if (enable_arguments) {
1697 /* FIXME: what reg? */
1698 ppc_fmr (code, ppc_f3, ppc_f1);
1699 /* FIXME: use 8 byte load on PPC64 */
1700 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1701 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1705 if (enable_arguments) {
1706 /* FIXME: get the actual address */
1707 ppc_mr (code, ppc_r4, ppc_r3);
1715 ppc_load (code, ppc_r3, cfg->method);
1716 ppc_load_func (code, ppc_r0, func);
1717 ppc_mtlr (code, ppc_r0);
1720 switch (save_mode) {
1722 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1723 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1726 ppc_load_reg (code, ppc_r3, save_offset, cfg->frame_reg);
1729 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1739 * Conditional branches have a small offset, so if it is likely overflowed,
1740 * we do a branch to the end of the method (uncond branches have much larger
1741 * offsets) where we perform the conditional and jump back unconditionally.
1742 * It's slightly slower, since we add two uncond branches, but it's very simple
1743 * with the current patch implementation and such large methods are likely not
1744 * going to be perf critical anyway.
1749 const char *exception;
1756 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1757 if (ins->flags & MONO_INST_BRLABEL) { \
1758 if (0 && ins->inst_i0->inst_c0) { \
1759 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff); \
1761 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1762 ppc_bc (code, (b0), (b1), 0); \
1765 if (0 && ins->inst_true_bb->native_offset) { \
1766 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1768 int br_disp = ins->inst_true_bb->max_offset - offset; \
1769 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1770 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1771 ovfj->data.bb = ins->inst_true_bb; \
1772 ovfj->ip_offset = 0; \
1773 ovfj->b0_cond = (b0); \
1774 ovfj->b1_cond = (b1); \
1775 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1778 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1779 ppc_bc (code, (b0), (b1), 0); \
1784 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1786 /* emit an exception if condition is fail
1788 * We assign the extra code used to throw the implicit exceptions
1789 * to cfg->bb_exit as far as the big branch handling is concerned
1791 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1793 int br_disp = cfg->bb_exit->max_offset - offset; \
1794 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1795 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1796 ovfj->data.exception = (exc_name); \
1797 ovfj->ip_offset = code - cfg->native_code; \
1798 ovfj->b0_cond = (b0); \
1799 ovfj->b1_cond = (b1); \
1800 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1802 cfg->bb_exit->max_offset += 24; \
1804 mono_add_patch_info (cfg, code - cfg->native_code, \
1805 MONO_PATCH_INFO_EXC, exc_name); \
1806 ppc_bcl (code, (b0), (b1), 0); \
1810 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1813 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1818 normalize_opcode (int opcode)
1821 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1822 return OP_LOAD_MEMBASE;
1823 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1824 return OP_LOAD_MEMINDEX;
1825 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1826 return OP_STORE_MEMBASE_REG;
1827 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1828 return OP_STORE_MEMBASE_IMM;
1829 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1830 return OP_STORE_MEMINDEX;
1831 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1833 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1834 return OP_SHR_UN_IMM;
1841 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1843 MonoInst *ins, *n, *last_ins = NULL;
1845 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1846 switch (normalize_opcode (ins->opcode)) {
1848 /* remove unnecessary multiplication with 1 */
1849 if (ins->inst_imm == 1) {
1850 if (ins->dreg != ins->sreg1) {
1851 ins->opcode = OP_MOVE;
1853 MONO_DELETE_INS (bb, ins);
1857 int power2 = mono_is_power_of_two (ins->inst_imm);
1859 ins->opcode = OP_SHL_IMM;
1860 ins->inst_imm = power2;
1864 case OP_LOAD_MEMBASE:
1866 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1867 * OP_LOAD_MEMBASE offset(basereg), reg
1869 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
1870 ins->inst_basereg == last_ins->inst_destbasereg &&
1871 ins->inst_offset == last_ins->inst_offset) {
1872 if (ins->dreg == last_ins->sreg1) {
1873 MONO_DELETE_INS (bb, ins);
1876 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1877 ins->opcode = OP_MOVE;
1878 ins->sreg1 = last_ins->sreg1;
1882 * Note: reg1 must be different from the basereg in the second load
1883 * OP_LOAD_MEMBASE offset(basereg), reg1
1884 * OP_LOAD_MEMBASE offset(basereg), reg2
1886 * OP_LOAD_MEMBASE offset(basereg), reg1
1887 * OP_MOVE reg1, reg2
1889 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
1890 ins->inst_basereg != last_ins->dreg &&
1891 ins->inst_basereg == last_ins->inst_basereg &&
1892 ins->inst_offset == last_ins->inst_offset) {
1894 if (ins->dreg == last_ins->dreg) {
1895 MONO_DELETE_INS (bb, ins);
1898 ins->opcode = OP_MOVE;
1899 ins->sreg1 = last_ins->dreg;
1902 //g_assert_not_reached ();
1906 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1907 * OP_LOAD_MEMBASE offset(basereg), reg
1909 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1910 * OP_ICONST reg, imm
1912 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
1913 ins->inst_basereg == last_ins->inst_destbasereg &&
1914 ins->inst_offset == last_ins->inst_offset) {
1915 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1916 ins->opcode = OP_ICONST;
1917 ins->inst_c0 = last_ins->inst_imm;
1918 g_assert_not_reached (); // check this rule
1922 case OP_LOADU1_MEMBASE:
1923 case OP_LOADI1_MEMBASE:
1924 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1925 ins->inst_basereg == last_ins->inst_destbasereg &&
1926 ins->inst_offset == last_ins->inst_offset) {
1927 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1928 ins->sreg1 = last_ins->sreg1;
1931 case OP_LOADU2_MEMBASE:
1932 case OP_LOADI2_MEMBASE:
1933 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1934 ins->inst_basereg == last_ins->inst_destbasereg &&
1935 ins->inst_offset == last_ins->inst_offset) {
1936 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1937 ins->sreg1 = last_ins->sreg1;
1940 #ifdef __mono_ppc64__
1941 case OP_LOADU4_MEMBASE:
1942 case OP_LOADI4_MEMBASE:
1943 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
1944 ins->inst_basereg == last_ins->inst_destbasereg &&
1945 ins->inst_offset == last_ins->inst_offset) {
1946 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
1947 ins->sreg1 = last_ins->sreg1;
1952 ins->opcode = OP_MOVE;
1956 if (ins->dreg == ins->sreg1) {
1957 MONO_DELETE_INS (bb, ins);
1961 * OP_MOVE sreg, dreg
1962 * OP_MOVE dreg, sreg
1964 if (last_ins && last_ins->opcode == OP_MOVE &&
1965 ins->sreg1 == last_ins->dreg &&
1966 ins->dreg == last_ins->sreg1) {
1967 MONO_DELETE_INS (bb, ins);
1975 bb->last_ins = last_ins;
1979 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1981 switch (ins->opcode) {
1982 case OP_ICONV_TO_R_UN: {
1983 static const guint64 adjust_val = 0x4330000000000000ULL;
1984 int msw_reg = mono_alloc_ireg (cfg);
1985 int adj_reg = mono_alloc_freg (cfg);
1986 int tmp_reg = mono_alloc_freg (cfg);
1987 int basereg = ppc_sp;
1989 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1990 if (!ppc_is_imm16 (offset + 4)) {
1991 basereg = mono_alloc_ireg (cfg);
1992 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
1994 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
1995 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
1996 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1997 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
1998 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1999 ins->opcode = OP_NOP;
2002 #ifndef __mono_ppc64__
2003 case OP_ICONV_TO_R4:
2004 case OP_ICONV_TO_R8: {
2005 /* FIXME: change precision for CEE_CONV_R4 */
2006 static const guint64 adjust_val = 0x4330000080000000ULL;
2007 int msw_reg = mono_alloc_ireg (cfg);
2008 int xored = mono_alloc_ireg (cfg);
2009 int adj_reg = mono_alloc_freg (cfg);
2010 int tmp_reg = mono_alloc_freg (cfg);
2011 int basereg = ppc_sp;
2013 if (!ppc_is_imm16 (offset + 4)) {
2014 basereg = mono_alloc_ireg (cfg);
2015 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2017 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2018 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2019 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2020 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2021 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2022 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2023 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2024 if (ins->opcode == OP_ICONV_TO_R4)
2025 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2026 ins->opcode = OP_NOP;
2031 int msw_reg = mono_alloc_ireg (cfg);
2032 int basereg = ppc_sp;
2034 if (!ppc_is_imm16 (offset + 4)) {
2035 basereg = mono_alloc_ireg (cfg);
2036 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2038 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2039 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2040 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2041 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2042 ins->opcode = OP_NOP;
2045 #ifdef __mono_ppc64__
2047 case OP_IADD_OVF_UN:
2049 int shifted1_reg = mono_alloc_ireg (cfg);
2050 int shifted2_reg = mono_alloc_ireg (cfg);
2051 int result_shifted_reg = mono_alloc_ireg (cfg);
2053 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2055 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2056 if (ins->opcode == OP_IADD_OVF_UN)
2057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2059 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2060 ins->opcode = OP_NOP;
2067 * the branch_b0_table should maintain the order of these
2081 branch_b0_table [] = {
2096 branch_b1_table [] = {
2110 #define NEW_INS(cfg,dest,op) do { \
2111 MONO_INST_NEW((cfg), (dest), (op)); \
2112 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2116 map_to_reg_reg_op (int op)
2125 case OP_COMPARE_IMM:
2127 case OP_ICOMPARE_IMM:
2129 case OP_LCOMPARE_IMM:
2145 case OP_LOAD_MEMBASE:
2146 return OP_LOAD_MEMINDEX;
2147 case OP_LOADI4_MEMBASE:
2148 return OP_LOADI4_MEMINDEX;
2149 case OP_LOADU4_MEMBASE:
2150 return OP_LOADU4_MEMINDEX;
2151 case OP_LOADI8_MEMBASE:
2152 return OP_LOADI8_MEMINDEX;
2153 case OP_LOADU1_MEMBASE:
2154 return OP_LOADU1_MEMINDEX;
2155 case OP_LOADI2_MEMBASE:
2156 return OP_LOADI2_MEMINDEX;
2157 case OP_LOADU2_MEMBASE:
2158 return OP_LOADU2_MEMINDEX;
2159 case OP_LOADI1_MEMBASE:
2160 return OP_LOADI1_MEMINDEX;
2161 case OP_LOADR4_MEMBASE:
2162 return OP_LOADR4_MEMINDEX;
2163 case OP_LOADR8_MEMBASE:
2164 return OP_LOADR8_MEMINDEX;
2165 case OP_STOREI1_MEMBASE_REG:
2166 return OP_STOREI1_MEMINDEX;
2167 case OP_STOREI2_MEMBASE_REG:
2168 return OP_STOREI2_MEMINDEX;
2169 case OP_STOREI4_MEMBASE_REG:
2170 return OP_STOREI4_MEMINDEX;
2171 case OP_STOREI8_MEMBASE_REG:
2172 return OP_STOREI8_MEMINDEX;
2173 case OP_STORE_MEMBASE_REG:
2174 return OP_STORE_MEMINDEX;
2175 case OP_STORER4_MEMBASE_REG:
2176 return OP_STORER4_MEMINDEX;
2177 case OP_STORER8_MEMBASE_REG:
2178 return OP_STORER8_MEMINDEX;
2179 case OP_STORE_MEMBASE_IMM:
2180 return OP_STORE_MEMBASE_REG;
2181 case OP_STOREI1_MEMBASE_IMM:
2182 return OP_STOREI1_MEMBASE_REG;
2183 case OP_STOREI2_MEMBASE_IMM:
2184 return OP_STOREI2_MEMBASE_REG;
2185 case OP_STOREI4_MEMBASE_IMM:
2186 return OP_STOREI4_MEMBASE_REG;
2187 case OP_STOREI8_MEMBASE_IMM:
2188 return OP_STOREI8_MEMBASE_REG;
2190 return mono_op_imm_to_op (op);
2193 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2195 #define compare_opcode_is_unsigned(opcode) \
2196 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2197 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2198 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2199 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2200 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2201 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2202 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2203 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2206 * Remove from the instruction list the instructions that can't be
2207 * represented with very simple instructions with no register
2211 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2213 MonoInst *ins, *next, *temp, *last_ins = NULL;
2216 MONO_BB_FOR_EACH_INS (bb, ins) {
2218 switch (ins->opcode) {
2219 case OP_IDIV_UN_IMM:
2222 case OP_IREM_UN_IMM:
2223 NEW_INS (cfg, temp, OP_ICONST);
2224 temp->inst_c0 = ins->inst_imm;
2225 temp->dreg = mono_alloc_ireg (cfg);
2226 ins->sreg2 = temp->dreg;
2227 if (ins->opcode == OP_IDIV_IMM)
2228 ins->opcode = OP_IDIV;
2229 else if (ins->opcode == OP_IREM_IMM)
2230 ins->opcode = OP_IREM;
2231 else if (ins->opcode == OP_IDIV_UN_IMM)
2232 ins->opcode = OP_IDIV_UN;
2233 else if (ins->opcode == OP_IREM_UN_IMM)
2234 ins->opcode = OP_IREM_UN;
2236 /* handle rem separately */
2240 CASE_PPC64 (OP_LREM)
2241 CASE_PPC64 (OP_LREM_UN) {
2243 /* we change a rem dest, src1, src2 to
2244 * div temp1, src1, src2
2245 * mul temp2, temp1, src2
2246 * sub dest, src1, temp2
2248 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2249 NEW_INS (cfg, mul, OP_IMUL);
2250 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2251 ins->opcode = OP_ISUB;
2253 NEW_INS (cfg, mul, OP_LMUL);
2254 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2255 ins->opcode = OP_LSUB;
2257 temp->sreg1 = ins->sreg1;
2258 temp->sreg2 = ins->sreg2;
2259 temp->dreg = mono_alloc_ireg (cfg);
2260 mul->sreg1 = temp->dreg;
2261 mul->sreg2 = ins->sreg2;
2262 mul->dreg = mono_alloc_ireg (cfg);
2263 ins->sreg2 = mul->dreg;
2267 CASE_PPC64 (OP_LADD_IMM)
2270 if (!ppc_is_imm16 (ins->inst_imm)) {
2271 NEW_INS (cfg, temp, OP_ICONST);
2272 temp->inst_c0 = ins->inst_imm;
2273 temp->dreg = mono_alloc_ireg (cfg);
2274 ins->sreg2 = temp->dreg;
2275 ins->opcode = map_to_reg_reg_op (ins->opcode);
2279 CASE_PPC64 (OP_LSUB_IMM)
2281 if (!ppc_is_imm16 (-ins->inst_imm)) {
2282 NEW_INS (cfg, temp, OP_ICONST);
2283 temp->inst_c0 = ins->inst_imm;
2284 temp->dreg = mono_alloc_ireg (cfg);
2285 ins->sreg2 = temp->dreg;
2286 ins->opcode = map_to_reg_reg_op (ins->opcode);
2298 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2299 #ifdef __mono_ppc64__
2300 if (ins->inst_imm & 0xffffffff00000000UL)
2304 NEW_INS (cfg, temp, OP_ICONST);
2305 temp->inst_c0 = ins->inst_imm;
2306 temp->dreg = mono_alloc_ireg (cfg);
2307 ins->sreg2 = temp->dreg;
2308 ins->opcode = map_to_reg_reg_op (ins->opcode);
2317 NEW_INS (cfg, temp, OP_ICONST);
2318 temp->inst_c0 = ins->inst_imm;
2319 temp->dreg = mono_alloc_ireg (cfg);
2320 ins->sreg2 = temp->dreg;
2321 ins->opcode = map_to_reg_reg_op (ins->opcode);
2323 case OP_COMPARE_IMM:
2324 case OP_ICOMPARE_IMM:
2325 CASE_PPC64 (OP_LCOMPARE_IMM)
2327 /* Branch opts can eliminate the branch */
2328 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2329 ins->opcode = OP_NOP;
2333 if (compare_opcode_is_unsigned (next->opcode)) {
2334 if (!ppc_is_uimm16 (ins->inst_imm)) {
2335 NEW_INS (cfg, temp, OP_ICONST);
2336 temp->inst_c0 = ins->inst_imm;
2337 temp->dreg = mono_alloc_ireg (cfg);
2338 ins->sreg2 = temp->dreg;
2339 ins->opcode = map_to_reg_reg_op (ins->opcode);
2342 if (!ppc_is_imm16 (ins->inst_imm)) {
2343 NEW_INS (cfg, temp, OP_ICONST);
2344 temp->inst_c0 = ins->inst_imm;
2345 temp->dreg = mono_alloc_ireg (cfg);
2346 ins->sreg2 = temp->dreg;
2347 ins->opcode = map_to_reg_reg_op (ins->opcode);
2353 if (ins->inst_imm == 1) {
2354 ins->opcode = OP_MOVE;
2357 if (ins->inst_imm == 0) {
2358 ins->opcode = OP_ICONST;
2362 imm = mono_is_power_of_two (ins->inst_imm);
2364 ins->opcode = OP_SHL_IMM;
2365 ins->inst_imm = imm;
2368 if (!ppc_is_imm16 (ins->inst_imm)) {
2369 NEW_INS (cfg, temp, OP_ICONST);
2370 temp->inst_c0 = ins->inst_imm;
2371 temp->dreg = mono_alloc_ireg (cfg);
2372 ins->sreg2 = temp->dreg;
2373 ins->opcode = map_to_reg_reg_op (ins->opcode);
2376 case OP_LOCALLOC_IMM:
2377 NEW_INS (cfg, temp, OP_ICONST);
2378 temp->inst_c0 = ins->inst_imm;
2379 temp->dreg = mono_alloc_ireg (cfg);
2380 ins->sreg1 = temp->dreg;
2381 ins->opcode = OP_LOCALLOC;
2383 case OP_LOAD_MEMBASE:
2384 case OP_LOADI4_MEMBASE:
2385 CASE_PPC64 (OP_LOADI8_MEMBASE)
2386 case OP_LOADU4_MEMBASE:
2387 case OP_LOADI2_MEMBASE:
2388 case OP_LOADU2_MEMBASE:
2389 case OP_LOADI1_MEMBASE:
2390 case OP_LOADU1_MEMBASE:
2391 case OP_LOADR4_MEMBASE:
2392 case OP_LOADR8_MEMBASE:
2393 case OP_STORE_MEMBASE_REG:
2394 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2395 case OP_STOREI4_MEMBASE_REG:
2396 case OP_STOREI2_MEMBASE_REG:
2397 case OP_STOREI1_MEMBASE_REG:
2398 case OP_STORER4_MEMBASE_REG:
2399 case OP_STORER8_MEMBASE_REG:
2400 /* we can do two things: load the immed in a register
2401 * and use an indexed load, or see if the immed can be
2402 * represented as an ad_imm + a load with a smaller offset
2403 * that fits. We just do the first for now, optimize later.
2405 if (ppc_is_imm16 (ins->inst_offset))
2407 NEW_INS (cfg, temp, OP_ICONST);
2408 temp->inst_c0 = ins->inst_offset;
2409 temp->dreg = mono_alloc_ireg (cfg);
2410 ins->sreg2 = temp->dreg;
2411 ins->opcode = map_to_reg_reg_op (ins->opcode);
2413 case OP_STORE_MEMBASE_IMM:
2414 case OP_STOREI1_MEMBASE_IMM:
2415 case OP_STOREI2_MEMBASE_IMM:
2416 case OP_STOREI4_MEMBASE_IMM:
2417 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2418 NEW_INS (cfg, temp, OP_ICONST);
2419 temp->inst_c0 = ins->inst_imm;
2420 temp->dreg = mono_alloc_ireg (cfg);
2421 ins->sreg1 = temp->dreg;
2422 ins->opcode = map_to_reg_reg_op (ins->opcode);
2424 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2427 NEW_INS (cfg, temp, OP_ICONST);
2428 temp->inst_c0 = (gulong)ins->inst_p0;
2429 temp->dreg = mono_alloc_ireg (cfg);
2430 ins->inst_basereg = temp->dreg;
2431 ins->inst_offset = 0;
2432 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2434 /* make it handle the possibly big ins->inst_offset
2435 * later optimize to use lis + load_membase
2441 bb->last_ins = last_ins;
2442 bb->max_vreg = cfg->next_vreg;
2446 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2448 long offset = cfg->arch.fp_conv_var_offset;
2450 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2451 #ifdef __mono_ppc64__
2453 ppc_fctidz (code, ppc_f0, sreg);
2458 ppc_fctiwz (code, ppc_f0, sreg);
2461 if (ppc_is_imm16 (offset + sub_offset)) {
2462 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2464 ppc_load_reg (code, dreg, offset + sub_offset, cfg->frame_reg);
2466 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2468 ppc_load (code, dreg, offset);
2469 ppc_add (code, dreg, dreg, cfg->frame_reg);
2470 ppc_stfd (code, ppc_f0, 0, dreg);
2472 ppc_load_reg (code, dreg, sub_offset, dreg);
2474 ppc_lwz (code, dreg, sub_offset, dreg);
2478 ppc_andid (code, dreg, dreg, 0xff);
2480 ppc_andid (code, dreg, dreg, 0xffff);
2481 #ifdef __mono_ppc64__
2483 ppc_clrldi (code, dreg, dreg, 32);
2487 ppc_extsb (code, dreg, dreg);
2489 ppc_extsh (code, dreg, dreg);
2490 #ifdef __mono_ppc64__
2492 ppc_extsw (code, dreg, dreg);
2500 const guchar *target;
2505 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2508 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2509 #ifdef __mono_ppc64__
2510 g_assert_not_reached ();
2512 PatchData *pdata = (PatchData*)user_data;
2513 guchar *code = data;
2514 guint32 *thunks = data;
2515 guint32 *endthunks = (guint32*)(code + bsize);
2519 int difflow, diffhigh;
2521 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2522 difflow = (char*)pdata->code - (char*)thunks;
2523 diffhigh = (char*)pdata->code - (char*)endthunks;
2524 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2527 templ = (guchar*)load;
2528 ppc_load_sequence (templ, ppc_r0, pdata->target);
2530 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2531 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2532 while (thunks < endthunks) {
2533 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2534 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2535 ppc_patch (pdata->code, (guchar*)thunks);
2538 static int num_thunks = 0;
2540 if ((num_thunks % 20) == 0)
2541 g_print ("num_thunks lookup: %d\n", num_thunks);
2544 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2545 /* found a free slot instead: emit thunk */
2546 code = (guchar*)thunks;
2547 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2548 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2549 ppc_mtctr (code, ppc_r0);
2550 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2551 mono_arch_flush_icache ((guchar*)thunks, 16);
2553 ppc_patch (pdata->code, (guchar*)thunks);
2556 static int num_thunks = 0;
2558 if ((num_thunks % 20) == 0)
2559 g_print ("num_thunks: %d\n", num_thunks);
2563 /* skip 16 bytes, the size of the thunk */
2567 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2574 handle_thunk (int absolute, guchar *code, const guchar *target) {
2575 MonoDomain *domain = mono_domain_get ();
2579 pdata.target = target;
2580 pdata.absolute = absolute;
2583 mono_domain_lock (domain);
2584 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2587 /* this uses the first available slot */
2589 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2591 mono_domain_unlock (domain);
2593 if (pdata.found != 1)
2594 g_print ("thunk failed for %p from %p\n", target, code);
2595 g_assert (pdata.found == 1);
2599 patch_ins (guint8 *code, guint32 ins)
2601 *(guint32*)code = ins;
2602 mono_arch_flush_icache (code, 4);
2606 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2608 guint32 ins = *(guint32*)code;
2609 guint32 prim = ins >> 26;
2612 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2614 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2615 gint diff = target - code;
2618 if (diff <= 33554431){
2619 ins = (18 << 26) | (diff) | (ins & 1);
2620 patch_ins (code, ins);
2624 /* diff between 0 and -33554432 */
2625 if (diff >= -33554432){
2626 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2627 patch_ins (code, ins);
2632 if ((glong)target >= 0){
2633 if ((glong)target <= 33554431){
2634 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2635 patch_ins (code, ins);
2639 if ((glong)target >= -33554432){
2640 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2641 patch_ins (code, ins);
2646 handle_thunk (TRUE, code, target);
2649 g_assert_not_reached ();
2657 guint32 li = (gulong)target;
2658 ins = (ins & 0xffff0000) | (ins & 3);
2659 ovf = li & 0xffff0000;
2660 if (ovf != 0 && ovf != 0xffff0000)
2661 g_assert_not_reached ();
2664 // FIXME: assert the top bits of li are 0
2666 gint diff = target - code;
2667 ins = (ins & 0xffff0000) | (ins & 3);
2668 ovf = diff & 0xffff0000;
2669 if (ovf != 0 && ovf != 0xffff0000)
2670 g_assert_not_reached ();
2674 patch_ins (code, ins);
2678 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2679 #ifdef __mono_ppc64__
2680 guint32 *seq = (guint32*)code;
2681 guint32 *branch_ins;
2683 /* the trampoline code will try to patch the blrl, blr, bcctr */
2684 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2686 if (ppc_opcode (seq [-3]) == 58 || ppc_opcode (seq [-3]) == 31) /* ld || mr */
2691 if (ppc_opcode (seq [5]) == 58 || ppc_opcode (seq [5]) == 31) /* ld || mr */
2692 branch_ins = seq + 8;
2694 branch_ins = seq + 6;
2697 seq = (guint32*)code;
2698 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2699 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2701 if (ppc_opcode (seq [5]) == 58) { /* ld */
2702 g_assert (ppc_opcode (seq [6]) == 58); /* ld */
2705 guint8 *buf = (guint8*)&seq [5];
2706 ppc_mr (buf, ppc_r0, ppc_r11);
2711 target = mono_get_addr_from_ftnptr ((gpointer)target);
2714 /* FIXME: make this thread safe */
2715 /* FIXME: we're assuming we're using r11 here */
2716 ppc_load_sequence (code, ppc_r11, target);
2717 mono_arch_flush_icache ((guint8*)seq, 28);
2720 /* the trampoline code will try to patch the blrl, blr, bcctr */
2721 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2724 /* this is the lis/ori/mtlr/blrl sequence */
2725 seq = (guint32*)code;
2726 g_assert ((seq [0] >> 26) == 15);
2727 g_assert ((seq [1] >> 26) == 24);
2728 g_assert ((seq [2] >> 26) == 31);
2729 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2730 /* FIXME: make this thread safe */
2731 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2732 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2733 mono_arch_flush_icache (code - 8, 8);
2736 g_assert_not_reached ();
2738 // g_print ("patched with 0x%08x\n", ins);
2742 ppc_patch (guchar *code, const guchar *target)
2744 ppc_patch_full (code, target, FALSE);
2748 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2750 switch (ins->opcode) {
2753 case OP_FCALL_MEMBASE:
2754 if (ins->dreg != ppc_f1)
2755 ppc_fmr (code, ins->dreg, ppc_f1);
2763 * emit_load_volatile_arguments:
2765 * Load volatile arguments from the stack to the original input registers.
2766 * Required before a tail call.
2769 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2771 MonoMethod *method = cfg->method;
2772 MonoMethodSignature *sig;
2776 int struct_index = 0;
2778 sig = mono_method_signature (method);
2780 /* This is the opposite of the code in emit_prolog */
2784 cinfo = calculate_sizes (sig, sig->pinvoke);
2786 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2787 ArgInfo *ainfo = &cinfo->ret;
2788 inst = cfg->vret_addr;
2789 g_assert (ppc_is_imm16 (inst->inst_offset));
2790 ppc_load_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2792 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2793 ArgInfo *ainfo = cinfo->args + i;
2794 inst = cfg->args [pos];
2796 g_assert (inst->opcode != OP_REGVAR);
2797 g_assert (ppc_is_imm16 (inst->inst_offset));
2799 switch (ainfo->regtype) {
2800 case RegTypeGeneral:
2801 switch (ainfo->size) {
2803 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2806 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2808 #ifdef __mono_ppc64__
2810 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2814 ppc_load_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2820 switch (ainfo->size) {
2822 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2825 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2828 g_assert_not_reached ();
2833 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
2834 &inst->klass->byval_arg);
2836 #ifndef __mono_ppc64__
2837 if (type->type == MONO_TYPE_I8)
2841 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
2842 ppc_load_reg (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2843 ppc_store_reg (code, ppc_r0, ainfo->offset, ainfo->reg);
2844 } else if (type->type == MONO_TYPE_I4) {
2845 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2846 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
2854 case RegTypeStructByVal: {
2865 * Darwin pinvokes needs some special handling
2866 * for 1 and 2 byte arguments
2868 if (method->signature->pinvoke)
2869 size = mono_class_native_size (inst->klass, NULL);
2870 if (size == 1 || size == 2) {
2875 for (j = 0; j < ainfo->size; ++j) {
2876 ppc_load_reg (code, ainfo->reg + j,
2877 inst->inst_offset + j * sizeof (gpointer),
2878 inst->inst_basereg);
2879 /* FIXME: shift to the right */
2886 case RegTypeStructByAddr: {
2887 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2889 g_assert (ppc_is_imm16 (addr->inst_offset));
2890 g_assert (!ainfo->offset);
2891 ppc_load_reg (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2898 g_assert_not_reached ();
2909 /* This must be kept in sync with emit_load_volatile_arguments(). */
2911 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2913 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2914 MonoMethodSignature *sig;
2919 if (ins->opcode != OP_JMP)
2922 call = (MonoCallInst*)ins;
2923 sig = mono_method_signature (cfg->method);
2924 cinfo = calculate_sizes (sig, sig->pinvoke);
2926 if (MONO_TYPE_ISSTRUCT (sig->ret))
2928 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2929 ArgInfo *ainfo = cinfo->args + i;
2931 switch (ainfo->regtype) {
2932 case RegTypeGeneral:
2941 case RegTypeStructByVal:
2942 len += 4 * ainfo->size;
2945 case RegTypeStructByAddr:
2950 g_assert_not_reached ();
2960 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2962 long size = cfg->param_area;
2964 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2965 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2970 ppc_load_reg (code, ppc_r0, 0, ppc_sp);
2971 if (ppc_is_imm16 (-size)) {
2972 ppc_store_reg_update (code, ppc_r0, -size, ppc_sp);
2974 ppc_load (code, ppc_r11, -size);
2975 ppc_store_reg_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
2982 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
2984 long size = cfg->param_area;
2986 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2987 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2992 ppc_load_reg (code, ppc_r0, 0, ppc_sp);
2993 if (ppc_is_imm16 (size)) {
2994 ppc_store_reg_update (code, ppc_r0, size, ppc_sp);
2996 ppc_load (code, ppc_r11, size);
2997 ppc_store_reg_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3003 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3006 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3008 MonoInst *ins, *next;
3011 guint8 *code = cfg->native_code + cfg->code_len;
3012 MonoInst *last_ins = NULL;
3013 guint last_offset = 0;
3017 /* we don't align basic blocks of loops on ppc */
3019 if (cfg->verbose_level > 2)
3020 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3022 cpos = bb->max_offset;
3024 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3025 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3026 //g_assert (!mono_compile_aot);
3029 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3030 /* this is not thread save, but good enough */
3031 /* fixme: howto handle overflows? */
3032 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3035 MONO_BB_FOR_EACH_INS (bb, ins) {
3036 offset = code - cfg->native_code;
3038 max_len = ins_native_length (cfg, ins);
3040 if (offset > (cfg->code_size - max_len - 16)) {
3041 cfg->code_size *= 2;
3042 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3043 code = cfg->native_code + offset;
3045 // if (ins->cil_code)
3046 // g_print ("cil code\n");
3047 mono_debug_record_line_number (cfg, ins, offset);
3049 switch (normalize_opcode (ins->opcode)) {
3050 case OP_RELAXED_NOP:
3053 case OP_DUMMY_STORE:
3054 case OP_NOT_REACHED:
3058 emit_tls_access (code, ins->dreg, ins->inst_offset);
3061 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3062 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3063 ppc_mr (code, ppc_r4, ppc_r0);
3066 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3067 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3068 ppc_mr (code, ppc_r4, ppc_r0);
3070 case OP_MEMORY_BARRIER:
3073 case OP_STOREI1_MEMBASE_REG:
3074 if (ppc_is_imm16 (ins->inst_offset)) {
3075 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3077 ppc_load (code, ppc_r0, ins->inst_offset);
3078 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3081 case OP_STOREI2_MEMBASE_REG:
3082 if (ppc_is_imm16 (ins->inst_offset)) {
3083 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3085 ppc_load (code, ppc_r0, ins->inst_offset);
3086 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3089 case OP_STORE_MEMBASE_REG:
3090 if (ppc_is_imm16 (ins->inst_offset)) {
3091 ppc_store_reg (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3093 ppc_load (code, ppc_r0, ins->inst_offset);
3094 ppc_store_reg_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3097 case OP_STOREI1_MEMINDEX:
3098 ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3100 case OP_STOREI2_MEMINDEX:
3101 ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3103 case OP_STORE_MEMINDEX:
3104 ppc_store_reg_indexed (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3107 g_assert_not_reached ();
3109 case OP_LOAD_MEMBASE:
3110 if (ppc_is_imm16 (ins->inst_offset)) {
3111 ppc_load_reg (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3113 ppc_load (code, ppc_r0, ins->inst_offset);
3114 ppc_load_reg_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3117 case OP_LOADI4_MEMBASE:
3118 #ifdef __mono_ppc64__
3119 if (ppc_is_imm16 (ins->inst_offset)) {
3120 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3122 ppc_load (code, ppc_r0, ins->inst_offset);
3123 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3127 case OP_LOADU4_MEMBASE:
3128 if (ppc_is_imm16 (ins->inst_offset)) {
3129 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3131 ppc_load (code, ppc_r0, ins->inst_offset);
3132 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3135 case OP_LOADI1_MEMBASE:
3136 case OP_LOADU1_MEMBASE:
3137 if (ppc_is_imm16 (ins->inst_offset)) {
3138 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3140 ppc_load (code, ppc_r0, ins->inst_offset);
3141 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3143 if (ins->opcode == OP_LOADI1_MEMBASE)
3144 ppc_extsb (code, ins->dreg, ins->dreg);
3146 case OP_LOADU2_MEMBASE:
3147 if (ppc_is_imm16 (ins->inst_offset)) {
3148 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3150 ppc_load (code, ppc_r0, ins->inst_offset);
3151 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3154 case OP_LOADI2_MEMBASE:
3155 if (ppc_is_imm16 (ins->inst_offset)) {
3156 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3158 ppc_load (code, ppc_r0, ins->inst_offset);
3159 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3162 case OP_LOAD_MEMINDEX:
3163 ppc_load_reg_indexed (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3165 case OP_LOADI4_MEMINDEX:
3166 case OP_LOADU4_MEMINDEX:
3167 ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3168 #ifdef __mono_ppc64__
3169 if (ins->opcode == OP_LOADI4_MEMINDEX)
3170 ppc_extsb (code, ins->dreg, ins->dreg);
3173 case OP_LOADU2_MEMINDEX:
3174 ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3176 case OP_LOADI2_MEMINDEX:
3177 ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3179 case OP_LOADU1_MEMINDEX:
3180 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3182 case OP_LOADI1_MEMINDEX:
3183 ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3184 ppc_extsb (code, ins->dreg, ins->dreg);
3186 case OP_ICONV_TO_I1:
3187 CASE_PPC64 (OP_LCONV_TO_I1)
3188 ppc_extsb (code, ins->dreg, ins->sreg1);
3190 case OP_ICONV_TO_I2:
3191 CASE_PPC64 (OP_LCONV_TO_I2)
3192 ppc_extsh (code, ins->dreg, ins->sreg1);
3194 case OP_ICONV_TO_U1:
3195 CASE_PPC64 (OP_LCONV_TO_U1)
3196 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3198 case OP_ICONV_TO_U2:
3199 CASE_PPC64 (OP_LCONV_TO_U2)
3200 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3204 CASE_PPC64 (OP_LCOMPARE)
3205 L = (sizeof (gpointer) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3207 if (next && compare_opcode_is_unsigned (next->opcode))
3208 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3210 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3212 case OP_COMPARE_IMM:
3213 case OP_ICOMPARE_IMM:
3214 CASE_PPC64 (OP_LCOMPARE_IMM)
3215 L = (sizeof (gpointer) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3217 if (next && compare_opcode_is_unsigned (next->opcode)) {
3218 if (ppc_is_uimm16 (ins->inst_imm)) {
3219 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3221 g_assert_not_reached ();
3224 if (ppc_is_imm16 (ins->inst_imm)) {
3225 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3227 g_assert_not_reached ();
3236 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3239 CASE_PPC64 (OP_LADD)
3240 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3244 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3247 if (ppc_is_imm16 (ins->inst_imm)) {
3248 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3250 g_assert_not_reached ();
3255 CASE_PPC64 (OP_LADD_IMM)
3256 if (ppc_is_imm16 (ins->inst_imm)) {
3257 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3259 g_assert_not_reached ();
3263 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3265 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3266 ppc_mfspr (code, ppc_r0, ppc_xer);
3267 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3268 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3270 case OP_IADD_OVF_UN:
3271 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3273 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3274 ppc_mfspr (code, ppc_r0, ppc_xer);
3275 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3276 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3279 CASE_PPC64 (OP_LSUB_OVF)
3280 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3282 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3283 ppc_mfspr (code, ppc_r0, ppc_xer);
3284 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3285 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3287 case OP_ISUB_OVF_UN:
3288 CASE_PPC64 (OP_LSUB_OVF_UN)
3289 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3291 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3292 ppc_mfspr (code, ppc_r0, ppc_xer);
3293 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3294 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3296 case OP_ADD_OVF_CARRY:
3297 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3299 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3300 ppc_mfspr (code, ppc_r0, ppc_xer);
3301 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3302 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3304 case OP_ADD_OVF_UN_CARRY:
3305 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3307 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3308 ppc_mfspr (code, ppc_r0, ppc_xer);
3309 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3310 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3312 case OP_SUB_OVF_CARRY:
3313 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3315 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3316 ppc_mfspr (code, ppc_r0, ppc_xer);
3317 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3318 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3320 case OP_SUB_OVF_UN_CARRY:
3321 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3323 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3324 ppc_mfspr (code, ppc_r0, ppc_xer);
3325 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3326 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3330 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3333 CASE_PPC64 (OP_LSUB)
3334 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3338 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3342 CASE_PPC64 (OP_LSUB_IMM)
3343 // we add the negated value
3344 if (ppc_is_imm16 (-ins->inst_imm))
3345 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3347 g_assert_not_reached ();
3351 g_assert (ppc_is_imm16 (ins->inst_imm));
3352 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3355 ppc_subfze (code, ins->dreg, ins->sreg1);
3358 CASE_PPC64 (OP_LAND)
3359 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3360 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3364 CASE_PPC64 (OP_LAND_IMM)
3365 if (!(ins->inst_imm & 0xffff0000)) {
3366 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3367 } else if (!(ins->inst_imm & 0xffff)) {
3368 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3370 g_assert_not_reached ();
3374 CASE_PPC64 (OP_LDIV) {
3375 guint8 *divisor_is_m1;
3376 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3378 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3379 divisor_is_m1 = code;
3380 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3381 ppc_lis (code, ppc_r0, 0x8000);
3382 #ifdef __mono_ppc64__
3383 if (ins->opcode == OP_LDIV)
3384 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3386 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3387 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3388 ppc_patch (divisor_is_m1, code);
3389 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3391 if (ins->opcode == OP_IDIV)
3392 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3393 #ifdef __mono_ppc64__
3395 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3397 ppc_mfspr (code, ppc_r0, ppc_xer);
3398 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3399 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3403 CASE_PPC64 (OP_LDIV_UN)
3404 if (ins->opcode == OP_IDIV_UN)
3405 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3406 #ifdef __mono_ppc64__
3408 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3410 ppc_mfspr (code, ppc_r0, ppc_xer);
3411 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3412 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3418 g_assert_not_reached ();
3421 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3425 CASE_PPC64 (OP_LOR_IMM)
3426 if (!(ins->inst_imm & 0xffff0000)) {
3427 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3428 } else if (!(ins->inst_imm & 0xffff)) {
3429 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3431 g_assert_not_reached ();
3435 CASE_PPC64 (OP_LXOR)
3436 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3440 CASE_PPC64 (OP_LXOR_IMM)
3441 if (!(ins->inst_imm & 0xffff0000)) {
3442 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3443 } else if (!(ins->inst_imm & 0xffff)) {
3444 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3446 g_assert_not_reached ();
3450 CASE_PPC64 (OP_LSHL)
3451 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3455 CASE_PPC64 (OP_LSHL_IMM)
3456 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3459 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3462 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3465 if (MASK_SHIFT_IMM (ins->inst_imm))
3466 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3468 ppc_mr (code, ins->dreg, ins->sreg1);
3471 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3474 CASE_PPC64 (OP_LNOT)
3475 ppc_not (code, ins->dreg, ins->sreg1);
3478 CASE_PPC64 (OP_LNEG)
3479 ppc_neg (code, ins->dreg, ins->sreg1);
3482 CASE_PPC64 (OP_LMUL)
3483 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3487 CASE_PPC64 (OP_LMUL_IMM)
3488 if (ppc_is_imm16 (ins->inst_imm)) {
3489 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3491 g_assert_not_reached ();
3495 CASE_PPC64 (OP_LMUL_OVF)
3496 /* we annot use mcrxr, since it's not implemented on some processors
3497 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3499 if (ins->opcode == OP_IMUL_OVF)
3500 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3501 #ifdef __mono_ppc64__
3503 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3505 ppc_mfspr (code, ppc_r0, ppc_xer);
3506 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3507 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3509 case OP_IMUL_OVF_UN:
3510 CASE_PPC64 (OP_LMUL_OVF_UN)
3511 /* we first multiply to get the high word and compare to 0
3512 * to set the flags, then the result is discarded and then
3513 * we multiply to get the lower * bits result
3515 if (ins->opcode == OP_IMUL_OVF_UN)
3516 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3517 #ifdef __mono_ppc64__
3519 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3521 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3522 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3523 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3526 CASE_PPC64 (OP_I8CONST)
3527 ppc_load (code, ins->dreg, ins->inst_c0);
3530 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3531 ppc_load_sequence (code, ins->dreg, 0);
3533 CASE_PPC32 (OP_ICONV_TO_I4)
3534 CASE_PPC32 (OP_ICONV_TO_U4)
3536 ppc_mr (code, ins->dreg, ins->sreg1);
3539 int saved = ins->sreg1;
3540 if (ins->sreg1 == ppc_r3) {
3541 ppc_mr (code, ppc_r0, ins->sreg1);
3544 if (ins->sreg2 != ppc_r3)
3545 ppc_mr (code, ppc_r3, ins->sreg2);
3546 if (saved != ppc_r4)
3547 ppc_mr (code, ppc_r4, saved);
3551 ppc_fmr (code, ins->dreg, ins->sreg1);
3553 case OP_FCONV_TO_R4:
3554 ppc_frsp (code, ins->dreg, ins->sreg1);
3560 * Keep in sync with mono_arch_emit_epilog
3562 g_assert (!cfg->method->save_lmf);
3564 * Note: we can use ppc_r11 here because it is dead anyway:
3565 * we're leaving the method.
3567 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3568 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3569 if (ppc_is_imm16 (ret_offset)) {
3570 ppc_load_reg (code, ppc_r0, ret_offset, cfg->frame_reg);
3572 ppc_load (code, ppc_r11, ret_offset);
3573 ppc_load_reg_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3575 ppc_mtlr (code, ppc_r0);
3578 code = emit_load_volatile_arguments (cfg, code);
3580 if (ppc_is_imm16 (cfg->stack_usage)) {
3581 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3583 ppc_load (code, ppc_r11, cfg->stack_usage);
3584 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
3586 if (!cfg->method->save_lmf) {
3587 /*for (i = 31; i >= 14; --i) {
3588 if (cfg->used_float_regs & (1 << i)) {
3589 pos += sizeof (double);
3590 ppc_lfd (code, i, -pos, cfg->frame_reg);
3594 for (i = 31; i >= 13; --i) {
3595 if (cfg->used_int_regs & (1 << i)) {
3596 pos += sizeof (gpointer);
3597 ppc_load_reg (code, i, -pos, ppc_r11);
3601 /* FIXME restore from MonoLMF: though this can't happen yet */
3603 ppc_mr (code, ppc_sp, ppc_r11);
3604 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3609 /* ensure ins->sreg1 is not NULL */
3610 ppc_load_reg (code, ppc_r0, 0, ins->sreg1);
3613 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3614 if (ppc_is_imm16 (cookie_offset)) {
3615 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3617 ppc_load (code, ppc_r0, cookie_offset);
3618 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3620 ppc_store_reg (code, ppc_r0, 0, ins->sreg1);
3629 call = (MonoCallInst*)ins;
3630 if (ins->flags & MONO_INST_HAS_METHOD)
3631 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3633 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3634 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3635 ppc_load_func (code, ppc_r0, 0);
3636 ppc_mtlr (code, ppc_r0);
3641 /* FIXME: this should be handled somewhere else in the new jit */
3642 code = emit_move_return_value (cfg, ins, code);
3648 case OP_VOIDCALL_REG:
3650 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3651 ppc_load_reg (code, ppc_r0, 0, ins->sreg1);
3652 /* FIXME: if we know that this is a method, we
3653 can omit this load */
3654 ppc_load_reg (code, ppc_r2, 8, ins->sreg1);
3655 ppc_mtlr (code, ppc_r0);
3657 ppc_mtlr (code, ins->sreg1);
3660 /* FIXME: this should be handled somewhere else in the new jit */
3661 code = emit_move_return_value (cfg, ins, code);
3663 case OP_FCALL_MEMBASE:
3664 case OP_LCALL_MEMBASE:
3665 case OP_VCALL_MEMBASE:
3666 case OP_VCALL2_MEMBASE:
3667 case OP_VOIDCALL_MEMBASE:
3668 case OP_CALL_MEMBASE:
3669 ppc_load_reg (code, ppc_r0, ins->inst_offset, ins->sreg1);
3670 ppc_mtlr (code, ppc_r0);
3672 /* FIXME: this should be handled somewhere else in the new jit */
3673 code = emit_move_return_value (cfg, ins, code);
3676 guint8 * zero_loop_jump, * zero_loop_start;
3677 /* keep alignment */
3678 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3679 int area_offset = alloca_waste;
3681 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3682 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3683 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3684 /* use ctr to store the number of words to 0 if needed */
3685 if (ins->flags & MONO_INST_INIT) {
3686 /* we zero 4 bytes at a time:
3687 * we add 7 instead of 3 so that we set the counter to
3688 * at least 1, otherwise the bdnz instruction will make
3689 * it negative and iterate billions of times.
3691 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3692 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3693 ppc_mtctr (code, ppc_r0);
3695 ppc_load_reg (code, ppc_r0, 0, ppc_sp);
3696 ppc_neg (code, ppc_r11, ppc_r11);
3697 ppc_store_reg_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3699 /* FIXME: make this loop work in 8 byte
3700 increments on PPC64 */
3701 if (ins->flags & MONO_INST_INIT) {
3702 /* adjust the dest reg by -4 so we can use stwu */
3703 /* we actually adjust -8 because we let the loop
3706 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3707 ppc_li (code, ppc_r11, 0);
3708 zero_loop_start = code;
3709 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3710 zero_loop_jump = code;
3711 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3712 ppc_patch (zero_loop_jump, zero_loop_start);
3714 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3719 ppc_mr (code, ppc_r3, ins->sreg1);
3720 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3721 (gpointer)"mono_arch_throw_exception");
3722 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3723 ppc_load_func (code, ppc_r0, 0);
3724 ppc_mtlr (code, ppc_r0);
3733 ppc_mr (code, ppc_r3, ins->sreg1);
3734 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3735 (gpointer)"mono_arch_rethrow_exception");
3736 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3737 ppc_load_func (code, ppc_r0, 0);
3738 ppc_mtlr (code, ppc_r0);
3745 case OP_START_HANDLER: {
3746 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3747 g_assert (spvar->inst_basereg != ppc_sp);
3748 code = emit_reserve_param_area (cfg, code);
3749 ppc_mflr (code, ppc_r0);
3750 if (ppc_is_imm16 (spvar->inst_offset)) {
3751 ppc_store_reg (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3753 ppc_load (code, ppc_r11, spvar->inst_offset);
3754 ppc_store_reg_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3758 case OP_ENDFILTER: {
3759 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3760 g_assert (spvar->inst_basereg != ppc_sp);
3761 code = emit_unreserve_param_area (cfg, code);
3762 if (ins->sreg1 != ppc_r3)
3763 ppc_mr (code, ppc_r3, ins->sreg1);
3764 if (ppc_is_imm16 (spvar->inst_offset)) {
3765 ppc_load_reg (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3767 ppc_load (code, ppc_r11, spvar->inst_offset);
3768 ppc_load_reg_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3770 ppc_mtlr (code, ppc_r0);
3774 case OP_ENDFINALLY: {
3775 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3776 g_assert (spvar->inst_basereg != ppc_sp);
3777 code = emit_unreserve_param_area (cfg, code);
3778 ppc_load_reg (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3779 ppc_mtlr (code, ppc_r0);
3783 case OP_CALL_HANDLER:
3784 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3788 ins->inst_c0 = code - cfg->native_code;
3791 if (ins->flags & MONO_INST_BRLABEL) {
3792 /*if (ins->inst_i0->inst_c0) {
3794 //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3796 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3800 /*if (ins->inst_target_bb->native_offset) {
3802 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3804 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3810 ppc_mtctr (code, ins->sreg1);
3811 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3815 CASE_PPC64 (OP_LCEQ)
3816 ppc_li (code, ins->dreg, 0);
3817 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3818 ppc_li (code, ins->dreg, 1);
3824 CASE_PPC64 (OP_LCLT)
3825 CASE_PPC64 (OP_LCLT_UN)
3826 ppc_li (code, ins->dreg, 1);
3827 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3828 ppc_li (code, ins->dreg, 0);
3834 CASE_PPC64 (OP_LCGT)
3835 CASE_PPC64 (OP_LCGT_UN)
3836 ppc_li (code, ins->dreg, 1);
3837 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3838 ppc_li (code, ins->dreg, 0);
3840 case OP_COND_EXC_EQ:
3841 case OP_COND_EXC_NE_UN:
3842 case OP_COND_EXC_LT:
3843 case OP_COND_EXC_LT_UN:
3844 case OP_COND_EXC_GT:
3845 case OP_COND_EXC_GT_UN:
3846 case OP_COND_EXC_GE:
3847 case OP_COND_EXC_GE_UN:
3848 case OP_COND_EXC_LE:
3849 case OP_COND_EXC_LE_UN:
3850 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3852 case OP_COND_EXC_IEQ:
3853 case OP_COND_EXC_INE_UN:
3854 case OP_COND_EXC_ILT:
3855 case OP_COND_EXC_ILT_UN:
3856 case OP_COND_EXC_IGT:
3857 case OP_COND_EXC_IGT_UN:
3858 case OP_COND_EXC_IGE:
3859 case OP_COND_EXC_IGE_UN:
3860 case OP_COND_EXC_ILE:
3861 case OP_COND_EXC_ILE_UN:
3862 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3874 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3877 /* floating point opcodes */
3880 g_assert_not_reached ();
3881 case OP_STORER8_MEMBASE_REG:
3882 if (ppc_is_imm16 (ins->inst_offset)) {
3883 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3885 ppc_load (code, ppc_r0, ins->inst_offset);
3886 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3889 case OP_LOADR8_MEMBASE:
3890 if (ppc_is_imm16 (ins->inst_offset)) {
3891 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3893 ppc_load (code, ppc_r0, ins->inst_offset);
3894 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3897 case OP_STORER4_MEMBASE_REG:
3898 ppc_frsp (code, ins->sreg1, ins->sreg1);
3899 if (ppc_is_imm16 (ins->inst_offset)) {
3900 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3902 ppc_load (code, ppc_r0, ins->inst_offset);
3903 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3906 case OP_LOADR4_MEMBASE:
3907 if (ppc_is_imm16 (ins->inst_offset)) {
3908 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3910 ppc_load (code, ppc_r0, ins->inst_offset);
3911 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3914 case OP_LOADR4_MEMINDEX:
3915 ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3917 case OP_LOADR8_MEMINDEX:
3918 ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3920 case OP_STORER4_MEMINDEX:
3921 ppc_frsp (code, ins->sreg1, ins->sreg1);
3922 ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3924 case OP_STORER8_MEMINDEX:
3925 ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3928 case CEE_CONV_R4: /* FIXME: change precision */
3930 g_assert_not_reached ();
3931 case OP_FCONV_TO_I1:
3932 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3934 case OP_FCONV_TO_U1:
3935 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3937 case OP_FCONV_TO_I2:
3938 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3940 case OP_FCONV_TO_U2:
3941 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3943 case OP_FCONV_TO_I4:
3945 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3947 case OP_FCONV_TO_U4:
3949 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3951 case OP_LCONV_TO_R_UN:
3952 g_assert_not_reached ();
3953 /* Implemented as helper calls */
3955 case OP_LCONV_TO_OVF_I4_2:
3956 case OP_LCONV_TO_OVF_I: {
3957 #ifdef __mono_ppc64__
3960 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3961 // Check if its negative
3962 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3963 negative_branch = code;
3964 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3965 // Its positive msword == 0
3966 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3967 msword_positive_branch = code;
3968 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3970 ovf_ex_target = code;
3971 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3973 ppc_patch (negative_branch, code);
3974 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3975 msword_negative_branch = code;
3976 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3977 ppc_patch (msword_negative_branch, ovf_ex_target);
3979 ppc_patch (msword_positive_branch, code);
3980 if (ins->dreg != ins->sreg1)
3981 ppc_mr (code, ins->dreg, ins->sreg1);
3986 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3989 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3992 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3995 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3998 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4001 ppc_fneg (code, ins->dreg, ins->sreg1);
4005 g_assert_not_reached ();
4008 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4011 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4012 ppc_li (code, ins->dreg, 0);
4013 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4014 ppc_li (code, ins->dreg, 1);
4017 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4018 ppc_li (code, ins->dreg, 1);
4019 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4020 ppc_li (code, ins->dreg, 0);
4023 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4024 ppc_li (code, ins->dreg, 1);
4025 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4026 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4027 ppc_li (code, ins->dreg, 0);
4030 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4031 ppc_li (code, ins->dreg, 1);
4032 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4033 ppc_li (code, ins->dreg, 0);
4036 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4037 ppc_li (code, ins->dreg, 1);
4038 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4039 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4040 ppc_li (code, ins->dreg, 0);
4043 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4046 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4049 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4050 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4053 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4054 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4057 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4058 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4061 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4062 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4065 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4066 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4069 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4072 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4073 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4076 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4079 g_assert_not_reached ();
4080 case OP_CHECK_FINITE: {
4081 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4082 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4083 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4084 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4087 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4088 #ifdef __mono_ppc64__
4089 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0f0f0f0f0fL);
4091 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4096 #ifdef __mono_ppc64__
4097 case OP_ICONV_TO_I4:
4099 ppc_extsw (code, ins->dreg, ins->sreg1);
4101 case OP_ICONV_TO_U4:
4103 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4105 case OP_ICONV_TO_R4:
4106 case OP_ICONV_TO_R8:
4107 case OP_LCONV_TO_R4:
4108 case OP_LCONV_TO_R8: {
4110 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4111 ppc_extsw (code, ppc_r0, ins->sreg1);
4116 ppc_store_reg (code, tmp, -8, ppc_r1);
4117 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4118 ppc_fcfid (code, ins->dreg, ins->dreg);
4119 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4120 ppc_frsp (code, ins->dreg, ins->dreg);
4124 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4127 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4130 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4132 ppc_mfspr (code, ppc_r0, ppc_xer);
4133 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4134 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4136 case OP_COND_EXC_OV:
4137 ppc_mfspr (code, ppc_r0, ppc_xer);
4138 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4139 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4151 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4153 case OP_FCONV_TO_I8:
4154 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4156 case OP_FCONV_TO_U8:
4157 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4159 case OP_STOREI4_MEMBASE_REG:
4160 if (ppc_is_imm16 (ins->inst_offset)) {
4161 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4163 ppc_load (code, ppc_r0, ins->inst_offset);
4164 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4167 case OP_STOREI4_MEMINDEX:
4168 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4171 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4173 case OP_ISHR_UN_IMM:
4174 if (ins->inst_imm & 0x1f)
4175 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4177 ppc_mr (code, ins->dreg, ins->sreg1);
4179 case OP_ATOMIC_ADD_NEW_I4:
4180 case OP_ATOMIC_ADD_NEW_I8: {
4181 guint8 *loop = code, *branch;
4182 g_assert (ins->inst_offset == 0);
4183 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4184 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4186 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4187 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4188 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4189 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4191 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4193 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4194 ppc_patch (branch, loop);
4195 ppc_mr (code, ins->dreg, ppc_r0);
4201 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4202 g_assert_not_reached ();
4205 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4206 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4207 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4208 g_assert_not_reached ();
4214 last_offset = offset;
4217 cfg->code_len = code - cfg->native_code;
4221 mono_arch_register_lowlevel_calls (void)
4225 #ifdef __mono_ppc64__
4226 #define patch_load_sequence(ip,val) do {\
4227 guint16 *__load = (guint16*)(ip); \
4228 __load [1] = (((guint64)(val)) >> 48) & 0xffff; \
4229 __load [3] = (((guint64)(val)) >> 32) & 0xffff; \
4230 __load [7] = (((guint64)(val)) >> 16) & 0xffff; \
4231 __load [9] = ((guint64)(val)) & 0xffff; \
4234 #define patch_load_sequence(ip,val) do {\
4235 guint16 *__lis_ori = (guint16*)(ip); \
4236 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4237 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4242 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4244 MonoJumpInfo *patch_info;
4246 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4247 unsigned char *ip = patch_info->ip.i + code;
4248 unsigned char *target;
4249 gboolean is_fd = FALSE;
4251 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4253 switch (patch_info->type) {
4254 case MONO_PATCH_INFO_IP:
4255 patch_load_sequence (ip, ip);
4257 case MONO_PATCH_INFO_METHOD_REL:
4258 g_assert_not_reached ();
4259 *((gpointer *)(ip)) = code + patch_info->data.offset;
4261 case MONO_PATCH_INFO_SWITCH: {
4262 gpointer *table = (gpointer *)patch_info->data.table->table;
4265 patch_load_sequence (ip, table);
4267 for (i = 0; i < patch_info->data.table->table_size; i++) {
4268 table [i] = (glong)patch_info->data.table->table [i] + code;
4270 /* we put into the table the absolute address, no need for ppc_patch in this case */
4273 case MONO_PATCH_INFO_METHODCONST:
4274 case MONO_PATCH_INFO_CLASS:
4275 case MONO_PATCH_INFO_IMAGE:
4276 case MONO_PATCH_INFO_FIELD:
4277 case MONO_PATCH_INFO_VTABLE:
4278 case MONO_PATCH_INFO_IID:
4279 case MONO_PATCH_INFO_SFLDA:
4280 case MONO_PATCH_INFO_LDSTR:
4281 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4282 case MONO_PATCH_INFO_LDTOKEN:
4283 /* from OP_AOTCONST : lis + ori */
4284 patch_load_sequence (ip, target);
4286 case MONO_PATCH_INFO_R4:
4287 case MONO_PATCH_INFO_R8:
4288 g_assert_not_reached ();
4289 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4291 case MONO_PATCH_INFO_EXC_NAME:
4292 g_assert_not_reached ();
4293 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4295 case MONO_PATCH_INFO_NONE:
4296 case MONO_PATCH_INFO_BB_OVF:
4297 case MONO_PATCH_INFO_EXC_OVF:
4298 /* everything is dealt with at epilog output time */
4300 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4301 case MONO_PATCH_INFO_INTERNAL_METHOD:
4302 case MONO_PATCH_INFO_ABS:
4303 case MONO_PATCH_INFO_CLASS_INIT:
4304 case MONO_PATCH_INFO_RGCTX_FETCH:
4311 ppc_patch_full (ip, target, is_fd);
4316 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4317 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4318 * the instruction offset immediate for all the registers.
4321 save_registers (guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs)
4325 for (i = 13; i <= 31; i++) {
4326 if (used_int_regs & (1 << i)) {
4327 ppc_store_reg (code, i, pos, base_reg);
4328 pos += sizeof (gulong);
4332 /* pos is the start of the MonoLMF structure */
4333 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4334 for (i = 13; i <= 31; i++) {
4335 ppc_store_reg (code, i, offset, base_reg);
4336 offset += sizeof (gulong);
4338 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4339 for (i = 14; i < 32; i++) {
4340 ppc_stfd (code, i, offset, base_reg);
4341 offset += sizeof (gdouble);
4348 * Stack frame layout:
4350 * ------------------- sp
4351 * MonoLMF structure or saved registers
4352 * -------------------
4354 * -------------------
4356 * -------------------
4357 * optional 8 bytes for tracing
4358 * -------------------
4359 * param area size is cfg->param_area
4360 * -------------------
4361 * linkage area size is PPC_STACK_PARAM_OFFSET
4362 * ------------------- sp
4366 mono_arch_emit_prolog (MonoCompile *cfg)
4368 MonoMethod *method = cfg->method;
4370 MonoMethodSignature *sig;
4372 long alloc_size, pos, max_offset;
4378 int tailcall_struct_index;
4380 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4383 sig = mono_method_signature (method);
4384 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4385 code = cfg->native_code = g_malloc (cfg->code_size);
4387 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4388 ppc_mflr (code, ppc_r0);
4389 ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4392 alloc_size = cfg->stack_offset;
4395 if (!method->save_lmf) {
4396 for (i = 31; i >= 13; --i) {
4397 if (cfg->used_int_regs & (1 << i)) {
4398 pos += sizeof (gulong);
4402 pos += sizeof (MonoLMF);
4406 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4407 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4408 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4409 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4412 cfg->stack_usage = alloc_size;
4413 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4415 if (ppc_is_imm16 (-alloc_size)) {
4416 ppc_store_reg_update (code, ppc_sp, -alloc_size, ppc_sp);
4417 code = save_registers (code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs);
4420 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4421 ppc_load (code, ppc_r0, -alloc_size);
4422 ppc_store_reg_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4423 code = save_registers (code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs);
4426 if (cfg->frame_reg != ppc_sp)
4427 ppc_mr (code, cfg->frame_reg, ppc_sp);
4429 /* store runtime generic context */
4430 if (cfg->rgctx_var) {
4431 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4432 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4434 ppc_store_reg (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4437 /* compute max_offset in order to use short forward jumps
4438 * we always do it on ppc because the immediate displacement
4439 * for jumps is too small
4442 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4444 bb->max_offset = max_offset;
4446 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4449 MONO_BB_FOR_EACH_INS (bb, ins)
4450 max_offset += ins_native_length (cfg, ins);
4453 /* load arguments allocated to register from the stack */
4456 cinfo = calculate_sizes (sig, sig->pinvoke);
4458 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4459 ArgInfo *ainfo = &cinfo->ret;
4461 inst = cfg->vret_addr;
4464 if (ppc_is_imm16 (inst->inst_offset)) {
4465 ppc_store_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4467 ppc_load (code, ppc_r11, inst->inst_offset);
4468 ppc_store_reg_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4472 tailcall_struct_index = 0;
4473 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4474 ArgInfo *ainfo = cinfo->args + i;
4475 inst = cfg->args [pos];
4477 if (cfg->verbose_level > 2)
4478 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4479 if (inst->opcode == OP_REGVAR) {
4480 if (ainfo->regtype == RegTypeGeneral)
4481 ppc_mr (code, inst->dreg, ainfo->reg);
4482 else if (ainfo->regtype == RegTypeFP)
4483 ppc_fmr (code, inst->dreg, ainfo->reg);
4484 else if (ainfo->regtype == RegTypeBase) {
4485 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4486 ppc_load_reg (code, inst->dreg, ainfo->offset, ppc_r11);
4488 g_assert_not_reached ();
4490 if (cfg->verbose_level > 2)
4491 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4493 /* the argument should be put on the stack: FIXME handle size != word */
4494 if (ainfo->regtype == RegTypeGeneral) {
4495 switch (ainfo->size) {
4497 if (ppc_is_imm16 (inst->inst_offset)) {
4498 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4500 ppc_load (code, ppc_r11, inst->inst_offset);
4501 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4505 if (ppc_is_imm16 (inst->inst_offset)) {
4506 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4508 ppc_load (code, ppc_r11, inst->inst_offset);
4509 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4512 #ifdef __mono_ppc64__
4514 if (ppc_is_imm16 (inst->inst_offset)) {
4515 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4517 ppc_load (code, ppc_r11, inst->inst_offset);
4518 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4523 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4524 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4525 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4527 ppc_load (code, ppc_r11, inst->inst_offset);
4528 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4529 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4530 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4535 if (ppc_is_imm16 (inst->inst_offset)) {
4536 ppc_store_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4538 ppc_load (code, ppc_r11, inst->inst_offset);
4539 ppc_store_reg_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4543 } else if (ainfo->regtype == RegTypeBase) {
4544 /* load the previous stack pointer in r11 */
4545 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4546 ppc_load_reg (code, ppc_r0, ainfo->offset, ppc_r11);
4547 switch (ainfo->size) {
4549 if (ppc_is_imm16 (inst->inst_offset)) {
4550 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4552 ppc_load (code, ppc_r11, inst->inst_offset);
4553 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4557 if (ppc_is_imm16 (inst->inst_offset)) {
4558 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4560 ppc_load (code, ppc_r11, inst->inst_offset);
4561 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4564 #ifdef __mono_ppc64__
4566 if (ppc_is_imm16 (inst->inst_offset)) {
4567 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4569 ppc_load (code, ppc_r11, inst->inst_offset);
4570 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4575 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4576 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4577 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4578 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4581 g_assert_not_reached ();
4586 if (ppc_is_imm16 (inst->inst_offset)) {
4587 ppc_store_reg (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4589 ppc_load (code, ppc_r11, inst->inst_offset);
4590 ppc_store_reg_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4594 } else if (ainfo->regtype == RegTypeFP) {
4595 g_assert (ppc_is_imm16 (inst->inst_offset));
4596 if (ainfo->size == 8)
4597 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4598 else if (ainfo->size == 4)
4599 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4601 g_assert_not_reached ();
4602 } else if (ainfo->regtype == RegTypeStructByVal) {
4603 int doffset = inst->inst_offset;
4607 g_assert (ppc_is_imm16 (inst->inst_offset));
4608 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4609 /* FIXME: what if there is no class? */
4610 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4611 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4612 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4615 * Darwin handles 1 and 2 byte
4616 * structs specially by
4617 * loading h/b into the arg
4618 * register. Only done for
4622 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4624 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4628 #ifdef __mono_ppc64__
4630 g_assert (cur_reg == 0);
4631 ppc_sldi (code, ppc_r0, ainfo->reg,
4632 (sizeof (gpointer) - ainfo->bytes) * 8);
4633 ppc_store_reg (code, ppc_r0, doffset, inst->inst_basereg);
4637 ppc_store_reg (code, ainfo->reg + cur_reg, doffset,
4638 inst->inst_basereg);
4641 soffset += sizeof (gpointer);
4642 doffset += sizeof (gpointer);
4644 if (ainfo->vtsize) {
4645 /* FIXME: we need to do the shifting here, too */
4648 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4649 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4650 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
4651 code = emit_memcpy (code, size - soffset,
4652 inst->inst_basereg, doffset,
4653 ppc_r11, ainfo->offset + soffset);
4655 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4656 inst->inst_basereg, doffset,
4657 ppc_r11, ainfo->offset + soffset);
4660 } else if (ainfo->regtype == RegTypeStructByAddr) {
4661 /* if it was originally a RegTypeBase */
4662 if (ainfo->offset) {
4663 /* load the previous stack pointer in r11 */
4664 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4665 ppc_load_reg (code, ppc_r11, ainfo->offset, ppc_r11);
4667 ppc_mr (code, ppc_r11, ainfo->reg);
4670 if (cfg->tailcall_valuetype_addrs) {
4671 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4673 g_assert (ppc_is_imm16 (addr->inst_offset));
4674 ppc_store_reg (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4676 tailcall_struct_index++;
4679 g_assert (ppc_is_imm16 (inst->inst_offset));
4680 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4681 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4683 g_assert_not_reached ();
4688 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4689 ppc_load (code, ppc_r3, cfg->domain);
4690 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4691 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4692 ppc_load_func (code, ppc_r0, 0);
4693 ppc_mtlr (code, ppc_r0);
4700 if (method->save_lmf) {
4701 if (lmf_pthread_key != -1) {
4702 emit_tls_access (code, ppc_r3, lmf_pthread_key);
4703 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4704 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4706 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4707 (gpointer)"mono_get_lmf_addr");
4708 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4709 ppc_load_func (code, ppc_r0, 0);
4710 ppc_mtlr (code, ppc_r0);
4716 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4717 /* lmf_offset is the offset from the previous stack pointer,
4718 * alloc_size is the total stack space allocated, so the offset
4719 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4720 * The pointer to the struct is put in ppc_r11 (new_lmf).
4721 * The callee-saved registers are already in the MonoLMF structure
4723 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4724 /* ppc_r3 is the result from mono_get_lmf_addr () */
4725 ppc_store_reg (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4726 /* new_lmf->previous_lmf = *lmf_addr */
4727 ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4728 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4729 /* *(lmf_addr) = r11 */
4730 ppc_store_reg (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4731 /* save method info */
4732 ppc_load (code, ppc_r0, method);
4733 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4734 ppc_store_reg (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4735 /* save the current IP */
4736 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4737 #ifdef __mono_ppc64__
4738 ppc_load_sequence (code, ppc_r0, (gulong)0x0101010101010101L);
4740 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
4742 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4746 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4748 cfg->code_len = code - cfg->native_code;
4749 g_assert (cfg->code_len <= cfg->code_size);
4756 mono_arch_emit_epilog (MonoCompile *cfg)
4758 MonoMethod *method = cfg->method;
4760 int max_epilog_size = 16 + 20*4;
4763 if (cfg->method->save_lmf)
4764 max_epilog_size += 128;
4766 if (mono_jit_trace_calls != NULL)
4767 max_epilog_size += 50;
4769 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4770 max_epilog_size += 50;
4772 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4773 cfg->code_size *= 2;
4774 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4775 mono_jit_stats.code_reallocs++;
4779 * Keep in sync with OP_JMP
4781 code = cfg->native_code + cfg->code_len;
4783 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4784 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4788 if (method->save_lmf) {
4790 pos += sizeof (MonoLMF);
4792 /* save the frame reg in r8 */
4793 ppc_mr (code, ppc_r8, cfg->frame_reg);
4794 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4795 /* r5 = previous_lmf */
4796 ppc_load_reg (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4798 ppc_load_reg (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4799 /* *(lmf_addr) = previous_lmf */
4800 ppc_store_reg (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4801 /* FIXME: speedup: there is no actual need to restore the registers if
4802 * we didn't actually change them (idea from Zoltan).
4805 ppc_load_multiple_regs (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
4807 /*for (i = 14; i < 32; i++) {
4808 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4810 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4811 /* use the saved copy of the frame reg in r8 */
4812 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4813 ppc_load_reg (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4814 ppc_mtlr (code, ppc_r0);
4816 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4818 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4819 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
4820 if (ppc_is_imm16 (return_offset)) {
4821 ppc_load_reg (code, ppc_r0, return_offset, cfg->frame_reg);
4823 ppc_load (code, ppc_r11, return_offset);
4824 ppc_load_reg_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
4826 ppc_mtlr (code, ppc_r0);
4828 if (ppc_is_imm16 (cfg->stack_usage)) {
4829 int offset = cfg->stack_usage;
4830 for (i = 13; i <= 31; i++) {
4831 if (cfg->used_int_regs & (1 << i))
4832 offset -= sizeof (gulong);
4834 if (cfg->frame_reg != ppc_sp)
4835 ppc_mr (code, ppc_r11, cfg->frame_reg);
4836 /* note r31 (possibly the frame register) is restored last */
4837 for (i = 13; i <= 31; i++) {
4838 if (cfg->used_int_regs & (1 << i)) {
4839 ppc_load_reg (code, i, offset, cfg->frame_reg);
4840 offset += sizeof (gulong);
4843 if (cfg->frame_reg != ppc_sp)
4844 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
4846 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
4848 ppc_load (code, ppc_r11, cfg->stack_usage);
4849 if (cfg->used_int_regs) {
4850 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
4851 for (i = 31; i >= 13; --i) {
4852 if (cfg->used_int_regs & (1 << i)) {
4853 pos += sizeof (gulong);
4854 ppc_load_reg (code, i, -pos, ppc_r11);
4857 ppc_mr (code, ppc_sp, ppc_r11);
4859 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4866 cfg->code_len = code - cfg->native_code;
4868 g_assert (cfg->code_len < cfg->code_size);
4872 /* remove once throw_exception_by_name is eliminated */
4874 exception_id_by_name (const char *name)
4876 if (strcmp (name, "IndexOutOfRangeException") == 0)
4877 return MONO_EXC_INDEX_OUT_OF_RANGE;
4878 if (strcmp (name, "OverflowException") == 0)
4879 return MONO_EXC_OVERFLOW;
4880 if (strcmp (name, "ArithmeticException") == 0)
4881 return MONO_EXC_ARITHMETIC;
4882 if (strcmp (name, "DivideByZeroException") == 0)
4883 return MONO_EXC_DIVIDE_BY_ZERO;
4884 if (strcmp (name, "InvalidCastException") == 0)
4885 return MONO_EXC_INVALID_CAST;
4886 if (strcmp (name, "NullReferenceException") == 0)
4887 return MONO_EXC_NULL_REF;
4888 if (strcmp (name, "ArrayTypeMismatchException") == 0)
4889 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4890 g_error ("Unknown intrinsic exception %s\n", name);
4895 mono_arch_emit_exceptions (MonoCompile *cfg)
4897 MonoJumpInfo *patch_info;
4900 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4901 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4902 int max_epilog_size = 50;
4904 /* count the number of exception infos */
4907 * make sure we have enough space for exceptions
4908 * 24 is the simulated call to throw_exception_by_name
4910 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4911 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4912 i = exception_id_by_name (patch_info->data.target);
4913 if (!exc_throw_found [i]) {
4914 max_epilog_size += 24;
4915 exc_throw_found [i] = TRUE;
4917 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4918 max_epilog_size += 12;
4919 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4920 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4921 i = exception_id_by_name (ovfj->data.exception);
4922 if (!exc_throw_found [i]) {
4923 max_epilog_size += 24;
4924 exc_throw_found [i] = TRUE;
4926 max_epilog_size += 8;
4930 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4931 cfg->code_size *= 2;
4932 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4933 mono_jit_stats.code_reallocs++;
4936 code = cfg->native_code + cfg->code_len;
4938 /* add code to raise exceptions */
4939 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4940 switch (patch_info->type) {
4941 case MONO_PATCH_INFO_BB_OVF: {
4942 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4943 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4944 /* patch the initial jump */
4945 ppc_patch (ip, code);
4946 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4948 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4949 /* jump back to the true target */
4951 ip = ovfj->data.bb->native_offset + cfg->native_code;
4952 ppc_patch (code - 4, ip);
4955 case MONO_PATCH_INFO_EXC_OVF: {
4956 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4957 MonoJumpInfo *newji;
4958 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4959 unsigned char *bcl = code;
4960 /* patch the initial jump: we arrived here with a call */
4961 ppc_patch (ip, code);
4962 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4964 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4965 /* patch the conditional jump to the right handler */
4966 /* make it processed next */
4967 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4968 newji->type = MONO_PATCH_INFO_EXC;
4969 newji->ip.i = bcl - cfg->native_code;
4970 newji->data.target = ovfj->data.exception;
4971 newji->next = patch_info->next;
4972 patch_info->next = newji;
4975 case MONO_PATCH_INFO_EXC: {
4976 unsigned char *ip = patch_info->ip.i + cfg->native_code;
4977 i = exception_id_by_name (patch_info->data.target);
4978 if (exc_throw_pos [i]) {
4979 ppc_patch (ip, exc_throw_pos [i]);
4980 patch_info->type = MONO_PATCH_INFO_NONE;
4983 exc_throw_pos [i] = code;
4985 ppc_patch (ip, code);
4986 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4987 ppc_load (code, ppc_r3, patch_info->data.target);
4988 /* we got here from a conditional call, so the calling ip is set in lr already */
4989 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4990 patch_info->data.name = "mono_arch_throw_exception_by_name";
4991 patch_info->ip.i = code - cfg->native_code;
4992 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4993 ppc_load_func (code, ppc_r0, 0);
4994 ppc_mtctr (code, ppc_r0);
4995 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5007 cfg->code_len = code - cfg->native_code;
5009 g_assert (cfg->code_len < cfg->code_size);
5014 try_offset_access (void *value, guint32 idx)
5016 register void* me __asm__ ("r2");
5017 void ***p = (void***)((char*)me + 284);
5018 int idx1 = idx / 32;
5019 int idx2 = idx % 32;
5022 if (value != p[idx1][idx2])
5028 setup_tls_access (void)
5030 #ifdef __mono_ppc64__
5031 /* FIXME: implement */
5032 tls_mode = TLS_MODE_FAILED;
5036 guint32 *ins, *code;
5037 guint32 cmplwi_1023, li_0x48, blr_ins;
5038 if (tls_mode == TLS_MODE_FAILED)
5041 if (g_getenv ("MONO_NO_TLS")) {
5042 tls_mode = TLS_MODE_FAILED;
5046 if (tls_mode == TLS_MODE_DETECT) {
5047 ins = (guint32*)pthread_getspecific;
5048 /* uncond branch to the real method */
5049 if ((*ins >> 26) == 18) {
5051 val = (*ins & ~3) << 6;
5055 ins = (guint32*)val;
5057 ins = (guint32*) ((char*)ins + val);
5060 code = &cmplwi_1023;
5061 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5063 ppc_li (code, ppc_r4, 0x48);
5066 if (*ins == cmplwi_1023) {
5067 int found_lwz_284 = 0;
5068 for (ptk = 0; ptk < 20; ++ptk) {
5070 if (!*ins || *ins == blr_ins)
5072 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5077 if (!found_lwz_284) {
5078 tls_mode = TLS_MODE_FAILED;
5081 tls_mode = TLS_MODE_LTHREADS;
5082 } else if (*ins == li_0x48) {
5084 /* uncond branch to the real method */
5085 if ((*ins >> 26) == 18) {
5087 val = (*ins & ~3) << 6;
5091 ins = (guint32*)val;
5093 ins = (guint32*) ((char*)ins + val);
5095 code = (guint32*)&val;
5096 ppc_li (code, ppc_r0, 0x7FF2);
5097 if (ins [1] == val) {
5098 /* Darwin on G4, implement */
5099 tls_mode = TLS_MODE_FAILED;
5102 code = (guint32*)&val;
5103 ppc_mfspr (code, ppc_r3, 104);
5104 if (ins [1] != val) {
5105 tls_mode = TLS_MODE_FAILED;
5108 tls_mode = TLS_MODE_DARWIN_G5;
5111 tls_mode = TLS_MODE_FAILED;
5115 tls_mode = TLS_MODE_FAILED;
5119 if (monodomain_key == -1) {
5120 ptk = mono_domain_get_tls_key ();
5122 ptk = mono_pthread_key_for_tls (ptk);
5124 monodomain_key = ptk;
5128 if (lmf_pthread_key == -1) {
5129 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5131 /*g_print ("MonoLMF at: %d\n", ptk);*/
5132 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5133 init_tls_failed = 1;
5136 lmf_pthread_key = ptk;
5139 if (monothread_key == -1) {
5140 ptk = mono_thread_get_tls_key ();
5142 ptk = mono_pthread_key_for_tls (ptk);
5144 monothread_key = ptk;
5145 /*g_print ("thread inited: %d\n", ptk);*/
5148 /*g_print ("thread not inited yet %d\n", ptk);*/
5155 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5157 setup_tls_access ();
5161 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5165 #ifdef MONO_ARCH_HAVE_IMT
5167 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5169 #define LOADSTORE_SIZE 4
5170 #define JUMP_IMM_SIZE 12
5171 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5172 #define ENABLE_WRONG_METHOD_CHECK 0
5175 * LOCKING: called with the domain lock held
5178 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5179 gpointer fail_tramp)
5183 guint8 *code, *start;
5185 for (i = 0; i < count; ++i) {
5186 MonoIMTCheckItem *item = imt_entries [i];
5187 if (item->is_equals) {
5188 if (item->check_target_idx) {
5189 if (!item->compare_done)
5190 item->chunk_size += CMP_SIZE;
5192 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5194 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5197 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5199 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5200 #if ENABLE_WRONG_METHOD_CHECK
5201 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5206 item->chunk_size += CMP_SIZE + BR_SIZE;
5207 imt_entries [item->check_target_idx]->compare_done = TRUE;
5209 size += item->chunk_size;
5212 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5214 /* the initial load of the vtable address */
5215 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5216 code = mono_code_manager_reserve (domain->code_mp, size);
5221 * We need to save and restore r11 because it might be
5222 * used by the caller as the vtable register, so
5223 * clobbering it will trip up the magic trampoline.
5225 * FIXME: Get rid of this by making sure that r11 is
5226 * not used as the vtable register in interface calls.
5228 ppc_store_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5229 ppc_load (code, ppc_r11, (gulong)(& (vtable->vtable [0])));
5231 for (i = 0; i < count; ++i) {
5232 MonoIMTCheckItem *item = imt_entries [i];
5233 item->code_target = code;
5234 if (item->is_equals) {
5235 if (item->check_target_idx) {
5236 if (!item->compare_done) {
5237 ppc_load (code, ppc_r0, (gulong)item->key);
5238 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5240 item->jmp_code = code;
5241 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5243 ppc_load (code, ppc_r0, item->value.target_code);
5245 ppc_load_reg (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5246 ppc_load_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5248 ppc_mtctr (code, ppc_r0);
5249 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5252 ppc_load (code, ppc_r0, (gulong)item->key);
5253 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5254 item->jmp_code = code;
5255 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5256 ppc_load (code, ppc_r0, item->value.target_code);
5257 ppc_mtctr (code, ppc_r0);
5258 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5259 ppc_patch (item->jmp_code, code);
5260 ppc_load (code, ppc_r0, fail_tramp);
5261 ppc_mtctr (code, ppc_r0);
5262 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5263 item->jmp_code = NULL;
5265 /* enable the commented code to assert on wrong method */
5266 #if ENABLE_WRONG_METHOD_CHECK
5267 ppc_load (code, ppc_r0, (guint32)item->key);
5268 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5269 item->jmp_code = code;
5270 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5272 ppc_load_reg (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5273 ppc_load_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5274 ppc_mtctr (code, ppc_r0);
5275 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5276 #if ENABLE_WRONG_METHOD_CHECK
5277 ppc_patch (item->jmp_code, code);
5279 item->jmp_code = NULL;
5284 ppc_load (code, ppc_r0, (gulong)item->key);
5285 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5286 item->jmp_code = code;
5287 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5290 /* patch the branches to get to the target items */
5291 for (i = 0; i < count; ++i) {
5292 MonoIMTCheckItem *item = imt_entries [i];
5293 if (item->jmp_code) {
5294 if (item->check_target_idx) {
5295 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5301 mono_stats.imt_thunks_size += code - start;
5302 g_assert (code - start <= size);
5303 mono_arch_flush_icache (start, size);
5308 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5310 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5314 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5316 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5321 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
5323 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5327 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5334 mono_arch_print_tree (MonoInst *tree, int arity)
5339 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5343 setup_tls_access ();
5344 if (monodomain_key == -1)
5347 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5348 ins->inst_offset = monodomain_key;
5353 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5357 setup_tls_access ();
5358 if (monothread_key == -1)
5361 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5362 ins->inst_offset = monothread_key;
5367 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5370 return MONO_CONTEXT_GET_SP (ctx);
5372 g_assert (reg >= ppc_r13);
5374 return (gpointer)ctx->regs [reg - ppc_r13];