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>
17 #include <mono/utils/mono-proclib.h>
20 #ifdef TARGET_POWERPC64
21 #include "cpu-ppc64.h"
28 #include <sys/sysctl.h>
34 #define FORCE_INDIR_CALL 1
45 /* cpu_hw_caps contains the flags defined below */
46 static int cpu_hw_caps = 0;
47 static int cachelinesize = 0;
48 static int cachelineinc = 0;
50 PPC_ICACHE_SNOOP = 1 << 0,
51 PPC_MULTIPLE_LS_UNITS = 1 << 1,
52 PPC_SMP_CAPABLE = 1 << 2,
55 PPC_MOVE_FPR_GPR = 1 << 5,
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
62 static CRITICAL_SECTION mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
68 static int monodomain_key = -1;
71 offsets_from_pthread_key (guint32 key, int *offset2)
75 *offset2 = idx2 * sizeof (gpointer);
76 return 284 + idx1 * sizeof (gpointer);
79 #define emit_linuxthreads_tls(code,dreg,key) do {\
81 off1 = offsets_from_pthread_key ((key), &off2); \
82 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
83 ppc_ldptr ((code), (dreg), off2, (dreg)); \
86 #define emit_darwing5_tls(code,dreg,key) do {\
87 int off1 = 0x48 + key * sizeof (gpointer); \
88 ppc_mfspr ((code), (dreg), 104); \
89 ppc_ldptr ((code), (dreg), off1, (dreg)); \
92 /* FIXME: ensure the sc call preserves all but r3 */
93 #define emit_darwing4_tls(code,dreg,key) do {\
94 int off1 = 0x48 + key * sizeof (gpointer); \
95 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
96 ppc_li ((code), ppc_r0, 0x7FF2); \
98 ppc_lwz ((code), (dreg), off1, ppc_r3); \
99 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
102 #ifdef PPC_THREAD_PTR_REG
103 #define emit_nptl_tls(code,dreg,key) do { \
105 int off2 = key >> 15; \
106 if ((off2 == 0) || (off2 == -1)) { \
107 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
109 int off3 = (off2 + 1) > 1; \
110 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
111 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
115 #define emit_nptl_tls(code,dreg,key) do { \
116 g_assert_not_reached (); \
120 #define emit_tls_access(code,dreg,key) do { \
121 switch (tls_mode) { \
122 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
123 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
124 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
125 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
126 default: g_assert_not_reached (); \
130 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
132 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
133 inst->type = STACK_R8; \
135 inst->inst_p0 = (void*)(addr); \
136 mono_bblock_add_inst (cfg->cbb, inst); \
140 mono_arch_regname (int reg) {
141 static const char rnames[][4] = {
142 "r0", "sp", "r2", "r3", "r4",
143 "r5", "r6", "r7", "r8", "r9",
144 "r10", "r11", "r12", "r13", "r14",
145 "r15", "r16", "r17", "r18", "r19",
146 "r20", "r21", "r22", "r23", "r24",
147 "r25", "r26", "r27", "r28", "r29",
150 if (reg >= 0 && reg < 32)
156 mono_arch_fregname (int reg) {
157 static const char rnames[][4] = {
158 "f0", "f1", "f2", "f3", "f4",
159 "f5", "f6", "f7", "f8", "f9",
160 "f10", "f11", "f12", "f13", "f14",
161 "f15", "f16", "f17", "f18", "f19",
162 "f20", "f21", "f22", "f23", "f24",
163 "f25", "f26", "f27", "f28", "f29",
166 if (reg >= 0 && reg < 32)
171 /* this function overwrites r0, r11, r12 */
173 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
175 /* unrolled, use the counter in big */
176 if (size > sizeof (gpointer) * 5) {
177 long shifted = size >> MONO_PPC_32_64_CASE (2, 3);
178 guint8 *copy_loop_start, *copy_loop_jump;
180 ppc_load (code, ppc_r0, shifted);
181 ppc_mtctr (code, ppc_r0);
182 g_assert (sreg == ppc_r11);
183 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
184 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
185 copy_loop_start = code;
186 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
187 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
188 copy_loop_jump = code;
189 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
190 ppc_patch (copy_loop_jump, copy_loop_start);
191 size -= shifted * sizeof (gpointer);
192 doffset = soffset = 0;
195 #ifdef __mono_ppc64__
196 /* the hardware has multiple load/store units and the move is long
197 enough to use more then one regiester, then use load/load/store/store
198 to execute 2 instructions per cycle. */
199 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
201 ppc_ldptr (code, ppc_r0, soffset, sreg);
202 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
203 ppc_stptr (code, ppc_r0, doffset, dreg);
204 ppc_stptr (code, ppc_r12, doffset+8, dreg);
211 ppc_ldptr (code, ppc_r0, soffset, sreg);
212 ppc_stptr (code, ppc_r0, doffset, dreg);
218 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
220 ppc_lwz (code, ppc_r0, soffset, sreg);
221 ppc_lwz (code, ppc_r12, soffset+4, sreg);
222 ppc_stw (code, ppc_r0, doffset, dreg);
223 ppc_stw (code, ppc_r12, doffset+4, dreg);
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_stw (code, ppc_r0, doffset, dreg);
238 ppc_lhz (code, ppc_r0, soffset, sreg);
239 ppc_sth (code, ppc_r0, doffset, dreg);
245 ppc_lbz (code, ppc_r0, soffset, sreg);
246 ppc_stb (code, ppc_r0, doffset, dreg);
255 * mono_arch_get_argument_info:
256 * @csig: a method signature
257 * @param_count: the number of parameters to consider
258 * @arg_info: an array to store the result infos
260 * Gathers information on parameters such as size, alignment and
261 * padding. arg_info should be large enought to hold param_count + 1 entries.
263 * Returns the size of the activation frame.
266 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
268 #ifdef __mono_ppc64__
272 int k, frame_size = 0;
273 int size, align, pad;
276 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
277 frame_size += sizeof (gpointer);
281 arg_info [0].offset = offset;
284 frame_size += sizeof (gpointer);
288 arg_info [0].size = frame_size;
290 for (k = 0; k < param_count; k++) {
293 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
295 size = mini_type_stack_size (NULL, csig->params [k], &align);
297 /* ignore alignment for now */
300 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
301 arg_info [k].pad = pad;
303 arg_info [k + 1].pad = 0;
304 arg_info [k + 1].size = size;
306 arg_info [k + 1].offset = offset;
310 align = MONO_ARCH_FRAME_ALIGNMENT;
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
318 #ifdef __mono_ppc64__
320 is_load_sequence (guint32 *seq)
322 return ppc_opcode (seq [0]) == 15 && /* lis */
323 ppc_opcode (seq [1]) == 24 && /* ori */
324 ppc_opcode (seq [2]) == 30 && /* sldi */
325 ppc_opcode (seq [3]) == 25 && /* oris */
326 ppc_opcode (seq [4]) == 24; /* ori */
329 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
330 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
333 /* code must point to the blrl */
335 mono_ppc_is_direct_call_sequence (guint32 *code)
337 #ifdef __mono_ppc64__
338 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
340 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
341 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
342 if (ppc_opcode (code [-2]) == 58 && ppc_opcode (code [-3]) == 58) { /* ld/ld */
343 if (!is_load_sequence (&code [-8]))
345 /* one of the loads must be "ld r2,8(rX)" */
346 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == 8) ||
347 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == 8);
349 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
350 return is_load_sequence (&code [-8]);
352 return is_load_sequence (&code [-6]);
356 g_assert(*code == 0x4e800021);
358 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
359 return ppc_opcode (code [-1]) == 31 &&
360 ppc_opcode (code [-2]) == 24 &&
361 ppc_opcode (code [-3]) == 15;
366 mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
370 guint32* code = (guint32*)code_ptr;
374 /* This is the 'blrl' instruction */
377 /* Sanity check: instruction must be 'blrl' */
378 if (*code != 0x4e800021)
381 if (mono_ppc_is_direct_call_sequence (code))
384 /* FIXME: more sanity checks here */
385 /* OK, we're now at the 'blrl' instruction. Now walk backwards
386 till we get to a 'mtlr rA' */
388 if((*code & 0x7c0803a6) == 0x7c0803a6) {
390 /* Here we are: we reached the 'mtlr rA'.
391 Extract the register from the instruction */
392 reg = (*code & 0x03e00000) >> 21;
394 /* ok, this is a lwz reg, offset (vtreg)
395 * it is emitted with:
396 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
398 soff = (*code & 0xffff);
400 reg = (*code >> 16) & 0x1f;
401 g_assert (reg != ppc_r1);
402 /*g_print ("patching reg is %d\n", reg);*/
404 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gpointer)));
405 /* saved in the MonoLMF structure */
406 o = (gpointer)lmf->iregs [reg - 13];
408 o = (gpointer)regs [reg];
413 *displacement = offset;
417 #define MAX_ARCH_DELEGATE_PARAMS 7
420 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
422 guint8 *code, *start;
425 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
427 start = code = mono_global_codeman_reserve (size);
429 code = mono_ppc_create_pre_code_ftnptr (code);
431 /* Replace the this argument with the target */
432 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
433 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
434 /* it's a function descriptor */
435 ppc_ldx (code, ppc_r0, 0, ppc_r0);
437 ppc_mtctr (code, ppc_r0);
438 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
439 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
441 g_assert ((code - start) <= size);
443 mono_arch_flush_icache (start, size);
447 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
448 start = code = mono_global_codeman_reserve (size);
450 code = mono_ppc_create_pre_code_ftnptr (code);
452 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
453 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
454 /* it's a function descriptor */
455 ppc_ldx (code, ppc_r0, 0, ppc_r0);
457 ppc_mtctr (code, ppc_r0);
458 /* slide down the arguments */
459 for (i = 0; i < param_count; ++i) {
460 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
462 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
464 g_assert ((code - start) <= size);
466 mono_arch_flush_icache (start, size);
470 *code_len = code - start;
476 mono_arch_get_delegate_invoke_impls (void)
483 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
484 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len));
486 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
487 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
488 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len));
495 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
497 guint8 *code, *start;
499 /* FIXME: Support more cases */
500 if (MONO_TYPE_ISSTRUCT (sig->ret))
504 static guint8* cached = NULL;
510 start = mono_aot_get_named_code ("delegate_invoke_impl_has_target");
512 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
514 mono_memory_barrier ();
518 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
521 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
523 for (i = 0; i < sig->param_count; ++i)
524 if (!mono_is_regsize_var (sig->params [i]))
528 code = cache [sig->param_count];
533 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
534 start = mono_aot_get_named_code (name);
537 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
540 mono_memory_barrier ();
542 cache [sig->param_count] = start;
548 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
550 /* FIXME: handle returning a struct */
551 if (MONO_TYPE_ISSTRUCT (sig->ret))
552 return (gpointer)regs [ppc_r4];
553 return (gpointer)regs [ppc_r3];
561 #ifdef USE_ENVIRON_HACK
563 linux_find_auxv (int *count)
567 char **result = __environ;
568 /* Scan over the env vector looking for the ending NULL */
569 for (; *result != NULL; ++result) {
571 /* Bump the pointer one more step, which should be the auxv. */
573 vec = (AuxVec *)result;
574 if (vec->type != 22 /*AT_IGNOREPPC*/) {
578 while (vec->type != 0 /*AT_NULL*/) {
583 return (AuxVec *)result;
587 #define MAX_AUX_ENTRIES 128
589 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
590 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
592 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
594 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
595 #define ISA_64 0x40000000
597 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
598 #define ISA_MOVE_FPR_GPR 0x00000200
600 * Initialize the cpu to execute managed code.
603 mono_arch_cpu_init (void)
609 mib [1] = HW_CACHELINE;
610 len = sizeof (cachelinesize);
611 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
615 cachelineinc = cachelinesize;
617 #elif defined(__linux__)
618 AuxVec vec [MAX_AUX_ENTRIES];
619 int i, vec_entries = 0;
620 /* sadly this will work only with 2.6 kernels... */
621 FILE* f = fopen ("/proc/self/auxv", "rb");
623 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
625 #ifdef USE_ENVIRON_HACK
627 AuxVec *evec = linux_find_auxv (&vec_entries);
629 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
632 for (i = 0; i < vec_entries; i++) {
633 int type = vec [i].type;
634 if (type == 19) { /* AT_DCACHEBSIZE */
635 cachelinesize = vec [i].value;
637 } else if (type == 16) { /* AT_HWCAP */
638 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
639 cpu_hw_caps |= PPC_ICACHE_SNOOP;
640 if (vec [i].value & ISA_2X)
641 cpu_hw_caps |= PPC_ISA_2X;
642 if (vec [i].value & ISA_64)
643 cpu_hw_caps |= PPC_ISA_64;
644 if (vec [i].value & ISA_MOVE_FPR_GPR)
645 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
647 } else if (type == 15) { /* AT_PLATFORM */
648 const char *arch = (char*)vec [i].value;
649 if (strcmp (arch, "ppc970") == 0 ||
650 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
651 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
652 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
656 #elif defined(G_COMPILER_CODEWARRIOR)
660 #warning Need a way to get cache line size
665 cachelineinc = cachelinesize;
667 if (mono_cpu_count () > 1)
668 cpu_hw_caps |= PPC_SMP_CAPABLE;
672 * Initialize architecture specific code.
675 mono_arch_init (void)
677 InitializeCriticalSection (&mini_arch_mutex);
681 * Cleanup architecture specific code.
684 mono_arch_cleanup (void)
686 DeleteCriticalSection (&mini_arch_mutex);
690 * This function returns the optimizations supported on this cpu.
693 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
697 /* no ppc-specific optimizations yet */
702 #ifdef __mono_ppc64__
703 #define CASE_PPC32(c)
704 #define CASE_PPC64(c) case c:
706 #define CASE_PPC32(c) case c:
707 #define CASE_PPC64(c)
711 is_regsize_var (MonoType *t) {
714 t = mini_type_get_underlying_type (NULL, t);
718 CASE_PPC64 (MONO_TYPE_I8)
719 CASE_PPC64 (MONO_TYPE_U8)
723 case MONO_TYPE_FNPTR:
725 case MONO_TYPE_OBJECT:
726 case MONO_TYPE_STRING:
727 case MONO_TYPE_CLASS:
728 case MONO_TYPE_SZARRAY:
729 case MONO_TYPE_ARRAY:
731 case MONO_TYPE_GENERICINST:
732 if (!mono_type_generic_inst_is_valuetype (t))
735 case MONO_TYPE_VALUETYPE:
742 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
747 for (i = 0; i < cfg->num_varinfo; i++) {
748 MonoInst *ins = cfg->varinfo [i];
749 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
752 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
755 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
758 /* we can only allocate 32 bit values */
759 if (is_regsize_var (ins->inst_vtype)) {
760 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
761 g_assert (i == vmv->idx);
762 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
770 mono_arch_get_global_int_regs (MonoCompile *cfg)
774 if (cfg->frame_reg != ppc_sp)
776 /* ppc_r13 is used by the system on PPC EABI */
777 for (i = 14; i < top; ++i)
778 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
784 * mono_arch_regalloc_cost:
786 * Return the cost, in number of memory references, of the action of
787 * allocating the variable VMV into a register during global register
791 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
798 mono_arch_flush_icache (guint8 *code, gint size)
800 #ifdef MONO_CROSS_COMPILE
803 guint8 *endp, *start;
807 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
808 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
809 #if defined(G_COMPILER_CODEWARRIOR)
810 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
811 for (p = start; p < endp; p += cachelineinc) {
815 for (p = start; p < endp; p += cachelineinc) {
821 for (p = start; p < endp; p += cachelineinc) {
832 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
833 * The sync is required to insure that the store queue is completely empty.
834 * While the icbi performs no cache operations, icbi/isync is required to
835 * kill local prefetch.
837 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
839 asm ("icbi 0,%0;" : : "r"(code) : "memory");
843 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
844 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
845 for (p = start; p < endp; p += cachelineinc) {
846 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
849 for (p = start; p < endp; p += cachelineinc) {
850 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
855 for (p = start; p < endp; p += cachelineinc) {
856 /* for ISA2.0+ implementations we should not need any extra sync between the
857 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
858 * So I am not sure which chip had this problem but its not an issue on
859 * of the ISA V2 chips.
861 if (cpu_hw_caps & PPC_ISA_2X)
862 asm ("icbi 0,%0;" : : "r"(p) : "memory");
864 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
866 if (!(cpu_hw_caps & PPC_ISA_2X))
874 mono_arch_flush_register_windows (void)
879 #define ALWAYS_ON_STACK(s) s
880 #define FP_ALSO_IN_REG(s) s
882 #ifdef __mono_ppc64__
883 #define ALWAYS_ON_STACK(s) s
884 #define FP_ALSO_IN_REG(s) s
886 #define ALWAYS_ON_STACK(s)
887 #define FP_ALSO_IN_REG(s)
889 #define ALIGN_DOUBLES
902 guint32 vtsize; /* in param area */
904 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
905 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
906 guint8 bytes : 4; /* size in bytes - only valid for
907 RegTypeStructByVal if the struct fits
908 in one word, otherwise it's 0*/
923 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
925 #ifdef __mono_ppc64__
930 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
931 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
932 ainfo->reg = ppc_sp; /* in the caller */
933 ainfo->regtype = RegTypeBase;
934 *stack_size += sizeof (gpointer);
936 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
940 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
942 //*stack_size += (*stack_size % 8);
944 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
945 ainfo->reg = ppc_sp; /* in the caller */
946 ainfo->regtype = RegTypeBase;
953 ALWAYS_ON_STACK (*stack_size += 8);
961 #if defined(__APPLE__) || defined(__mono_ppc64__)
963 has_only_a_r48_field (MonoClass *klass)
967 gboolean have_field = FALSE;
969 while ((f = mono_class_get_fields (klass, &iter))) {
970 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
973 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
984 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
987 int n = sig->hasthis + sig->param_count;
989 guint32 stack_size = 0;
990 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
992 fr = PPC_FIRST_FPARG_REG;
993 gr = PPC_FIRST_ARG_REG;
995 /* FIXME: handle returning a struct */
996 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
997 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
998 cinfo->struct_ret = PPC_FIRST_ARG_REG;
1003 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1006 DEBUG(printf("params: %d\n", sig->param_count));
1007 for (i = 0; i < sig->param_count; ++i) {
1008 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1009 /* Prevent implicit arguments and sig_cookie from
1010 being passed in registers */
1011 gr = PPC_LAST_ARG_REG + 1;
1012 /* FIXME: don't we have to set fr, too? */
1013 /* Emit the signature cookie just before the implicit arguments */
1014 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1016 DEBUG(printf("param %d: ", i));
1017 if (sig->params [i]->byref) {
1018 DEBUG(printf("byref\n"));
1019 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1023 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
1024 switch (simpletype) {
1025 case MONO_TYPE_BOOLEAN:
1028 cinfo->args [n].size = 1;
1029 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1032 case MONO_TYPE_CHAR:
1035 cinfo->args [n].size = 2;
1036 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1041 cinfo->args [n].size = 4;
1042 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1048 case MONO_TYPE_FNPTR:
1049 case MONO_TYPE_CLASS:
1050 case MONO_TYPE_OBJECT:
1051 case MONO_TYPE_STRING:
1052 case MONO_TYPE_SZARRAY:
1053 case MONO_TYPE_ARRAY:
1054 cinfo->args [n].size = sizeof (gpointer);
1055 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1058 case MONO_TYPE_GENERICINST:
1059 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
1060 cinfo->args [n].size = sizeof (gpointer);
1061 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1066 case MONO_TYPE_VALUETYPE: {
1069 klass = mono_class_from_mono_type (sig->params [i]);
1071 size = mono_class_native_size (klass, NULL);
1073 size = mono_class_value_size (klass, NULL);
1074 #if defined(__APPLE__) || defined(__mono_ppc64__)
1075 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1076 cinfo->args [n].size = size;
1078 /* It was 7, now it is 8 in LinuxPPC */
1079 if (fr <= PPC_LAST_FPARG_REG) {
1080 cinfo->args [n].regtype = RegTypeFP;
1081 cinfo->args [n].reg = fr;
1083 FP_ALSO_IN_REG (gr ++);
1085 FP_ALSO_IN_REG (gr ++);
1086 ALWAYS_ON_STACK (stack_size += size);
1088 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1089 cinfo->args [n].regtype = RegTypeBase;
1090 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1097 DEBUG(printf ("load %d bytes struct\n",
1098 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1099 #if PPC_PASS_STRUCTS_BY_VALUE
1101 int align_size = size;
1103 int rest = PPC_LAST_ARG_REG - gr + 1;
1105 align_size += (sizeof (gpointer) - 1);
1106 align_size &= ~(sizeof (gpointer) - 1);
1107 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1108 n_in_regs = MIN (rest, nwords);
1109 cinfo->args [n].regtype = RegTypeStructByVal;
1110 if (gr > PPC_LAST_ARG_REG
1112 /* FIXME: check this */
1113 || (size >= 3 && size % 4 != 0)
1116 cinfo->args [n].size = 0;
1117 cinfo->args [n].vtsize = nwords;
1119 cinfo->args [n].size = n_in_regs;
1120 cinfo->args [n].vtsize = nwords - n_in_regs;
1121 cinfo->args [n].reg = gr;
1123 #ifdef __mono_ppc64__
1124 if (nwords == 1 && is_pinvoke)
1125 cinfo->args [n].bytes = size;
1128 cinfo->args [n].bytes = 0;
1130 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1131 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1132 stack_size += nwords * sizeof (gpointer);
1135 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1136 cinfo->args [n].regtype = RegTypeStructByAddr;
1137 cinfo->args [n].vtsize = size;
1142 case MONO_TYPE_TYPEDBYREF: {
1143 int size = sizeof (MonoTypedRef);
1144 /* keep in sync or merge with the valuetype case */
1145 #if PPC_PASS_STRUCTS_BY_VALUE
1147 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1148 cinfo->args [n].regtype = RegTypeStructByVal;
1149 if (gr <= PPC_LAST_ARG_REG) {
1150 int rest = PPC_LAST_ARG_REG - gr + 1;
1151 int n_in_regs = rest >= nwords? nwords: rest;
1152 cinfo->args [n].size = n_in_regs;
1153 cinfo->args [n].vtsize = nwords - n_in_regs;
1154 cinfo->args [n].reg = gr;
1157 cinfo->args [n].size = 0;
1158 cinfo->args [n].vtsize = nwords;
1160 #ifdef __mono_ppc64__
1161 if (nwords == 1 && is_pinvoke)
1162 cinfo->args [n].bytes = size;
1165 cinfo->args [n].bytes = 0;
1166 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1167 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1168 stack_size += nwords * sizeof (gpointer);
1171 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1172 cinfo->args [n].regtype = RegTypeStructByAddr;
1173 cinfo->args [n].vtsize = size;
1180 cinfo->args [n].size = 8;
1181 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1185 cinfo->args [n].size = 4;
1187 /* It was 7, now it is 8 in LinuxPPC */
1188 if (fr <= PPC_LAST_FPARG_REG) {
1189 cinfo->args [n].regtype = RegTypeFP;
1190 cinfo->args [n].reg = fr;
1192 FP_ALSO_IN_REG (gr ++);
1193 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1195 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1196 cinfo->args [n].regtype = RegTypeBase;
1197 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1198 stack_size += SIZEOF_REGISTER;
1203 cinfo->args [n].size = 8;
1204 /* It was 7, now it is 8 in LinuxPPC */
1205 if (fr <= PPC_LAST_FPARG_REG) {
1206 cinfo->args [n].regtype = RegTypeFP;
1207 cinfo->args [n].reg = fr;
1209 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1210 ALWAYS_ON_STACK (stack_size += 8);
1212 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1213 cinfo->args [n].regtype = RegTypeBase;
1214 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1220 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1224 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1225 /* Prevent implicit arguments and sig_cookie from
1226 being passed in registers */
1227 gr = PPC_LAST_ARG_REG + 1;
1228 /* Emit the signature cookie just before the implicit arguments */
1229 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1233 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
1234 switch (simpletype) {
1235 case MONO_TYPE_BOOLEAN:
1240 case MONO_TYPE_CHAR:
1246 case MONO_TYPE_FNPTR:
1247 case MONO_TYPE_CLASS:
1248 case MONO_TYPE_OBJECT:
1249 case MONO_TYPE_SZARRAY:
1250 case MONO_TYPE_ARRAY:
1251 case MONO_TYPE_STRING:
1252 cinfo->ret.reg = ppc_r3;
1256 cinfo->ret.reg = ppc_r3;
1260 cinfo->ret.reg = ppc_f1;
1261 cinfo->ret.regtype = RegTypeFP;
1263 case MONO_TYPE_GENERICINST:
1264 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
1265 cinfo->ret.reg = ppc_r3;
1269 case MONO_TYPE_VALUETYPE:
1271 case MONO_TYPE_TYPEDBYREF:
1272 case MONO_TYPE_VOID:
1275 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1279 /* align stack size to 16 */
1280 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1281 stack_size = (stack_size + 15) & ~15;
1283 cinfo->stack_usage = stack_size;
1288 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1290 #if !PPC_PASS_STRUCTS_BY_VALUE
1291 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1292 int num_structs = 0;
1295 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1298 for (i = 0; i < sig->param_count; ++i) {
1299 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1300 if (type->type == MONO_TYPE_VALUETYPE)
1305 cfg->tailcall_valuetype_addrs =
1306 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1307 for (i = 0; i < num_structs; ++i) {
1308 cfg->tailcall_valuetype_addrs [i] =
1309 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1310 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1317 * Set var information according to the calling convention. ppc version.
1318 * The locals var stuff should most likely be split in another method.
1321 mono_arch_allocate_vars (MonoCompile *m)
1323 MonoMethodSignature *sig;
1324 MonoMethodHeader *header;
1326 int i, offset, size, align, curinst;
1327 int frame_reg = ppc_sp;
1329 guint32 locals_stack_size, locals_stack_align;
1331 allocate_tailcall_valuetype_addrs (m);
1333 m->flags |= MONO_CFG_HAS_SPILLUP;
1335 /* allow room for the vararg method args: void* and long/double */
1336 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1337 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1338 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1339 * call convs needs to be handled this way.
1341 if (m->flags & MONO_CFG_HAS_VARARGS)
1342 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1343 /* gtk-sharp and other broken code will dllimport vararg functions even with
1344 * non-varargs signatures. Since there is little hope people will get this right
1345 * we assume they won't.
1347 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1348 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1350 header = mono_method_get_header (m->method);
1353 * We use the frame register also for any method that has
1354 * exception clauses. This way, when the handlers are called,
1355 * the code will reference local variables using the frame reg instead of
1356 * the stack pointer: if we had to restore the stack pointer, we'd
1357 * corrupt the method frames that are already on the stack (since
1358 * filters get called before stack unwinding happens) when the filter
1359 * code would call any method (this also applies to finally etc.).
1361 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1362 frame_reg = ppc_r31;
1363 m->frame_reg = frame_reg;
1364 if (frame_reg != ppc_sp) {
1365 m->used_int_regs |= 1 << frame_reg;
1368 sig = mono_method_signature (m->method);
1372 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1373 m->ret->opcode = OP_REGVAR;
1374 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1376 /* FIXME: handle long values? */
1377 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1378 case MONO_TYPE_VOID:
1382 m->ret->opcode = OP_REGVAR;
1383 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1386 m->ret->opcode = OP_REGVAR;
1387 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1391 /* local vars are at a positive offset from the stack pointer */
1393 * also note that if the function uses alloca, we use ppc_r31
1394 * to point at the local variables.
1396 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1397 /* align the offset to 16 bytes: not sure this is needed here */
1399 //offset &= ~(16 - 1);
1401 /* add parameter area size for called functions */
1402 offset += m->param_area;
1404 offset &= ~(16 - 1);
1406 /* allow room to save the return value */
1407 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1410 /* the MonoLMF structure is stored just below the stack pointer */
1413 /* this stuff should not be needed on ppc and the new jit,
1414 * because a call on ppc to the handlers doesn't change the
1415 * stack pointer and the jist doesn't manipulate the stack pointer
1416 * for operations involving valuetypes.
1418 /* reserve space to store the esp */
1419 offset += sizeof (gpointer);
1421 /* this is a global constant */
1422 mono_exc_esp_offset = offset;
1425 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1426 offset += sizeof(gpointer) - 1;
1427 offset &= ~(sizeof(gpointer) - 1);
1429 m->vret_addr->opcode = OP_REGOFFSET;
1430 m->vret_addr->inst_basereg = frame_reg;
1431 m->vret_addr->inst_offset = offset;
1433 if (G_UNLIKELY (m->verbose_level > 1)) {
1434 printf ("vret_addr =");
1435 mono_print_ins (m->vret_addr);
1438 offset += sizeof(gpointer);
1441 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1442 if (locals_stack_align) {
1443 offset += (locals_stack_align - 1);
1444 offset &= ~(locals_stack_align - 1);
1446 for (i = m->locals_start; i < m->num_varinfo; i++) {
1447 if (offsets [i] != -1) {
1448 MonoInst *inst = m->varinfo [i];
1449 inst->opcode = OP_REGOFFSET;
1450 inst->inst_basereg = frame_reg;
1451 inst->inst_offset = offset + offsets [i];
1453 g_print ("allocating local %d (%s) to %d\n",
1454 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1458 offset += locals_stack_size;
1462 inst = m->args [curinst];
1463 if (inst->opcode != OP_REGVAR) {
1464 inst->opcode = OP_REGOFFSET;
1465 inst->inst_basereg = frame_reg;
1466 offset += sizeof (gpointer) - 1;
1467 offset &= ~(sizeof (gpointer) - 1);
1468 inst->inst_offset = offset;
1469 offset += sizeof (gpointer);
1474 for (i = 0; i < sig->param_count; ++i) {
1475 inst = m->args [curinst];
1476 if (inst->opcode != OP_REGVAR) {
1477 inst->opcode = OP_REGOFFSET;
1478 inst->inst_basereg = frame_reg;
1480 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1481 inst->backend.is_pinvoke = 1;
1483 size = mono_type_size (sig->params [i], &align);
1485 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1486 size = align = sizeof (gpointer);
1487 offset += align - 1;
1488 offset &= ~(align - 1);
1489 inst->inst_offset = offset;
1495 /* some storage for fp conversions */
1498 m->arch.fp_conv_var_offset = offset;
1501 /* align the offset to 16 bytes */
1503 offset &= ~(16 - 1);
1506 m->stack_offset = offset;
1508 if (sig->call_convention == MONO_CALL_VARARG) {
1509 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1511 m->sig_cookie = cinfo->sig_cookie.offset;
1518 mono_arch_create_vars (MonoCompile *cfg)
1520 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1522 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1523 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1527 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1528 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1532 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1534 int sig_reg = mono_alloc_ireg (cfg);
1536 /* FIXME: Add support for signature tokens to AOT */
1537 cfg->disable_aot = TRUE;
1539 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1541 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1545 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1548 MonoMethodSignature *sig;
1552 sig = call->signature;
1553 n = sig->param_count + sig->hasthis;
1555 cinfo = calculate_sizes (sig, sig->pinvoke);
1557 for (i = 0; i < n; ++i) {
1558 ArgInfo *ainfo = cinfo->args + i;
1561 if (i >= sig->hasthis)
1562 t = sig->params [i - sig->hasthis];
1564 t = &mono_defaults.int_class->byval_arg;
1565 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1567 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1568 emit_sig_cookie (cfg, call, cinfo);
1570 in = call->args [i];
1572 if (ainfo->regtype == RegTypeGeneral) {
1573 #ifndef __mono_ppc64__
1574 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1575 MONO_INST_NEW (cfg, ins, OP_MOVE);
1576 ins->dreg = mono_alloc_ireg (cfg);
1577 ins->sreg1 = in->dreg + 1;
1578 MONO_ADD_INS (cfg->cbb, ins);
1579 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1581 MONO_INST_NEW (cfg, ins, OP_MOVE);
1582 ins->dreg = mono_alloc_ireg (cfg);
1583 ins->sreg1 = in->dreg + 2;
1584 MONO_ADD_INS (cfg->cbb, ins);
1585 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1589 MONO_INST_NEW (cfg, ins, OP_MOVE);
1590 ins->dreg = mono_alloc_ireg (cfg);
1591 ins->sreg1 = in->dreg;
1592 MONO_ADD_INS (cfg->cbb, ins);
1594 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1596 } else if (ainfo->regtype == RegTypeStructByAddr) {
1597 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1598 ins->opcode = OP_OUTARG_VT;
1599 ins->sreg1 = in->dreg;
1600 ins->klass = in->klass;
1601 ins->inst_p0 = call;
1602 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1603 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1604 MONO_ADD_INS (cfg->cbb, ins);
1605 } else if (ainfo->regtype == RegTypeStructByVal) {
1606 /* this is further handled in mono_arch_emit_outarg_vt () */
1607 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1608 ins->opcode = OP_OUTARG_VT;
1609 ins->sreg1 = in->dreg;
1610 ins->klass = in->klass;
1611 ins->inst_p0 = call;
1612 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1613 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1614 MONO_ADD_INS (cfg->cbb, ins);
1615 } else if (ainfo->regtype == RegTypeBase) {
1616 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1617 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1618 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1619 if (t->type == MONO_TYPE_R8)
1620 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1622 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1624 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1626 } else if (ainfo->regtype == RegTypeFP) {
1627 if (t->type == MONO_TYPE_VALUETYPE) {
1628 /* this is further handled in mono_arch_emit_outarg_vt () */
1629 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1630 ins->opcode = OP_OUTARG_VT;
1631 ins->sreg1 = in->dreg;
1632 ins->klass = in->klass;
1633 ins->inst_p0 = call;
1634 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1635 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1636 MONO_ADD_INS (cfg->cbb, ins);
1638 cfg->flags |= MONO_CFG_HAS_FPOUT;
1640 int dreg = mono_alloc_freg (cfg);
1642 if (ainfo->size == 4) {
1643 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1645 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1647 ins->sreg1 = in->dreg;
1648 MONO_ADD_INS (cfg->cbb, ins);
1651 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1652 cfg->flags |= MONO_CFG_HAS_FPOUT;
1655 g_assert_not_reached ();
1659 /* Emit the signature cookie in the case that there is no
1660 additional argument */
1661 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1662 emit_sig_cookie (cfg, call, cinfo);
1664 if (cinfo->struct_ret) {
1667 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1668 vtarg->sreg1 = call->vret_var->dreg;
1669 vtarg->dreg = mono_alloc_preg (cfg);
1670 MONO_ADD_INS (cfg->cbb, vtarg);
1672 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1675 call->stack_usage = cinfo->stack_usage;
1676 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1677 cfg->flags |= MONO_CFG_HAS_CALLS;
1683 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1685 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1686 ArgInfo *ainfo = ins->inst_p1;
1687 int ovf_size = ainfo->vtsize;
1688 int doffset = ainfo->offset;
1689 int i, soffset, dreg;
1691 if (ainfo->regtype == RegTypeStructByVal) {
1698 * Darwin pinvokes needs some special handling for 1
1699 * and 2 byte arguments
1701 g_assert (ins->klass);
1702 if (call->signature->pinvoke)
1703 size = mono_class_native_size (ins->klass, NULL);
1704 if (size == 2 || size == 1) {
1705 int tmpr = mono_alloc_ireg (cfg);
1707 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1709 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1710 dreg = mono_alloc_ireg (cfg);
1711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1712 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1715 for (i = 0; i < ainfo->size; ++i) {
1716 int antipadding = 0;
1719 antipadding = sizeof (gpointer) - ainfo->bytes;
1721 dreg = mono_alloc_ireg (cfg);
1722 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1724 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1725 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1726 soffset += sizeof (gpointer);
1729 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1730 } else if (ainfo->regtype == RegTypeFP) {
1731 int tmpr = mono_alloc_freg (cfg);
1732 if (ainfo->size == 4)
1733 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1735 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1736 dreg = mono_alloc_freg (cfg);
1737 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1738 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1740 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1744 /* FIXME: alignment? */
1745 if (call->signature->pinvoke) {
1746 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1747 vtcopy->backend.is_pinvoke = 1;
1749 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1752 g_assert (ovf_size > 0);
1754 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1755 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1758 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1760 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1765 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1767 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1768 mono_method_signature (method)->ret);
1771 #ifndef __mono_ppc64__
1772 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1775 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1776 ins->sreg1 = val->dreg + 1;
1777 ins->sreg2 = val->dreg + 2;
1778 MONO_ADD_INS (cfg->cbb, ins);
1782 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1783 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1787 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1790 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1792 mono_arch_is_inst_imm (gint64 imm)
1798 * Allow tracing to work with this interface (with an optional argument)
1802 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1806 ppc_load (code, ppc_r3, cfg->method);
1807 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1808 ppc_load_func (code, ppc_r0, func);
1809 ppc_mtlr (code, ppc_r0);
1823 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1826 int save_mode = SAVE_NONE;
1828 MonoMethod *method = cfg->method;
1829 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1830 mono_method_signature (method)->ret)->type;
1831 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1835 offset = code - cfg->native_code;
1836 /* we need about 16 instructions */
1837 if (offset > (cfg->code_size - 16 * 4)) {
1838 cfg->code_size *= 2;
1839 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1840 code = cfg->native_code + offset;
1844 case MONO_TYPE_VOID:
1845 /* special case string .ctor icall */
1846 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1847 save_mode = SAVE_ONE;
1849 save_mode = SAVE_NONE;
1851 #ifndef __mono_ppc64__
1854 save_mode = SAVE_TWO;
1859 save_mode = SAVE_FP;
1861 case MONO_TYPE_VALUETYPE:
1862 save_mode = SAVE_STRUCT;
1865 save_mode = SAVE_ONE;
1869 switch (save_mode) {
1871 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1872 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1873 if (enable_arguments) {
1874 ppc_mr (code, ppc_r5, ppc_r4);
1875 ppc_mr (code, ppc_r4, ppc_r3);
1879 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1880 if (enable_arguments) {
1881 ppc_mr (code, ppc_r4, ppc_r3);
1885 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1886 if (enable_arguments) {
1887 /* FIXME: what reg? */
1888 ppc_fmr (code, ppc_f3, ppc_f1);
1889 /* FIXME: use 8 byte load on PPC64 */
1890 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1891 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1895 if (enable_arguments) {
1896 /* FIXME: get the actual address */
1897 ppc_mr (code, ppc_r4, ppc_r3);
1905 ppc_load (code, ppc_r3, cfg->method);
1906 ppc_load_func (code, ppc_r0, func);
1907 ppc_mtlr (code, ppc_r0);
1910 switch (save_mode) {
1912 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1913 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1916 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1919 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1929 * Conditional branches have a small offset, so if it is likely overflowed,
1930 * we do a branch to the end of the method (uncond branches have much larger
1931 * offsets) where we perform the conditional and jump back unconditionally.
1932 * It's slightly slower, since we add two uncond branches, but it's very simple
1933 * with the current patch implementation and such large methods are likely not
1934 * going to be perf critical anyway.
1939 const char *exception;
1946 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1947 if (0 && ins->inst_true_bb->native_offset) { \
1948 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1950 int br_disp = ins->inst_true_bb->max_offset - offset; \
1951 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1952 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1953 ovfj->data.bb = ins->inst_true_bb; \
1954 ovfj->ip_offset = 0; \
1955 ovfj->b0_cond = (b0); \
1956 ovfj->b1_cond = (b1); \
1957 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1960 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1961 ppc_bc (code, (b0), (b1), 0); \
1965 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1967 /* emit an exception if condition is fail
1969 * We assign the extra code used to throw the implicit exceptions
1970 * to cfg->bb_exit as far as the big branch handling is concerned
1972 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1974 int br_disp = cfg->bb_exit->max_offset - offset; \
1975 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1976 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1977 ovfj->data.exception = (exc_name); \
1978 ovfj->ip_offset = code - cfg->native_code; \
1979 ovfj->b0_cond = (b0); \
1980 ovfj->b1_cond = (b1); \
1981 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1983 cfg->bb_exit->max_offset += 24; \
1985 mono_add_patch_info (cfg, code - cfg->native_code, \
1986 MONO_PATCH_INFO_EXC, exc_name); \
1987 ppc_bcl (code, (b0), (b1), 0); \
1991 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1994 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1999 normalize_opcode (int opcode)
2002 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2003 return OP_LOAD_MEMBASE;
2004 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2005 return OP_LOAD_MEMINDEX;
2006 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2007 return OP_STORE_MEMBASE_REG;
2008 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2009 return OP_STORE_MEMBASE_IMM;
2010 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2011 return OP_STORE_MEMINDEX;
2012 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2014 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2015 return OP_SHR_UN_IMM;
2022 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2024 MonoInst *ins, *n, *last_ins = NULL;
2026 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2027 switch (normalize_opcode (ins->opcode)) {
2029 /* remove unnecessary multiplication with 1 */
2030 if (ins->inst_imm == 1) {
2031 if (ins->dreg != ins->sreg1) {
2032 ins->opcode = OP_MOVE;
2034 MONO_DELETE_INS (bb, ins);
2038 int power2 = mono_is_power_of_two (ins->inst_imm);
2040 ins->opcode = OP_SHL_IMM;
2041 ins->inst_imm = power2;
2045 case OP_LOAD_MEMBASE:
2047 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2048 * OP_LOAD_MEMBASE offset(basereg), reg
2050 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2051 ins->inst_basereg == last_ins->inst_destbasereg &&
2052 ins->inst_offset == last_ins->inst_offset) {
2053 if (ins->dreg == last_ins->sreg1) {
2054 MONO_DELETE_INS (bb, ins);
2057 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2058 ins->opcode = OP_MOVE;
2059 ins->sreg1 = last_ins->sreg1;
2063 * Note: reg1 must be different from the basereg in the second load
2064 * OP_LOAD_MEMBASE offset(basereg), reg1
2065 * OP_LOAD_MEMBASE offset(basereg), reg2
2067 * OP_LOAD_MEMBASE offset(basereg), reg1
2068 * OP_MOVE reg1, reg2
2070 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2071 ins->inst_basereg != last_ins->dreg &&
2072 ins->inst_basereg == last_ins->inst_basereg &&
2073 ins->inst_offset == last_ins->inst_offset) {
2075 if (ins->dreg == last_ins->dreg) {
2076 MONO_DELETE_INS (bb, ins);
2079 ins->opcode = OP_MOVE;
2080 ins->sreg1 = last_ins->dreg;
2083 //g_assert_not_reached ();
2087 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2088 * OP_LOAD_MEMBASE offset(basereg), reg
2090 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2091 * OP_ICONST reg, imm
2093 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2094 ins->inst_basereg == last_ins->inst_destbasereg &&
2095 ins->inst_offset == last_ins->inst_offset) {
2096 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2097 ins->opcode = OP_ICONST;
2098 ins->inst_c0 = last_ins->inst_imm;
2099 g_assert_not_reached (); // check this rule
2103 case OP_LOADU1_MEMBASE:
2104 case OP_LOADI1_MEMBASE:
2105 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2106 ins->inst_basereg == last_ins->inst_destbasereg &&
2107 ins->inst_offset == last_ins->inst_offset) {
2108 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2109 ins->sreg1 = last_ins->sreg1;
2112 case OP_LOADU2_MEMBASE:
2113 case OP_LOADI2_MEMBASE:
2114 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2115 ins->inst_basereg == last_ins->inst_destbasereg &&
2116 ins->inst_offset == last_ins->inst_offset) {
2117 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2118 ins->sreg1 = last_ins->sreg1;
2121 #ifdef __mono_ppc64__
2122 case OP_LOADU4_MEMBASE:
2123 case OP_LOADI4_MEMBASE:
2124 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2125 ins->inst_basereg == last_ins->inst_destbasereg &&
2126 ins->inst_offset == last_ins->inst_offset) {
2127 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2128 ins->sreg1 = last_ins->sreg1;
2133 ins->opcode = OP_MOVE;
2137 if (ins->dreg == ins->sreg1) {
2138 MONO_DELETE_INS (bb, ins);
2142 * OP_MOVE sreg, dreg
2143 * OP_MOVE dreg, sreg
2145 if (last_ins && last_ins->opcode == OP_MOVE &&
2146 ins->sreg1 == last_ins->dreg &&
2147 ins->dreg == last_ins->sreg1) {
2148 MONO_DELETE_INS (bb, ins);
2156 bb->last_ins = last_ins;
2160 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2162 switch (ins->opcode) {
2163 case OP_ICONV_TO_R_UN: {
2164 static const guint64 adjust_val = 0x4330000000000000ULL;
2165 int msw_reg = mono_alloc_ireg (cfg);
2166 int adj_reg = mono_alloc_freg (cfg);
2167 int tmp_reg = mono_alloc_freg (cfg);
2168 int basereg = ppc_sp;
2170 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2171 if (!ppc_is_imm16 (offset + 4)) {
2172 basereg = mono_alloc_ireg (cfg);
2173 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2175 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2176 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2177 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2178 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2180 ins->opcode = OP_NOP;
2183 #ifndef __mono_ppc64__
2184 case OP_ICONV_TO_R4:
2185 case OP_ICONV_TO_R8: {
2186 /* If we have a PPC_FEATURE_64 machine we can avoid
2187 this and use the fcfid instruction. Otherwise
2188 on an old 32-bit chip and we have to do this the
2190 if (!(cpu_hw_caps & PPC_ISA_64)) {
2191 /* FIXME: change precision for CEE_CONV_R4 */
2192 static const guint64 adjust_val = 0x4330000080000000ULL;
2193 int msw_reg = mono_alloc_ireg (cfg);
2194 int xored = mono_alloc_ireg (cfg);
2195 int adj_reg = mono_alloc_freg (cfg);
2196 int tmp_reg = mono_alloc_freg (cfg);
2197 int basereg = ppc_sp;
2199 if (!ppc_is_imm16 (offset + 4)) {
2200 basereg = mono_alloc_ireg (cfg);
2201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2203 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2204 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2206 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2207 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2208 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2209 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2210 if (ins->opcode == OP_ICONV_TO_R4)
2211 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2212 ins->opcode = OP_NOP;
2218 int msw_reg = mono_alloc_ireg (cfg);
2219 int basereg = ppc_sp;
2221 if (!ppc_is_imm16 (offset + 4)) {
2222 basereg = mono_alloc_ireg (cfg);
2223 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2225 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2226 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2227 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2228 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2229 ins->opcode = OP_NOP;
2232 #ifdef __mono_ppc64__
2234 case OP_IADD_OVF_UN:
2236 int shifted1_reg = mono_alloc_ireg (cfg);
2237 int shifted2_reg = mono_alloc_ireg (cfg);
2238 int result_shifted_reg = mono_alloc_ireg (cfg);
2240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2241 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2242 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2243 if (ins->opcode == OP_IADD_OVF_UN)
2244 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2246 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2247 ins->opcode = OP_NOP;
2254 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2256 switch (ins->opcode) {
2258 /* ADC sets the condition code */
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2263 case OP_LADD_OVF_UN:
2264 /* ADC sets the condition code */
2265 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2266 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2270 /* SBB sets the condition code */
2271 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2272 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2275 case OP_LSUB_OVF_UN:
2276 /* SBB sets the condition code */
2277 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2278 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2282 /* This is the old version from inssel-long32.brg */
2283 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 1, ins->sreg1 + 1);
2284 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 2, ins->sreg1 + 2);
2285 /* ADC sets the condition codes */
2286 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 1, ins->dreg + 1, 1);
2287 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->dreg + 2, 0);
2296 * the branch_b0_table should maintain the order of these
2310 branch_b0_table [] = {
2325 branch_b1_table [] = {
2339 #define NEW_INS(cfg,dest,op) do { \
2340 MONO_INST_NEW((cfg), (dest), (op)); \
2341 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2345 map_to_reg_reg_op (int op)
2354 case OP_COMPARE_IMM:
2356 case OP_ICOMPARE_IMM:
2358 case OP_LCOMPARE_IMM:
2374 case OP_LOAD_MEMBASE:
2375 return OP_LOAD_MEMINDEX;
2376 case OP_LOADI4_MEMBASE:
2377 return OP_LOADI4_MEMINDEX;
2378 case OP_LOADU4_MEMBASE:
2379 return OP_LOADU4_MEMINDEX;
2380 case OP_LOADI8_MEMBASE:
2381 return OP_LOADI8_MEMINDEX;
2382 case OP_LOADU1_MEMBASE:
2383 return OP_LOADU1_MEMINDEX;
2384 case OP_LOADI2_MEMBASE:
2385 return OP_LOADI2_MEMINDEX;
2386 case OP_LOADU2_MEMBASE:
2387 return OP_LOADU2_MEMINDEX;
2388 case OP_LOADI1_MEMBASE:
2389 return OP_LOADI1_MEMINDEX;
2390 case OP_LOADR4_MEMBASE:
2391 return OP_LOADR4_MEMINDEX;
2392 case OP_LOADR8_MEMBASE:
2393 return OP_LOADR8_MEMINDEX;
2394 case OP_STOREI1_MEMBASE_REG:
2395 return OP_STOREI1_MEMINDEX;
2396 case OP_STOREI2_MEMBASE_REG:
2397 return OP_STOREI2_MEMINDEX;
2398 case OP_STOREI4_MEMBASE_REG:
2399 return OP_STOREI4_MEMINDEX;
2400 case OP_STOREI8_MEMBASE_REG:
2401 return OP_STOREI8_MEMINDEX;
2402 case OP_STORE_MEMBASE_REG:
2403 return OP_STORE_MEMINDEX;
2404 case OP_STORER4_MEMBASE_REG:
2405 return OP_STORER4_MEMINDEX;
2406 case OP_STORER8_MEMBASE_REG:
2407 return OP_STORER8_MEMINDEX;
2408 case OP_STORE_MEMBASE_IMM:
2409 return OP_STORE_MEMBASE_REG;
2410 case OP_STOREI1_MEMBASE_IMM:
2411 return OP_STOREI1_MEMBASE_REG;
2412 case OP_STOREI2_MEMBASE_IMM:
2413 return OP_STOREI2_MEMBASE_REG;
2414 case OP_STOREI4_MEMBASE_IMM:
2415 return OP_STOREI4_MEMBASE_REG;
2416 case OP_STOREI8_MEMBASE_IMM:
2417 return OP_STOREI8_MEMBASE_REG;
2419 return mono_op_imm_to_op (op);
2422 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2424 #define compare_opcode_is_unsigned(opcode) \
2425 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2426 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2427 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2428 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2429 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2430 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2431 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2432 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2435 * Remove from the instruction list the instructions that can't be
2436 * represented with very simple instructions with no register
2440 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2442 MonoInst *ins, *next, *temp, *last_ins = NULL;
2445 MONO_BB_FOR_EACH_INS (bb, ins) {
2447 switch (ins->opcode) {
2448 case OP_IDIV_UN_IMM:
2451 case OP_IREM_UN_IMM:
2452 NEW_INS (cfg, temp, OP_ICONST);
2453 temp->inst_c0 = ins->inst_imm;
2454 temp->dreg = mono_alloc_ireg (cfg);
2455 ins->sreg2 = temp->dreg;
2456 if (ins->opcode == OP_IDIV_IMM)
2457 ins->opcode = OP_IDIV;
2458 else if (ins->opcode == OP_IREM_IMM)
2459 ins->opcode = OP_IREM;
2460 else if (ins->opcode == OP_IDIV_UN_IMM)
2461 ins->opcode = OP_IDIV_UN;
2462 else if (ins->opcode == OP_IREM_UN_IMM)
2463 ins->opcode = OP_IREM_UN;
2465 /* handle rem separately */
2469 CASE_PPC64 (OP_LREM)
2470 CASE_PPC64 (OP_LREM_UN) {
2472 /* we change a rem dest, src1, src2 to
2473 * div temp1, src1, src2
2474 * mul temp2, temp1, src2
2475 * sub dest, src1, temp2
2477 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2478 NEW_INS (cfg, mul, OP_IMUL);
2479 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2480 ins->opcode = OP_ISUB;
2482 NEW_INS (cfg, mul, OP_LMUL);
2483 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2484 ins->opcode = OP_LSUB;
2486 temp->sreg1 = ins->sreg1;
2487 temp->sreg2 = ins->sreg2;
2488 temp->dreg = mono_alloc_ireg (cfg);
2489 mul->sreg1 = temp->dreg;
2490 mul->sreg2 = ins->sreg2;
2491 mul->dreg = mono_alloc_ireg (cfg);
2492 ins->sreg2 = mul->dreg;
2496 CASE_PPC64 (OP_LADD_IMM)
2499 if (!ppc_is_imm16 (ins->inst_imm)) {
2500 NEW_INS (cfg, temp, OP_ICONST);
2501 temp->inst_c0 = ins->inst_imm;
2502 temp->dreg = mono_alloc_ireg (cfg);
2503 ins->sreg2 = temp->dreg;
2504 ins->opcode = map_to_reg_reg_op (ins->opcode);
2508 CASE_PPC64 (OP_LSUB_IMM)
2510 if (!ppc_is_imm16 (-ins->inst_imm)) {
2511 NEW_INS (cfg, temp, OP_ICONST);
2512 temp->inst_c0 = ins->inst_imm;
2513 temp->dreg = mono_alloc_ireg (cfg);
2514 ins->sreg2 = temp->dreg;
2515 ins->opcode = map_to_reg_reg_op (ins->opcode);
2527 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2528 #ifdef __mono_ppc64__
2529 if (ins->inst_imm & 0xffffffff00000000UL)
2533 NEW_INS (cfg, temp, OP_ICONST);
2534 temp->inst_c0 = ins->inst_imm;
2535 temp->dreg = mono_alloc_ireg (cfg);
2536 ins->sreg2 = temp->dreg;
2537 ins->opcode = map_to_reg_reg_op (ins->opcode);
2546 NEW_INS (cfg, temp, OP_ICONST);
2547 temp->inst_c0 = ins->inst_imm;
2548 temp->dreg = mono_alloc_ireg (cfg);
2549 ins->sreg2 = temp->dreg;
2550 ins->opcode = map_to_reg_reg_op (ins->opcode);
2552 case OP_COMPARE_IMM:
2553 case OP_ICOMPARE_IMM:
2554 CASE_PPC64 (OP_LCOMPARE_IMM)
2556 /* Branch opts can eliminate the branch */
2557 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2558 ins->opcode = OP_NOP;
2562 if (compare_opcode_is_unsigned (next->opcode)) {
2563 if (!ppc_is_uimm16 (ins->inst_imm)) {
2564 NEW_INS (cfg, temp, OP_ICONST);
2565 temp->inst_c0 = ins->inst_imm;
2566 temp->dreg = mono_alloc_ireg (cfg);
2567 ins->sreg2 = temp->dreg;
2568 ins->opcode = map_to_reg_reg_op (ins->opcode);
2571 if (!ppc_is_imm16 (ins->inst_imm)) {
2572 NEW_INS (cfg, temp, OP_ICONST);
2573 temp->inst_c0 = ins->inst_imm;
2574 temp->dreg = mono_alloc_ireg (cfg);
2575 ins->sreg2 = temp->dreg;
2576 ins->opcode = map_to_reg_reg_op (ins->opcode);
2582 if (ins->inst_imm == 1) {
2583 ins->opcode = OP_MOVE;
2586 if (ins->inst_imm == 0) {
2587 ins->opcode = OP_ICONST;
2591 imm = mono_is_power_of_two (ins->inst_imm);
2593 ins->opcode = OP_SHL_IMM;
2594 ins->inst_imm = imm;
2597 if (!ppc_is_imm16 (ins->inst_imm)) {
2598 NEW_INS (cfg, temp, OP_ICONST);
2599 temp->inst_c0 = ins->inst_imm;
2600 temp->dreg = mono_alloc_ireg (cfg);
2601 ins->sreg2 = temp->dreg;
2602 ins->opcode = map_to_reg_reg_op (ins->opcode);
2605 case OP_LOCALLOC_IMM:
2606 NEW_INS (cfg, temp, OP_ICONST);
2607 temp->inst_c0 = ins->inst_imm;
2608 temp->dreg = mono_alloc_ireg (cfg);
2609 ins->sreg1 = temp->dreg;
2610 ins->opcode = OP_LOCALLOC;
2612 case OP_LOAD_MEMBASE:
2613 case OP_LOADI4_MEMBASE:
2614 CASE_PPC64 (OP_LOADI8_MEMBASE)
2615 case OP_LOADU4_MEMBASE:
2616 case OP_LOADI2_MEMBASE:
2617 case OP_LOADU2_MEMBASE:
2618 case OP_LOADI1_MEMBASE:
2619 case OP_LOADU1_MEMBASE:
2620 case OP_LOADR4_MEMBASE:
2621 case OP_LOADR8_MEMBASE:
2622 case OP_STORE_MEMBASE_REG:
2623 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2624 case OP_STOREI4_MEMBASE_REG:
2625 case OP_STOREI2_MEMBASE_REG:
2626 case OP_STOREI1_MEMBASE_REG:
2627 case OP_STORER4_MEMBASE_REG:
2628 case OP_STORER8_MEMBASE_REG:
2629 /* we can do two things: load the immed in a register
2630 * and use an indexed load, or see if the immed can be
2631 * represented as an ad_imm + a load with a smaller offset
2632 * that fits. We just do the first for now, optimize later.
2634 if (ppc_is_imm16 (ins->inst_offset))
2636 NEW_INS (cfg, temp, OP_ICONST);
2637 temp->inst_c0 = ins->inst_offset;
2638 temp->dreg = mono_alloc_ireg (cfg);
2639 ins->sreg2 = temp->dreg;
2640 ins->opcode = map_to_reg_reg_op (ins->opcode);
2642 case OP_STORE_MEMBASE_IMM:
2643 case OP_STOREI1_MEMBASE_IMM:
2644 case OP_STOREI2_MEMBASE_IMM:
2645 case OP_STOREI4_MEMBASE_IMM:
2646 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2647 NEW_INS (cfg, temp, OP_ICONST);
2648 temp->inst_c0 = ins->inst_imm;
2649 temp->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg1 = temp->dreg;
2651 ins->opcode = map_to_reg_reg_op (ins->opcode);
2653 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2656 if (cfg->compile_aot) {
2657 /* Keep these in the aot case */
2660 NEW_INS (cfg, temp, OP_ICONST);
2661 temp->inst_c0 = (gulong)ins->inst_p0;
2662 temp->dreg = mono_alloc_ireg (cfg);
2663 ins->inst_basereg = temp->dreg;
2664 ins->inst_offset = 0;
2665 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2667 /* make it handle the possibly big ins->inst_offset
2668 * later optimize to use lis + load_membase
2674 bb->last_ins = last_ins;
2675 bb->max_vreg = cfg->next_vreg;
2679 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2681 long offset = cfg->arch.fp_conv_var_offset;
2683 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2684 #ifdef __mono_ppc64__
2686 ppc_fctidz (code, ppc_f0, sreg);
2691 ppc_fctiwz (code, ppc_f0, sreg);
2694 if (ppc_is_imm16 (offset + sub_offset)) {
2695 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2697 ppc_ldptr (code, dreg, offset + sub_offset, cfg->frame_reg);
2699 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2701 ppc_load (code, dreg, offset);
2702 ppc_add (code, dreg, dreg, cfg->frame_reg);
2703 ppc_stfd (code, ppc_f0, 0, dreg);
2705 ppc_ldptr (code, dreg, sub_offset, dreg);
2707 ppc_lwz (code, dreg, sub_offset, dreg);
2711 ppc_andid (code, dreg, dreg, 0xff);
2713 ppc_andid (code, dreg, dreg, 0xffff);
2714 #ifdef __mono_ppc64__
2716 ppc_clrldi (code, dreg, dreg, 32);
2720 ppc_extsb (code, dreg, dreg);
2722 ppc_extsh (code, dreg, dreg);
2723 #ifdef __mono_ppc64__
2725 ppc_extsw (code, dreg, dreg);
2733 const guchar *target;
2738 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2741 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2742 #ifdef __mono_ppc64__
2743 g_assert_not_reached ();
2745 PatchData *pdata = (PatchData*)user_data;
2746 guchar *code = data;
2747 guint32 *thunks = data;
2748 guint32 *endthunks = (guint32*)(code + bsize);
2752 int difflow, diffhigh;
2754 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2755 difflow = (char*)pdata->code - (char*)thunks;
2756 diffhigh = (char*)pdata->code - (char*)endthunks;
2757 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2760 templ = (guchar*)load;
2761 ppc_load_sequence (templ, ppc_r0, pdata->target);
2763 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2764 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2765 while (thunks < endthunks) {
2766 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2767 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2768 ppc_patch (pdata->code, (guchar*)thunks);
2771 static int num_thunks = 0;
2773 if ((num_thunks % 20) == 0)
2774 g_print ("num_thunks lookup: %d\n", num_thunks);
2777 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2778 /* found a free slot instead: emit thunk */
2779 code = (guchar*)thunks;
2780 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2781 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2782 ppc_mtctr (code, ppc_r0);
2783 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2784 mono_arch_flush_icache ((guchar*)thunks, 16);
2786 ppc_patch (pdata->code, (guchar*)thunks);
2789 static int num_thunks = 0;
2791 if ((num_thunks % 20) == 0)
2792 g_print ("num_thunks: %d\n", num_thunks);
2796 /* skip 16 bytes, the size of the thunk */
2800 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2807 handle_thunk (int absolute, guchar *code, const guchar *target) {
2808 MonoDomain *domain = mono_domain_get ();
2812 pdata.target = target;
2813 pdata.absolute = absolute;
2816 mono_domain_lock (domain);
2817 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2820 /* this uses the first available slot */
2822 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2824 mono_domain_unlock (domain);
2826 if (pdata.found != 1)
2827 g_print ("thunk failed for %p from %p\n", target, code);
2828 g_assert (pdata.found == 1);
2832 patch_ins (guint8 *code, guint32 ins)
2834 *(guint32*)code = ins;
2835 mono_arch_flush_icache (code, 4);
2839 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2841 guint32 ins = *(guint32*)code;
2842 guint32 prim = ins >> 26;
2845 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2847 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2848 gint diff = target - code;
2851 if (diff <= 33554431){
2852 ins = (18 << 26) | (diff) | (ins & 1);
2853 patch_ins (code, ins);
2857 /* diff between 0 and -33554432 */
2858 if (diff >= -33554432){
2859 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2860 patch_ins (code, ins);
2865 if ((glong)target >= 0){
2866 if ((glong)target <= 33554431){
2867 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2868 patch_ins (code, ins);
2872 if ((glong)target >= -33554432){
2873 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2874 patch_ins (code, ins);
2879 handle_thunk (TRUE, code, target);
2882 g_assert_not_reached ();
2890 guint32 li = (gulong)target;
2891 ins = (ins & 0xffff0000) | (ins & 3);
2892 ovf = li & 0xffff0000;
2893 if (ovf != 0 && ovf != 0xffff0000)
2894 g_assert_not_reached ();
2897 // FIXME: assert the top bits of li are 0
2899 gint diff = target - code;
2900 ins = (ins & 0xffff0000) | (ins & 3);
2901 ovf = diff & 0xffff0000;
2902 if (ovf != 0 && ovf != 0xffff0000)
2903 g_assert_not_reached ();
2907 patch_ins (code, ins);
2911 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2912 #ifdef __mono_ppc64__
2913 guint32 *seq = (guint32*)code;
2914 guint32 *branch_ins;
2916 /* the trampoline code will try to patch the blrl, blr, bcctr */
2917 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2919 if (ppc_opcode (seq [-3]) == 58 || ppc_opcode (seq [-3]) == 31) /* ld || mr */
2924 if (ppc_opcode (seq [5]) == 58 || ppc_opcode (seq [5]) == 31) /* ld || mr */
2925 branch_ins = seq + 8;
2927 branch_ins = seq + 6;
2930 seq = (guint32*)code;
2931 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2932 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2934 if (ppc_opcode (seq [5]) == 58) { /* ld */
2935 g_assert (ppc_opcode (seq [6]) == 58); /* ld */
2938 guint8 *buf = (guint8*)&seq [5];
2939 ppc_mr (buf, ppc_r0, ppc_r11);
2944 target = mono_get_addr_from_ftnptr ((gpointer)target);
2947 /* FIXME: make this thread safe */
2948 /* FIXME: we're assuming we're using r11 here */
2949 ppc_load_sequence (code, ppc_r11, target);
2950 mono_arch_flush_icache ((guint8*)seq, 28);
2953 /* the trampoline code will try to patch the blrl, blr, bcctr */
2954 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2957 /* this is the lis/ori/mtlr/blrl sequence */
2958 seq = (guint32*)code;
2959 g_assert ((seq [0] >> 26) == 15);
2960 g_assert ((seq [1] >> 26) == 24);
2961 g_assert ((seq [2] >> 26) == 31);
2962 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2963 /* FIXME: make this thread safe */
2964 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2965 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2966 mono_arch_flush_icache (code - 8, 8);
2969 g_assert_not_reached ();
2971 // g_print ("patched with 0x%08x\n", ins);
2975 ppc_patch (guchar *code, const guchar *target)
2977 ppc_patch_full (code, target, FALSE);
2981 mono_ppc_patch (guchar *code, const guchar *target)
2983 ppc_patch (code, target);
2987 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2989 switch (ins->opcode) {
2992 case OP_FCALL_MEMBASE:
2993 if (ins->dreg != ppc_f1)
2994 ppc_fmr (code, ins->dreg, ppc_f1);
3002 * emit_load_volatile_arguments:
3004 * Load volatile arguments from the stack to the original input registers.
3005 * Required before a tail call.
3008 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3010 MonoMethod *method = cfg->method;
3011 MonoMethodSignature *sig;
3015 int struct_index = 0;
3017 sig = mono_method_signature (method);
3019 /* This is the opposite of the code in emit_prolog */
3023 cinfo = calculate_sizes (sig, sig->pinvoke);
3025 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3026 ArgInfo *ainfo = &cinfo->ret;
3027 inst = cfg->vret_addr;
3028 g_assert (ppc_is_imm16 (inst->inst_offset));
3029 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3031 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3032 ArgInfo *ainfo = cinfo->args + i;
3033 inst = cfg->args [pos];
3035 g_assert (inst->opcode != OP_REGVAR);
3036 g_assert (ppc_is_imm16 (inst->inst_offset));
3038 switch (ainfo->regtype) {
3039 case RegTypeGeneral:
3040 switch (ainfo->size) {
3042 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3045 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3047 #ifdef __mono_ppc64__
3049 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3053 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3059 switch (ainfo->size) {
3061 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3064 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3067 g_assert_not_reached ();
3072 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3073 &inst->klass->byval_arg);
3075 #ifndef __mono_ppc64__
3076 if (type->type == MONO_TYPE_I8)
3080 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3081 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3082 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3083 } else if (type->type == MONO_TYPE_I4) {
3084 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3085 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3093 case RegTypeStructByVal: {
3104 * Darwin pinvokes needs some special handling
3105 * for 1 and 2 byte arguments
3107 if (method->signature->pinvoke)
3108 size = mono_class_native_size (inst->klass, NULL);
3109 if (size == 1 || size == 2) {
3114 for (j = 0; j < ainfo->size; ++j) {
3115 ppc_ldptr (code, ainfo->reg + j,
3116 inst->inst_offset + j * sizeof (gpointer),
3117 inst->inst_basereg);
3118 /* FIXME: shift to the right */
3125 case RegTypeStructByAddr: {
3126 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3128 g_assert (ppc_is_imm16 (addr->inst_offset));
3129 g_assert (!ainfo->offset);
3130 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3137 g_assert_not_reached ();
3148 /* This must be kept in sync with emit_load_volatile_arguments(). */
3150 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3152 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3153 MonoMethodSignature *sig;
3158 if (ins->opcode != OP_JMP)
3161 call = (MonoCallInst*)ins;
3162 sig = mono_method_signature (cfg->method);
3163 cinfo = calculate_sizes (sig, sig->pinvoke);
3165 if (MONO_TYPE_ISSTRUCT (sig->ret))
3167 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3168 ArgInfo *ainfo = cinfo->args + i;
3170 switch (ainfo->regtype) {
3171 case RegTypeGeneral:
3180 case RegTypeStructByVal:
3181 len += 4 * ainfo->size;
3184 case RegTypeStructByAddr:
3189 g_assert_not_reached ();
3199 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3201 long size = cfg->param_area;
3203 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3204 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3209 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3210 if (ppc_is_imm16 (-size)) {
3211 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3213 ppc_load (code, ppc_r11, -size);
3214 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3221 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3223 long size = cfg->param_area;
3225 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3226 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3231 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3232 if (ppc_is_imm16 (size)) {
3233 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3235 ppc_load (code, ppc_r11, size);
3236 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3242 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3245 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3247 MonoInst *ins, *next;
3250 guint8 *code = cfg->native_code + cfg->code_len;
3251 MonoInst *last_ins = NULL;
3252 guint last_offset = 0;
3256 /* we don't align basic blocks of loops on ppc */
3258 if (cfg->verbose_level > 2)
3259 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3261 cpos = bb->max_offset;
3263 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3264 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3265 //g_assert (!mono_compile_aot);
3268 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3269 /* this is not thread save, but good enough */
3270 /* fixme: howto handle overflows? */
3271 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3274 MONO_BB_FOR_EACH_INS (bb, ins) {
3275 offset = code - cfg->native_code;
3277 max_len = ins_native_length (cfg, ins);
3279 if (offset > (cfg->code_size - max_len - 16)) {
3280 cfg->code_size *= 2;
3281 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3282 code = cfg->native_code + offset;
3284 // if (ins->cil_code)
3285 // g_print ("cil code\n");
3286 mono_debug_record_line_number (cfg, ins, offset);
3288 switch (normalize_opcode (ins->opcode)) {
3289 case OP_RELAXED_NOP:
3292 case OP_DUMMY_STORE:
3293 case OP_NOT_REACHED:
3297 emit_tls_access (code, ins->dreg, ins->inst_offset);
3300 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3301 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3302 ppc_mr (code, ppc_r4, ppc_r0);
3305 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3306 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3307 ppc_mr (code, ppc_r4, ppc_r0);
3309 case OP_MEMORY_BARRIER:
3312 case OP_STOREI1_MEMBASE_REG:
3313 if (ppc_is_imm16 (ins->inst_offset)) {
3314 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3316 if (ppc_is_imm32 (ins->inst_offset)) {
3317 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3318 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3320 ppc_load (code, ppc_r0, ins->inst_offset);
3321 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3325 case OP_STOREI2_MEMBASE_REG:
3326 if (ppc_is_imm16 (ins->inst_offset)) {
3327 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3329 if (ppc_is_imm32 (ins->inst_offset)) {
3330 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3331 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3333 ppc_load (code, ppc_r0, ins->inst_offset);
3334 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3338 case OP_STORE_MEMBASE_REG:
3339 if (ppc_is_imm16 (ins->inst_offset)) {
3340 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3342 if (ppc_is_imm32 (ins->inst_offset)) {
3343 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3344 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3346 ppc_load (code, ppc_r0, ins->inst_offset);
3347 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3351 case OP_STOREI1_MEMINDEX:
3352 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3354 case OP_STOREI2_MEMINDEX:
3355 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3357 case OP_STORE_MEMINDEX:
3358 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3361 g_assert_not_reached ();
3363 case OP_LOAD_MEMBASE:
3364 if (ppc_is_imm16 (ins->inst_offset)) {
3365 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3367 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3368 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3369 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3371 ppc_load (code, ppc_r0, ins->inst_offset);
3372 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3376 case OP_LOADI4_MEMBASE:
3377 #ifdef __mono_ppc64__
3378 if (ppc_is_imm16 (ins->inst_offset)) {
3379 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3381 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3382 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3383 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3385 ppc_load (code, ppc_r0, ins->inst_offset);
3386 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3391 case OP_LOADU4_MEMBASE:
3392 if (ppc_is_imm16 (ins->inst_offset)) {
3393 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3395 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3396 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3397 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3399 ppc_load (code, ppc_r0, ins->inst_offset);
3400 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3404 case OP_LOADI1_MEMBASE:
3405 case OP_LOADU1_MEMBASE:
3406 if (ppc_is_imm16 (ins->inst_offset)) {
3407 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3409 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3410 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3411 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3413 ppc_load (code, ppc_r0, ins->inst_offset);
3414 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3417 if (ins->opcode == OP_LOADI1_MEMBASE)
3418 ppc_extsb (code, ins->dreg, ins->dreg);
3420 case OP_LOADU2_MEMBASE:
3421 if (ppc_is_imm16 (ins->inst_offset)) {
3422 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3424 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3425 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3426 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3428 ppc_load (code, ppc_r0, ins->inst_offset);
3429 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3433 case OP_LOADI2_MEMBASE:
3434 if (ppc_is_imm16 (ins->inst_offset)) {
3435 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3437 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3438 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3439 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3441 ppc_load (code, ppc_r0, ins->inst_offset);
3442 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3446 case OP_LOAD_MEMINDEX:
3447 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3449 case OP_LOADI4_MEMINDEX:
3450 #ifdef __mono_ppc64__
3451 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3454 case OP_LOADU4_MEMINDEX:
3455 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3457 case OP_LOADU2_MEMINDEX:
3458 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3460 case OP_LOADI2_MEMINDEX:
3461 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3463 case OP_LOADU1_MEMINDEX:
3464 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3466 case OP_LOADI1_MEMINDEX:
3467 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3468 ppc_extsb (code, ins->dreg, ins->dreg);
3470 case OP_ICONV_TO_I1:
3471 CASE_PPC64 (OP_LCONV_TO_I1)
3472 ppc_extsb (code, ins->dreg, ins->sreg1);
3474 case OP_ICONV_TO_I2:
3475 CASE_PPC64 (OP_LCONV_TO_I2)
3476 ppc_extsh (code, ins->dreg, ins->sreg1);
3478 case OP_ICONV_TO_U1:
3479 CASE_PPC64 (OP_LCONV_TO_U1)
3480 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3482 case OP_ICONV_TO_U2:
3483 CASE_PPC64 (OP_LCONV_TO_U2)
3484 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3488 CASE_PPC64 (OP_LCOMPARE)
3489 L = (sizeof (gpointer) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3491 if (next && compare_opcode_is_unsigned (next->opcode))
3492 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3494 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3496 case OP_COMPARE_IMM:
3497 case OP_ICOMPARE_IMM:
3498 CASE_PPC64 (OP_LCOMPARE_IMM)
3499 L = (sizeof (gpointer) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3501 if (next && compare_opcode_is_unsigned (next->opcode)) {
3502 if (ppc_is_uimm16 (ins->inst_imm)) {
3503 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3505 g_assert_not_reached ();
3508 if (ppc_is_imm16 (ins->inst_imm)) {
3509 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3511 g_assert_not_reached ();
3520 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3523 CASE_PPC64 (OP_LADD)
3524 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3528 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3531 if (ppc_is_imm16 (ins->inst_imm)) {
3532 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3534 g_assert_not_reached ();
3539 CASE_PPC64 (OP_LADD_IMM)
3540 if (ppc_is_imm16 (ins->inst_imm)) {
3541 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3543 g_assert_not_reached ();
3547 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3549 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3550 ppc_mfspr (code, ppc_r0, ppc_xer);
3551 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3552 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3554 case OP_IADD_OVF_UN:
3555 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3557 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3558 ppc_mfspr (code, ppc_r0, ppc_xer);
3559 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3560 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3563 CASE_PPC64 (OP_LSUB_OVF)
3564 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3566 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3567 ppc_mfspr (code, ppc_r0, ppc_xer);
3568 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3569 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3571 case OP_ISUB_OVF_UN:
3572 CASE_PPC64 (OP_LSUB_OVF_UN)
3573 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3575 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3576 ppc_mfspr (code, ppc_r0, ppc_xer);
3577 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3578 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3580 case OP_ADD_OVF_CARRY:
3581 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3583 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 ppc_mfspr (code, ppc_r0, ppc_xer);
3585 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3586 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3588 case OP_ADD_OVF_UN_CARRY:
3589 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3591 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3592 ppc_mfspr (code, ppc_r0, ppc_xer);
3593 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3594 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3596 case OP_SUB_OVF_CARRY:
3597 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3599 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3600 ppc_mfspr (code, ppc_r0, ppc_xer);
3601 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3602 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3604 case OP_SUB_OVF_UN_CARRY:
3605 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3607 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3608 ppc_mfspr (code, ppc_r0, ppc_xer);
3609 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3610 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3614 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3617 CASE_PPC64 (OP_LSUB)
3618 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3622 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3626 CASE_PPC64 (OP_LSUB_IMM)
3627 // we add the negated value
3628 if (ppc_is_imm16 (-ins->inst_imm))
3629 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3631 g_assert_not_reached ();
3635 g_assert (ppc_is_imm16 (ins->inst_imm));
3636 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3639 ppc_subfze (code, ins->dreg, ins->sreg1);
3642 CASE_PPC64 (OP_LAND)
3643 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3644 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3648 CASE_PPC64 (OP_LAND_IMM)
3649 if (!(ins->inst_imm & 0xffff0000)) {
3650 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3651 } else if (!(ins->inst_imm & 0xffff)) {
3652 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3654 g_assert_not_reached ();
3658 CASE_PPC64 (OP_LDIV) {
3659 guint8 *divisor_is_m1;
3660 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3662 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3663 divisor_is_m1 = code;
3664 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3665 ppc_lis (code, ppc_r0, 0x8000);
3666 #ifdef __mono_ppc64__
3667 if (ins->opcode == OP_LDIV)
3668 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3670 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3671 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3672 ppc_patch (divisor_is_m1, code);
3673 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3675 if (ins->opcode == OP_IDIV)
3676 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3677 #ifdef __mono_ppc64__
3679 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3681 ppc_mfspr (code, ppc_r0, ppc_xer);
3682 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3683 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3687 CASE_PPC64 (OP_LDIV_UN)
3688 if (ins->opcode == OP_IDIV_UN)
3689 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3690 #ifdef __mono_ppc64__
3692 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3694 ppc_mfspr (code, ppc_r0, ppc_xer);
3695 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3696 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3702 g_assert_not_reached ();
3705 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3709 CASE_PPC64 (OP_LOR_IMM)
3710 if (!(ins->inst_imm & 0xffff0000)) {
3711 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3712 } else if (!(ins->inst_imm & 0xffff)) {
3713 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3715 g_assert_not_reached ();
3719 CASE_PPC64 (OP_LXOR)
3720 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3724 CASE_PPC64 (OP_LXOR_IMM)
3725 if (!(ins->inst_imm & 0xffff0000)) {
3726 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3727 } else if (!(ins->inst_imm & 0xffff)) {
3728 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3730 g_assert_not_reached ();
3734 CASE_PPC64 (OP_LSHL)
3735 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3739 CASE_PPC64 (OP_LSHL_IMM)
3740 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3743 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3746 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3749 if (MASK_SHIFT_IMM (ins->inst_imm))
3750 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3752 ppc_mr (code, ins->dreg, ins->sreg1);
3755 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3758 CASE_PPC64 (OP_LNOT)
3759 ppc_not (code, ins->dreg, ins->sreg1);
3762 CASE_PPC64 (OP_LNEG)
3763 ppc_neg (code, ins->dreg, ins->sreg1);
3766 CASE_PPC64 (OP_LMUL)
3767 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3771 CASE_PPC64 (OP_LMUL_IMM)
3772 if (ppc_is_imm16 (ins->inst_imm)) {
3773 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3775 g_assert_not_reached ();
3779 CASE_PPC64 (OP_LMUL_OVF)
3780 /* we annot use mcrxr, since it's not implemented on some processors
3781 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3783 if (ins->opcode == OP_IMUL_OVF)
3784 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3785 #ifdef __mono_ppc64__
3787 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3789 ppc_mfspr (code, ppc_r0, ppc_xer);
3790 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3791 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3793 case OP_IMUL_OVF_UN:
3794 CASE_PPC64 (OP_LMUL_OVF_UN)
3795 /* we first multiply to get the high word and compare to 0
3796 * to set the flags, then the result is discarded and then
3797 * we multiply to get the lower * bits result
3799 if (ins->opcode == OP_IMUL_OVF_UN)
3800 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3801 #ifdef __mono_ppc64__
3803 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3805 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3806 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3807 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3810 CASE_PPC64 (OP_I8CONST)
3811 ppc_load (code, ins->dreg, ins->inst_c0);
3813 case OP_LOAD_GOTADDR:
3814 /* The PLT implementation depends on this */
3815 g_assert (ins->dreg == ppc_r30);
3817 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3820 // FIXME: Fix max instruction length
3821 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3822 /* arch_emit_got_access () patches this */
3823 ppc_load32 (code, ppc_r0, 0);
3824 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3827 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3828 ppc_load_sequence (code, ins->dreg, 0);
3830 CASE_PPC32 (OP_ICONV_TO_I4)
3831 CASE_PPC32 (OP_ICONV_TO_U4)
3833 ppc_mr (code, ins->dreg, ins->sreg1);
3836 int saved = ins->sreg1;
3837 if (ins->sreg1 == ppc_r3) {
3838 ppc_mr (code, ppc_r0, ins->sreg1);
3841 if (ins->sreg2 != ppc_r3)
3842 ppc_mr (code, ppc_r3, ins->sreg2);
3843 if (saved != ppc_r4)
3844 ppc_mr (code, ppc_r4, saved);
3848 ppc_fmr (code, ins->dreg, ins->sreg1);
3850 case OP_FCONV_TO_R4:
3851 ppc_frsp (code, ins->dreg, ins->sreg1);
3857 * Keep in sync with mono_arch_emit_epilog
3859 g_assert (!cfg->method->save_lmf);
3861 * Note: we can use ppc_r11 here because it is dead anyway:
3862 * we're leaving the method.
3864 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3865 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3866 if (ppc_is_imm16 (ret_offset)) {
3867 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3869 ppc_load (code, ppc_r11, ret_offset);
3870 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3872 ppc_mtlr (code, ppc_r0);
3875 code = emit_load_volatile_arguments (cfg, code);
3877 if (ppc_is_imm16 (cfg->stack_usage)) {
3878 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3880 /* cfg->stack_usage is an int, so we can use
3881 * an addis/addi sequence here even in 64-bit. */
3882 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3883 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3885 if (!cfg->method->save_lmf) {
3886 /*for (i = 31; i >= 14; --i) {
3887 if (cfg->used_float_regs & (1 << i)) {
3888 pos += sizeof (double);
3889 ppc_lfd (code, i, -pos, cfg->frame_reg);
3893 for (i = 31; i >= 13; --i) {
3894 if (cfg->used_int_regs & (1 << i)) {
3895 pos += sizeof (gpointer);
3896 ppc_ldptr (code, i, -pos, ppc_r11);
3900 /* FIXME restore from MonoLMF: though this can't happen yet */
3902 ppc_mr (code, ppc_sp, ppc_r11);
3903 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3904 if (cfg->compile_aot) {
3905 /* arch_emit_got_access () patches this */
3906 ppc_load32 (code, ppc_r0, 0);
3907 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3908 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3909 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3911 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3913 ppc_mtctr (code, ppc_r0);
3914 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3921 /* ensure ins->sreg1 is not NULL */
3922 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3925 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3926 if (ppc_is_imm16 (cookie_offset)) {
3927 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3929 ppc_load (code, ppc_r0, cookie_offset);
3930 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3932 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3941 call = (MonoCallInst*)ins;
3942 if (ins->flags & MONO_INST_HAS_METHOD)
3943 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3945 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3946 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3947 ppc_load_func (code, ppc_r0, 0);
3948 ppc_mtlr (code, ppc_r0);
3953 /* FIXME: this should be handled somewhere else in the new jit */
3954 code = emit_move_return_value (cfg, ins, code);
3960 case OP_VOIDCALL_REG:
3962 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3963 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3964 /* FIXME: if we know that this is a method, we
3965 can omit this load */
3966 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3967 ppc_mtlr (code, ppc_r0);
3969 ppc_mtlr (code, ins->sreg1);
3972 /* FIXME: this should be handled somewhere else in the new jit */
3973 code = emit_move_return_value (cfg, ins, code);
3975 case OP_FCALL_MEMBASE:
3976 case OP_LCALL_MEMBASE:
3977 case OP_VCALL_MEMBASE:
3978 case OP_VCALL2_MEMBASE:
3979 case OP_VOIDCALL_MEMBASE:
3980 case OP_CALL_MEMBASE:
3981 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3982 ppc_mtlr (code, ppc_r0);
3984 /* FIXME: this should be handled somewhere else in the new jit */
3985 code = emit_move_return_value (cfg, ins, code);
3988 guint8 * zero_loop_jump, * zero_loop_start;
3989 /* keep alignment */
3990 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3991 int area_offset = alloca_waste;
3993 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3994 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3995 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3996 /* use ctr to store the number of words to 0 if needed */
3997 if (ins->flags & MONO_INST_INIT) {
3998 /* we zero 4 bytes at a time:
3999 * we add 7 instead of 3 so that we set the counter to
4000 * at least 1, otherwise the bdnz instruction will make
4001 * it negative and iterate billions of times.
4003 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4004 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4005 ppc_mtctr (code, ppc_r0);
4007 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4008 ppc_neg (code, ppc_r11, ppc_r11);
4009 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4011 /* FIXME: make this loop work in 8 byte
4012 increments on PPC64 */
4013 if (ins->flags & MONO_INST_INIT) {
4014 /* adjust the dest reg by -4 so we can use stwu */
4015 /* we actually adjust -8 because we let the loop
4018 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4019 ppc_li (code, ppc_r11, 0);
4020 zero_loop_start = code;
4021 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4022 zero_loop_jump = code;
4023 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4024 ppc_patch (zero_loop_jump, zero_loop_start);
4026 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4031 ppc_mr (code, ppc_r3, ins->sreg1);
4032 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4033 (gpointer)"mono_arch_throw_exception");
4034 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4035 ppc_load_func (code, ppc_r0, 0);
4036 ppc_mtlr (code, ppc_r0);
4045 ppc_mr (code, ppc_r3, ins->sreg1);
4046 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4047 (gpointer)"mono_arch_rethrow_exception");
4048 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4049 ppc_load_func (code, ppc_r0, 0);
4050 ppc_mtlr (code, ppc_r0);
4057 case OP_START_HANDLER: {
4058 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4059 g_assert (spvar->inst_basereg != ppc_sp);
4060 code = emit_reserve_param_area (cfg, code);
4061 ppc_mflr (code, ppc_r0);
4062 if (ppc_is_imm16 (spvar->inst_offset)) {
4063 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4065 ppc_load (code, ppc_r11, spvar->inst_offset);
4066 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4070 case OP_ENDFILTER: {
4071 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4072 g_assert (spvar->inst_basereg != ppc_sp);
4073 code = emit_unreserve_param_area (cfg, code);
4074 if (ins->sreg1 != ppc_r3)
4075 ppc_mr (code, ppc_r3, ins->sreg1);
4076 if (ppc_is_imm16 (spvar->inst_offset)) {
4077 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4079 ppc_load (code, ppc_r11, spvar->inst_offset);
4080 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4082 ppc_mtlr (code, ppc_r0);
4086 case OP_ENDFINALLY: {
4087 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4088 g_assert (spvar->inst_basereg != ppc_sp);
4089 code = emit_unreserve_param_area (cfg, code);
4090 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4091 ppc_mtlr (code, ppc_r0);
4095 case OP_CALL_HANDLER:
4096 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4100 ins->inst_c0 = code - cfg->native_code;
4103 /*if (ins->inst_target_bb->native_offset) {
4105 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4107 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4112 ppc_mtctr (code, ins->sreg1);
4113 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4117 CASE_PPC64 (OP_LCEQ)
4118 ppc_li (code, ins->dreg, 0);
4119 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4120 ppc_li (code, ins->dreg, 1);
4126 CASE_PPC64 (OP_LCLT)
4127 CASE_PPC64 (OP_LCLT_UN)
4128 ppc_li (code, ins->dreg, 1);
4129 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4130 ppc_li (code, ins->dreg, 0);
4136 CASE_PPC64 (OP_LCGT)
4137 CASE_PPC64 (OP_LCGT_UN)
4138 ppc_li (code, ins->dreg, 1);
4139 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4140 ppc_li (code, ins->dreg, 0);
4142 case OP_COND_EXC_EQ:
4143 case OP_COND_EXC_NE_UN:
4144 case OP_COND_EXC_LT:
4145 case OP_COND_EXC_LT_UN:
4146 case OP_COND_EXC_GT:
4147 case OP_COND_EXC_GT_UN:
4148 case OP_COND_EXC_GE:
4149 case OP_COND_EXC_GE_UN:
4150 case OP_COND_EXC_LE:
4151 case OP_COND_EXC_LE_UN:
4152 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4154 case OP_COND_EXC_IEQ:
4155 case OP_COND_EXC_INE_UN:
4156 case OP_COND_EXC_ILT:
4157 case OP_COND_EXC_ILT_UN:
4158 case OP_COND_EXC_IGT:
4159 case OP_COND_EXC_IGT_UN:
4160 case OP_COND_EXC_IGE:
4161 case OP_COND_EXC_IGE_UN:
4162 case OP_COND_EXC_ILE:
4163 case OP_COND_EXC_ILE_UN:
4164 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4176 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4179 /* floating point opcodes */
4181 g_assert (cfg->compile_aot);
4183 /* FIXME: Optimize this */
4185 ppc_mflr (code, ppc_r11);
4187 *(double*)code = *(double*)ins->inst_p0;
4189 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4192 g_assert_not_reached ();
4194 case OP_STORER8_MEMBASE_REG:
4195 if (ppc_is_imm16 (ins->inst_offset)) {
4196 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4198 if (ppc_is_imm32 (ins->inst_offset)) {
4199 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4200 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4202 ppc_load (code, ppc_r0, ins->inst_offset);
4203 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4207 case OP_LOADR8_MEMBASE:
4208 if (ppc_is_imm16 (ins->inst_offset)) {
4209 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4211 if (ppc_is_imm32 (ins->inst_offset)) {
4212 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4213 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4215 ppc_load (code, ppc_r0, ins->inst_offset);
4216 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4220 case OP_STORER4_MEMBASE_REG:
4221 ppc_frsp (code, ins->sreg1, ins->sreg1);
4222 if (ppc_is_imm16 (ins->inst_offset)) {
4223 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4225 if (ppc_is_imm32 (ins->inst_offset)) {
4226 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4227 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4229 ppc_load (code, ppc_r0, ins->inst_offset);
4230 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4234 case OP_LOADR4_MEMBASE:
4235 if (ppc_is_imm16 (ins->inst_offset)) {
4236 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4238 if (ppc_is_imm32 (ins->inst_offset)) {
4239 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4240 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4242 ppc_load (code, ppc_r0, ins->inst_offset);
4243 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4247 case OP_LOADR4_MEMINDEX:
4248 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4250 case OP_LOADR8_MEMINDEX:
4251 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4253 case OP_STORER4_MEMINDEX:
4254 ppc_frsp (code, ins->sreg1, ins->sreg1);
4255 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4257 case OP_STORER8_MEMINDEX:
4258 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4261 case CEE_CONV_R4: /* FIXME: change precision */
4263 g_assert_not_reached ();
4264 case OP_FCONV_TO_I1:
4265 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4267 case OP_FCONV_TO_U1:
4268 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4270 case OP_FCONV_TO_I2:
4271 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4273 case OP_FCONV_TO_U2:
4274 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4276 case OP_FCONV_TO_I4:
4278 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4280 case OP_FCONV_TO_U4:
4282 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4284 case OP_LCONV_TO_R_UN:
4285 g_assert_not_reached ();
4286 /* Implemented as helper calls */
4288 case OP_LCONV_TO_OVF_I4_2:
4289 case OP_LCONV_TO_OVF_I: {
4290 #ifdef __mono_ppc64__
4293 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4294 // Check if its negative
4295 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4296 negative_branch = code;
4297 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4298 // Its positive msword == 0
4299 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4300 msword_positive_branch = code;
4301 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4303 ovf_ex_target = code;
4304 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4306 ppc_patch (negative_branch, code);
4307 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4308 msword_negative_branch = code;
4309 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4310 ppc_patch (msword_negative_branch, ovf_ex_target);
4312 ppc_patch (msword_positive_branch, code);
4313 if (ins->dreg != ins->sreg1)
4314 ppc_mr (code, ins->dreg, ins->sreg1);
4319 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4322 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4325 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4328 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4331 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4334 ppc_fneg (code, ins->dreg, ins->sreg1);
4338 g_assert_not_reached ();
4341 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4344 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4345 ppc_li (code, ins->dreg, 0);
4346 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4347 ppc_li (code, ins->dreg, 1);
4350 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4351 ppc_li (code, ins->dreg, 1);
4352 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4353 ppc_li (code, ins->dreg, 0);
4356 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4357 ppc_li (code, ins->dreg, 1);
4358 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4359 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4360 ppc_li (code, ins->dreg, 0);
4363 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4364 ppc_li (code, ins->dreg, 1);
4365 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4366 ppc_li (code, ins->dreg, 0);
4369 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4370 ppc_li (code, ins->dreg, 1);
4371 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4372 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4373 ppc_li (code, ins->dreg, 0);
4376 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4379 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4382 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4383 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4386 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4387 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4390 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4391 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4394 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4395 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4398 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4399 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4402 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4405 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4406 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4409 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4412 g_assert_not_reached ();
4413 case OP_CHECK_FINITE: {
4414 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4415 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4416 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4417 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4420 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4421 #ifdef __mono_ppc64__
4422 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0f0f0f0f0fL);
4424 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4429 #ifdef __mono_ppc64__
4430 case OP_ICONV_TO_I4:
4432 ppc_extsw (code, ins->dreg, ins->sreg1);
4434 case OP_ICONV_TO_U4:
4436 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4438 case OP_ICONV_TO_R4:
4439 case OP_ICONV_TO_R8:
4440 case OP_LCONV_TO_R4:
4441 case OP_LCONV_TO_R8: {
4443 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4444 ppc_extsw (code, ppc_r0, ins->sreg1);
4449 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4450 ppc_mffgpr (code, ins->dreg, tmp);
4452 ppc_stptr (code, tmp, -8, ppc_r1);
4453 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4455 ppc_fcfid (code, ins->dreg, ins->dreg);
4456 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4457 ppc_frsp (code, ins->dreg, ins->dreg);
4461 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4464 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4467 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4469 ppc_mfspr (code, ppc_r0, ppc_xer);
4470 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4471 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4473 case OP_COND_EXC_OV:
4474 ppc_mfspr (code, ppc_r0, ppc_xer);
4475 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4476 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4488 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4490 case OP_FCONV_TO_I8:
4491 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4493 case OP_FCONV_TO_U8:
4494 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4496 case OP_STOREI4_MEMBASE_REG:
4497 if (ppc_is_imm16 (ins->inst_offset)) {
4498 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4500 ppc_load (code, ppc_r0, ins->inst_offset);
4501 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4504 case OP_STOREI4_MEMINDEX:
4505 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4508 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4510 case OP_ISHR_UN_IMM:
4511 if (ins->inst_imm & 0x1f)
4512 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4514 ppc_mr (code, ins->dreg, ins->sreg1);
4516 case OP_ATOMIC_ADD_NEW_I4:
4517 case OP_ATOMIC_ADD_NEW_I8: {
4518 guint8 *loop = code, *branch;
4519 g_assert (ins->inst_offset == 0);
4520 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4521 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4523 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4524 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4525 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4526 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4528 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4530 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4531 ppc_patch (branch, loop);
4532 ppc_mr (code, ins->dreg, ppc_r0);
4536 case OP_ICONV_TO_R4:
4537 case OP_ICONV_TO_R8: {
4538 if (cpu_hw_caps & PPC_ISA_64) {
4539 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4540 ppc_stw (code, ppc_r0, -8, ppc_r1);
4541 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4542 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4543 ppc_fcfid (code, ins->dreg, ins->dreg);
4544 if (ins->opcode == OP_ICONV_TO_R4)
4545 ppc_frsp (code, ins->dreg, ins->dreg);
4550 case OP_ATOMIC_CAS_I4:
4551 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4552 int location = ins->sreg1;
4553 int value = ins->sreg2;
4554 int comparand = ins->sreg3;
4555 guint8 *start, *not_equal, *lost_reservation;
4558 if (ins->opcode == OP_ATOMIC_CAS_I4)
4559 ppc_lwarx (code, ppc_r0, 0, location);
4560 #ifdef __mono_ppc64__
4562 ppc_ldarx (code, ppc_r0, 0, location);
4564 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4567 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4568 if (ins->opcode == OP_ATOMIC_CAS_I4)
4569 ppc_stwcxd (code, value, 0, location);
4570 #ifdef __mono_ppc64__
4572 ppc_stdcxd (code, value, 0, location);
4575 lost_reservation = code;
4576 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4577 ppc_patch (lost_reservation, start);
4579 ppc_patch (not_equal, code);
4580 ppc_mr (code, ins->dreg, ppc_r0);
4585 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4586 g_assert_not_reached ();
4589 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4590 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4591 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4592 g_assert_not_reached ();
4598 last_offset = offset;
4601 cfg->code_len = code - cfg->native_code;
4605 mono_arch_register_lowlevel_calls (void)
4607 /* The signature doesn't matter */
4608 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4611 #ifdef __mono_ppc64__
4612 #define patch_load_sequence(ip,val) do {\
4613 guint16 *__load = (guint16*)(ip); \
4614 __load [1] = (((guint64)(val)) >> 48) & 0xffff; \
4615 __load [3] = (((guint64)(val)) >> 32) & 0xffff; \
4616 __load [7] = (((guint64)(val)) >> 16) & 0xffff; \
4617 __load [9] = ((guint64)(val)) & 0xffff; \
4620 #define patch_load_sequence(ip,val) do {\
4621 guint16 *__lis_ori = (guint16*)(ip); \
4622 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4623 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4628 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4630 MonoJumpInfo *patch_info;
4631 gboolean compile_aot = !run_cctors;
4633 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4634 unsigned char *ip = patch_info->ip.i + code;
4635 unsigned char *target;
4636 gboolean is_fd = FALSE;
4638 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4641 switch (patch_info->type) {
4642 case MONO_PATCH_INFO_BB:
4643 case MONO_PATCH_INFO_LABEL:
4646 /* No need to patch these */
4651 switch (patch_info->type) {
4652 case MONO_PATCH_INFO_IP:
4653 patch_load_sequence (ip, ip);
4655 case MONO_PATCH_INFO_METHOD_REL:
4656 g_assert_not_reached ();
4657 *((gpointer *)(ip)) = code + patch_info->data.offset;
4659 case MONO_PATCH_INFO_SWITCH: {
4660 gpointer *table = (gpointer *)patch_info->data.table->table;
4663 patch_load_sequence (ip, table);
4665 for (i = 0; i < patch_info->data.table->table_size; i++) {
4666 table [i] = (glong)patch_info->data.table->table [i] + code;
4668 /* we put into the table the absolute address, no need for ppc_patch in this case */
4671 case MONO_PATCH_INFO_METHODCONST:
4672 case MONO_PATCH_INFO_CLASS:
4673 case MONO_PATCH_INFO_IMAGE:
4674 case MONO_PATCH_INFO_FIELD:
4675 case MONO_PATCH_INFO_VTABLE:
4676 case MONO_PATCH_INFO_IID:
4677 case MONO_PATCH_INFO_SFLDA:
4678 case MONO_PATCH_INFO_LDSTR:
4679 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4680 case MONO_PATCH_INFO_LDTOKEN:
4681 /* from OP_AOTCONST : lis + ori */
4682 patch_load_sequence (ip, target);
4684 case MONO_PATCH_INFO_R4:
4685 case MONO_PATCH_INFO_R8:
4686 g_assert_not_reached ();
4687 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4689 case MONO_PATCH_INFO_EXC_NAME:
4690 g_assert_not_reached ();
4691 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4693 case MONO_PATCH_INFO_NONE:
4694 case MONO_PATCH_INFO_BB_OVF:
4695 case MONO_PATCH_INFO_EXC_OVF:
4696 /* everything is dealt with at epilog output time */
4698 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4699 case MONO_PATCH_INFO_INTERNAL_METHOD:
4700 case MONO_PATCH_INFO_ABS:
4701 case MONO_PATCH_INFO_CLASS_INIT:
4702 case MONO_PATCH_INFO_RGCTX_FETCH:
4709 ppc_patch_full (ip, target, is_fd);
4714 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4715 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4716 * the instruction offset immediate for all the registers.
4719 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4723 for (i = 13; i <= 31; i++) {
4724 if (used_int_regs & (1 << i)) {
4725 ppc_str (code, i, pos, base_reg);
4726 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4727 pos += sizeof (mgreg_t);
4731 /* pos is the start of the MonoLMF structure */
4732 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4733 for (i = 13; i <= 31; i++) {
4734 ppc_str (code, i, offset, base_reg);
4735 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4736 offset += sizeof (mgreg_t);
4738 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4739 for (i = 14; i < 32; i++) {
4740 ppc_stfd (code, i, offset, base_reg);
4741 offset += sizeof (gdouble);
4748 * Stack frame layout:
4750 * ------------------- sp
4751 * MonoLMF structure or saved registers
4752 * -------------------
4754 * -------------------
4756 * -------------------
4757 * optional 8 bytes for tracing
4758 * -------------------
4759 * param area size is cfg->param_area
4760 * -------------------
4761 * linkage area size is PPC_STACK_PARAM_OFFSET
4762 * ------------------- sp
4766 mono_arch_emit_prolog (MonoCompile *cfg)
4768 MonoMethod *method = cfg->method;
4770 MonoMethodSignature *sig;
4772 long alloc_size, pos, max_offset, cfa_offset;
4778 int tailcall_struct_index;
4780 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4783 sig = mono_method_signature (method);
4784 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4785 code = cfg->native_code = g_malloc (cfg->code_size);
4789 /* We currently emit unwind info for aot, but don't use it */
4790 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4792 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4793 ppc_mflr (code, ppc_r0);
4794 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4796 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4799 alloc_size = cfg->stack_offset;
4802 if (!method->save_lmf) {
4803 for (i = 31; i >= 13; --i) {
4804 if (cfg->used_int_regs & (1 << i)) {
4805 pos += sizeof (gulong);
4809 pos += sizeof (MonoLMF);
4813 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4814 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4815 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4816 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4819 cfg->stack_usage = alloc_size;
4820 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4822 if (ppc_is_imm16 (-alloc_size)) {
4823 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4824 cfa_offset = alloc_size;
4825 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4826 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4829 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4830 ppc_load (code, ppc_r0, -alloc_size);
4831 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4832 cfa_offset = alloc_size;
4833 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4834 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4837 if (cfg->frame_reg != ppc_sp) {
4838 ppc_mr (code, cfg->frame_reg, ppc_sp);
4839 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4842 /* store runtime generic context */
4843 if (cfg->rgctx_var) {
4844 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4845 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4847 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4850 /* compute max_offset in order to use short forward jumps
4851 * we always do it on ppc because the immediate displacement
4852 * for jumps is too small
4855 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4857 bb->max_offset = max_offset;
4859 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4862 MONO_BB_FOR_EACH_INS (bb, ins)
4863 max_offset += ins_native_length (cfg, ins);
4866 /* load arguments allocated to register from the stack */
4869 cinfo = calculate_sizes (sig, sig->pinvoke);
4871 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4872 ArgInfo *ainfo = &cinfo->ret;
4874 inst = cfg->vret_addr;
4877 if (ppc_is_imm16 (inst->inst_offset)) {
4878 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4880 ppc_load (code, ppc_r11, inst->inst_offset);
4881 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4885 tailcall_struct_index = 0;
4886 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4887 ArgInfo *ainfo = cinfo->args + i;
4888 inst = cfg->args [pos];
4890 if (cfg->verbose_level > 2)
4891 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4892 if (inst->opcode == OP_REGVAR) {
4893 if (ainfo->regtype == RegTypeGeneral)
4894 ppc_mr (code, inst->dreg, ainfo->reg);
4895 else if (ainfo->regtype == RegTypeFP)
4896 ppc_fmr (code, inst->dreg, ainfo->reg);
4897 else if (ainfo->regtype == RegTypeBase) {
4898 ppc_ldptr (code, ppc_r11, 0, ppc_sp);
4899 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4901 g_assert_not_reached ();
4903 if (cfg->verbose_level > 2)
4904 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4906 /* the argument should be put on the stack: FIXME handle size != word */
4907 if (ainfo->regtype == RegTypeGeneral) {
4908 switch (ainfo->size) {
4910 if (ppc_is_imm16 (inst->inst_offset)) {
4911 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4913 if (ppc_is_imm32 (inst->inst_offset)) {
4914 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4915 ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
4917 ppc_load (code, ppc_r11, inst->inst_offset);
4918 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4923 if (ppc_is_imm16 (inst->inst_offset)) {
4924 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4926 if (ppc_is_imm32 (inst->inst_offset)) {
4927 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4928 ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
4930 ppc_load (code, ppc_r11, inst->inst_offset);
4931 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4935 #ifdef __mono_ppc64__
4937 if (ppc_is_imm16 (inst->inst_offset)) {
4938 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4940 if (ppc_is_imm32 (inst->inst_offset)) {
4941 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4942 ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
4944 ppc_load (code, ppc_r11, inst->inst_offset);
4945 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4951 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4952 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4953 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4955 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4956 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4957 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4958 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4963 if (ppc_is_imm16 (inst->inst_offset)) {
4964 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4966 if (ppc_is_imm32 (inst->inst_offset)) {
4967 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4968 ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
4970 ppc_load (code, ppc_r11, inst->inst_offset);
4971 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4976 } else if (ainfo->regtype == RegTypeBase) {
4977 g_assert (ppc_is_imm16 (ainfo->offset));
4978 /* load the previous stack pointer in r11 */
4979 ppc_ldptr (code, ppc_r11, 0, ppc_sp);
4980 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4981 switch (ainfo->size) {
4983 if (ppc_is_imm16 (inst->inst_offset)) {
4984 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4986 if (ppc_is_imm32 (inst->inst_offset)) {
4987 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4988 ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
4990 ppc_load (code, ppc_r11, inst->inst_offset);
4991 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4996 if (ppc_is_imm16 (inst->inst_offset)) {
4997 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4999 if (ppc_is_imm32 (inst->inst_offset)) {
5000 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5001 ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
5003 ppc_load (code, ppc_r11, inst->inst_offset);
5004 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5008 #ifdef __mono_ppc64__
5010 if (ppc_is_imm16 (inst->inst_offset)) {
5011 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5013 if (ppc_is_imm32 (inst->inst_offset)) {
5014 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5015 ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
5017 ppc_load (code, ppc_r11, inst->inst_offset);
5018 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5024 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5025 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5026 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5027 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5028 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5030 /* use r12 to load the 2nd half of the long before we clobber r11. */
5031 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5032 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5033 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5034 ppc_stw (code, ppc_r0, 0, ppc_r11);
5035 ppc_stw (code, ppc_r12, 4, ppc_r11);
5040 if (ppc_is_imm16 (inst->inst_offset)) {
5041 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5043 if (ppc_is_imm32 (inst->inst_offset)) {
5044 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5045 ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
5047 ppc_load (code, ppc_r11, inst->inst_offset);
5048 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5053 } else if (ainfo->regtype == RegTypeFP) {
5054 g_assert (ppc_is_imm16 (inst->inst_offset));
5055 if (ainfo->size == 8)
5056 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5057 else if (ainfo->size == 4)
5058 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5060 g_assert_not_reached ();
5061 } else if (ainfo->regtype == RegTypeStructByVal) {
5062 int doffset = inst->inst_offset;
5066 g_assert (ppc_is_imm16 (inst->inst_offset));
5067 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5068 /* FIXME: what if there is no class? */
5069 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5070 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5071 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
5074 * Darwin handles 1 and 2 byte
5075 * structs specially by
5076 * loading h/b into the arg
5077 * register. Only done for
5081 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5083 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5087 #ifdef __mono_ppc64__
5089 g_assert (cur_reg == 0);
5090 ppc_sldi (code, ppc_r0, ainfo->reg,
5091 (sizeof (gpointer) - ainfo->bytes) * 8);
5092 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5096 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5097 inst->inst_basereg);
5100 soffset += sizeof (gpointer);
5101 doffset += sizeof (gpointer);
5103 if (ainfo->vtsize) {
5104 /* FIXME: we need to do the shifting here, too */
5107 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5108 ppc_ldptr (code, ppc_r11, 0, ppc_sp);
5109 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5110 code = emit_memcpy (code, size - soffset,
5111 inst->inst_basereg, doffset,
5112 ppc_r11, ainfo->offset + soffset);
5114 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5115 inst->inst_basereg, doffset,
5116 ppc_r11, ainfo->offset + soffset);
5119 } else if (ainfo->regtype == RegTypeStructByAddr) {
5120 /* if it was originally a RegTypeBase */
5121 if (ainfo->offset) {
5122 /* load the previous stack pointer in r11 */
5123 ppc_ldptr (code, ppc_r11, 0, ppc_sp);
5124 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5126 ppc_mr (code, ppc_r11, ainfo->reg);
5129 if (cfg->tailcall_valuetype_addrs) {
5130 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5132 g_assert (ppc_is_imm16 (addr->inst_offset));
5133 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5135 tailcall_struct_index++;
5138 g_assert (ppc_is_imm16 (inst->inst_offset));
5139 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5140 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5142 g_assert_not_reached ();
5147 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5148 ppc_load (code, ppc_r3, cfg->domain);
5149 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5150 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5151 ppc_load_func (code, ppc_r0, 0);
5152 ppc_mtlr (code, ppc_r0);
5159 if (method->save_lmf) {
5160 if (lmf_pthread_key != -1) {
5161 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5162 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5163 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5165 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5166 (gpointer)"mono_get_lmf_addr");
5167 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5168 ppc_load_func (code, ppc_r0, 0);
5169 ppc_mtlr (code, ppc_r0);
5175 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5176 /* lmf_offset is the offset from the previous stack pointer,
5177 * alloc_size is the total stack space allocated, so the offset
5178 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5179 * The pointer to the struct is put in ppc_r11 (new_lmf).
5180 * The callee-saved registers are already in the MonoLMF structure
5182 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5183 /* ppc_r3 is the result from mono_get_lmf_addr () */
5184 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5185 /* new_lmf->previous_lmf = *lmf_addr */
5186 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5187 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5188 /* *(lmf_addr) = r11 */
5189 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5190 /* save method info */
5191 if (cfg->compile_aot)
5193 ppc_load (code, ppc_r0, 0);
5195 ppc_load (code, ppc_r0, method);
5196 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5197 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5198 /* save the current IP */
5199 if (cfg->compile_aot) {
5201 ppc_mflr (code, ppc_r0);
5203 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5204 #ifdef __mono_ppc64__
5205 ppc_load_sequence (code, ppc_r0, (gulong)0x0101010101010101L);
5207 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5210 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5214 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5216 cfg->code_len = code - cfg->native_code;
5217 g_assert (cfg->code_len <= cfg->code_size);
5224 mono_arch_emit_epilog (MonoCompile *cfg)
5226 MonoMethod *method = cfg->method;
5228 int max_epilog_size = 16 + 20*4;
5231 if (cfg->method->save_lmf)
5232 max_epilog_size += 128;
5234 if (mono_jit_trace_calls != NULL)
5235 max_epilog_size += 50;
5237 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5238 max_epilog_size += 50;
5240 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5241 cfg->code_size *= 2;
5242 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5243 mono_jit_stats.code_reallocs++;
5247 * Keep in sync with OP_JMP
5249 code = cfg->native_code + cfg->code_len;
5251 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5252 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5256 if (method->save_lmf) {
5258 pos += sizeof (MonoLMF);
5260 /* save the frame reg in r8 */
5261 ppc_mr (code, ppc_r8, cfg->frame_reg);
5262 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5263 /* r5 = previous_lmf */
5264 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5266 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5267 /* *(lmf_addr) = previous_lmf */
5268 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5269 /* FIXME: speedup: there is no actual need to restore the registers if
5270 * we didn't actually change them (idea from Zoltan).
5273 ppc_load_multiple_regs (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5275 /*for (i = 14; i < 32; i++) {
5276 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5278 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5279 /* use the saved copy of the frame reg in r8 */
5280 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5281 ppc_ldptr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5282 ppc_mtlr (code, ppc_r0);
5284 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5286 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5287 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5288 if (ppc_is_imm16 (return_offset)) {
5289 ppc_ldptr (code, ppc_r0, return_offset, cfg->frame_reg);
5291 ppc_load (code, ppc_r11, return_offset);
5292 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5294 ppc_mtlr (code, ppc_r0);
5296 if (ppc_is_imm16 (cfg->stack_usage)) {
5297 int offset = cfg->stack_usage;
5298 for (i = 13; i <= 31; i++) {
5299 if (cfg->used_int_regs & (1 << i))
5300 offset -= sizeof (gulong);
5302 if (cfg->frame_reg != ppc_sp)
5303 ppc_mr (code, ppc_r11, cfg->frame_reg);
5304 /* note r31 (possibly the frame register) is restored last */
5305 for (i = 13; i <= 31; i++) {
5306 if (cfg->used_int_regs & (1 << i)) {
5307 ppc_ldptr (code, i, offset, cfg->frame_reg);
5308 offset += sizeof (gulong);
5311 if (cfg->frame_reg != ppc_sp)
5312 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5314 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5316 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5317 if (cfg->used_int_regs) {
5318 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5319 for (i = 31; i >= 13; --i) {
5320 if (cfg->used_int_regs & (1 << i)) {
5321 pos += sizeof (gulong);
5322 ppc_ldptr (code, i, -pos, ppc_r11);
5325 ppc_mr (code, ppc_sp, ppc_r11);
5327 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5334 cfg->code_len = code - cfg->native_code;
5336 g_assert (cfg->code_len < cfg->code_size);
5340 /* remove once throw_exception_by_name is eliminated */
5342 exception_id_by_name (const char *name)
5344 if (strcmp (name, "IndexOutOfRangeException") == 0)
5345 return MONO_EXC_INDEX_OUT_OF_RANGE;
5346 if (strcmp (name, "OverflowException") == 0)
5347 return MONO_EXC_OVERFLOW;
5348 if (strcmp (name, "ArithmeticException") == 0)
5349 return MONO_EXC_ARITHMETIC;
5350 if (strcmp (name, "DivideByZeroException") == 0)
5351 return MONO_EXC_DIVIDE_BY_ZERO;
5352 if (strcmp (name, "InvalidCastException") == 0)
5353 return MONO_EXC_INVALID_CAST;
5354 if (strcmp (name, "NullReferenceException") == 0)
5355 return MONO_EXC_NULL_REF;
5356 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5357 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5358 g_error ("Unknown intrinsic exception %s\n", name);
5363 mono_arch_emit_exceptions (MonoCompile *cfg)
5365 MonoJumpInfo *patch_info;
5368 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5369 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5370 int max_epilog_size = 50;
5372 /* count the number of exception infos */
5375 * make sure we have enough space for exceptions
5376 * 28 is the simulated call to throw_corlib_exception
5378 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5379 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5380 i = exception_id_by_name (patch_info->data.target);
5381 if (!exc_throw_found [i]) {
5382 max_epilog_size += 28;
5383 exc_throw_found [i] = TRUE;
5385 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5386 max_epilog_size += 12;
5387 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5388 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5389 i = exception_id_by_name (ovfj->data.exception);
5390 if (!exc_throw_found [i]) {
5391 max_epilog_size += 28;
5392 exc_throw_found [i] = TRUE;
5394 max_epilog_size += 8;
5398 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5399 cfg->code_size *= 2;
5400 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5401 mono_jit_stats.code_reallocs++;
5404 code = cfg->native_code + cfg->code_len;
5406 /* add code to raise exceptions */
5407 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5408 switch (patch_info->type) {
5409 case MONO_PATCH_INFO_BB_OVF: {
5410 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5411 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5412 /* patch the initial jump */
5413 ppc_patch (ip, code);
5414 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5416 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5417 /* jump back to the true target */
5419 ip = ovfj->data.bb->native_offset + cfg->native_code;
5420 ppc_patch (code - 4, ip);
5421 patch_info->type = MONO_PATCH_INFO_NONE;
5424 case MONO_PATCH_INFO_EXC_OVF: {
5425 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5426 MonoJumpInfo *newji;
5427 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5428 unsigned char *bcl = code;
5429 /* patch the initial jump: we arrived here with a call */
5430 ppc_patch (ip, code);
5431 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5433 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5434 /* patch the conditional jump to the right handler */
5435 /* make it processed next */
5436 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5437 newji->type = MONO_PATCH_INFO_EXC;
5438 newji->ip.i = bcl - cfg->native_code;
5439 newji->data.target = ovfj->data.exception;
5440 newji->next = patch_info->next;
5441 patch_info->next = newji;
5442 patch_info->type = MONO_PATCH_INFO_NONE;
5445 case MONO_PATCH_INFO_EXC: {
5446 MonoClass *exc_class;
5448 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5449 i = exception_id_by_name (patch_info->data.target);
5450 if (exc_throw_pos [i]) {
5451 ppc_patch (ip, exc_throw_pos [i]);
5452 patch_info->type = MONO_PATCH_INFO_NONE;
5455 exc_throw_pos [i] = code;
5458 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5459 g_assert (exc_class);
5461 ppc_patch (ip, code);
5462 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5463 ppc_load (code, ppc_r3, exc_class->type_token);
5464 /* we got here from a conditional call, so the calling ip is set in lr */
5465 ppc_mflr (code, ppc_r4);
5466 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5467 patch_info->data.name = "mono_arch_throw_corlib_exception";
5468 patch_info->ip.i = code - cfg->native_code;
5469 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5470 ppc_load_func (code, ppc_r0, 0);
5471 ppc_mtctr (code, ppc_r0);
5472 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5484 cfg->code_len = code - cfg->native_code;
5486 g_assert (cfg->code_len <= cfg->code_size);
5491 try_offset_access (void *value, guint32 idx)
5493 register void* me __asm__ ("r2");
5494 void ***p = (void***)((char*)me + 284);
5495 int idx1 = idx / 32;
5496 int idx2 = idx % 32;
5499 if (value != p[idx1][idx2])
5506 setup_tls_access (void)
5510 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5511 size_t conf_size = 0;
5514 /* FIXME for darwin */
5515 guint32 *ins, *code;
5516 guint32 cmplwi_1023, li_0x48, blr_ins;
5519 if (tls_mode == TLS_MODE_FAILED)
5521 if (g_getenv ("MONO_NO_TLS")) {
5522 tls_mode = TLS_MODE_FAILED;
5526 if (tls_mode == TLS_MODE_DETECT) {
5527 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5528 tls_mode = TLS_MODE_DARWIN_G4;
5529 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5530 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5531 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5532 tls_mode = TLS_MODE_NPTL;
5534 ins = (guint32*)pthread_getspecific;
5535 /* uncond branch to the real method */
5536 if ((*ins >> 26) == 18) {
5538 val = (*ins & ~3) << 6;
5542 ins = (guint32*)(long)val;
5544 ins = (guint32*) ((char*)ins + val);
5547 code = &cmplwi_1023;
5548 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5550 ppc_li (code, ppc_r4, 0x48);
5553 if (*ins == cmplwi_1023) {
5554 int found_lwz_284 = 0;
5555 for (ptk = 0; ptk < 20; ++ptk) {
5557 if (!*ins || *ins == blr_ins)
5559 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5564 if (!found_lwz_284) {
5565 tls_mode = TLS_MODE_FAILED;
5568 tls_mode = TLS_MODE_LTHREADS;
5569 } else if (*ins == li_0x48) {
5571 /* uncond branch to the real method */
5572 if ((*ins >> 26) == 18) {
5574 val = (*ins & ~3) << 6;
5578 ins = (guint32*)(long)val;
5580 ins = (guint32*) ((char*)ins + val);
5582 code = (guint32*)&val;
5583 ppc_li (code, ppc_r0, 0x7FF2);
5584 if (ins [1] == val) {
5585 /* Darwin on G4, implement */
5586 tls_mode = TLS_MODE_FAILED;
5589 code = (guint32*)&val;
5590 ppc_mfspr (code, ppc_r3, 104);
5591 if (ins [1] != val) {
5592 tls_mode = TLS_MODE_FAILED;
5595 tls_mode = TLS_MODE_DARWIN_G5;
5598 tls_mode = TLS_MODE_FAILED;
5602 tls_mode = TLS_MODE_FAILED;
5607 if (tls_mode == TLS_MODE_DETECT)
5608 tls_mode = TLS_MODE_FAILED;
5609 if (tls_mode == TLS_MODE_FAILED)
5611 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5612 monodomain_key = mono_domain_get_tls_offset();
5614 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5615 mono_domain_get_tls_offset returning -1) then use keyed access. */
5616 if (monodomain_key == -1) {
5617 ptk = mono_domain_get_tls_key ();
5619 ptk = mono_pthread_key_for_tls (ptk);
5621 monodomain_key = ptk;
5626 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5627 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5629 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5630 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5631 if (lmf_pthread_key == -1) {
5632 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5634 /*g_print ("MonoLMF at: %d\n", ptk);*/
5635 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5636 init_tls_failed = 1;
5639 lmf_pthread_key = ptk;
5643 if ((monothread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5644 monothread_key = mono_thread_get_tls_offset();
5646 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5647 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5648 if (monothread_key == -1) {
5649 ptk = mono_thread_get_tls_key ();
5651 ptk = mono_pthread_key_for_tls (ptk);
5653 monothread_key = ptk;
5654 /*g_print ("thread inited: %d\n", ptk);*/
5657 /*g_print ("thread not inited yet %d\n", ptk);*/
5663 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5665 setup_tls_access ();
5669 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5673 #ifdef MONO_ARCH_HAVE_IMT
5675 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5677 #define LOADSTORE_SIZE 4
5678 #define JUMP_IMM_SIZE 12
5679 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5680 #define ENABLE_WRONG_METHOD_CHECK 0
5683 * LOCKING: called with the domain lock held
5686 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5687 gpointer fail_tramp)
5691 guint8 *code, *start;
5693 for (i = 0; i < count; ++i) {
5694 MonoIMTCheckItem *item = imt_entries [i];
5695 if (item->is_equals) {
5696 if (item->check_target_idx) {
5697 if (!item->compare_done)
5698 item->chunk_size += CMP_SIZE;
5699 if (item->has_target_code)
5700 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5702 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5705 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5706 if (!item->has_target_code)
5707 item->chunk_size += LOADSTORE_SIZE;
5709 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5710 #if ENABLE_WRONG_METHOD_CHECK
5711 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5716 item->chunk_size += CMP_SIZE + BR_SIZE;
5717 imt_entries [item->check_target_idx]->compare_done = TRUE;
5719 size += item->chunk_size;
5722 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5724 /* the initial load of the vtable address */
5725 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5726 code = mono_domain_code_reserve (domain, size);
5731 * We need to save and restore r11 because it might be
5732 * used by the caller as the vtable register, so
5733 * clobbering it will trip up the magic trampoline.
5735 * FIXME: Get rid of this by making sure that r11 is
5736 * not used as the vtable register in interface calls.
5738 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5739 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5741 for (i = 0; i < count; ++i) {
5742 MonoIMTCheckItem *item = imt_entries [i];
5743 item->code_target = code;
5744 if (item->is_equals) {
5745 if (item->check_target_idx) {
5746 if (!item->compare_done) {
5747 ppc_load (code, ppc_r0, (gsize)item->key);
5748 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5750 item->jmp_code = code;
5751 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5752 if (item->has_target_code) {
5753 ppc_load (code, ppc_r0, item->value.target_code);
5755 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5756 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5758 ppc_mtctr (code, ppc_r0);
5759 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5762 ppc_load (code, ppc_r0, (gulong)item->key);
5763 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5764 item->jmp_code = code;
5765 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5766 if (item->has_target_code) {
5767 ppc_load (code, ppc_r0, item->value.target_code);
5770 ppc_load (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5771 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5773 ppc_mtctr (code, ppc_r0);
5774 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5775 ppc_patch (item->jmp_code, code);
5776 ppc_load (code, ppc_r0, fail_tramp);
5777 ppc_mtctr (code, ppc_r0);
5778 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5779 item->jmp_code = NULL;
5781 /* enable the commented code to assert on wrong method */
5782 #if ENABLE_WRONG_METHOD_CHECK
5783 ppc_load (code, ppc_r0, (guint32)item->key);
5784 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5785 item->jmp_code = code;
5786 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5788 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5789 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5790 ppc_mtctr (code, ppc_r0);
5791 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5792 #if ENABLE_WRONG_METHOD_CHECK
5793 ppc_patch (item->jmp_code, code);
5795 item->jmp_code = NULL;
5800 ppc_load (code, ppc_r0, (gulong)item->key);
5801 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5802 item->jmp_code = code;
5803 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5806 /* patch the branches to get to the target items */
5807 for (i = 0; i < count; ++i) {
5808 MonoIMTCheckItem *item = imt_entries [i];
5809 if (item->jmp_code) {
5810 if (item->check_target_idx) {
5811 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5817 mono_stats.imt_thunks_size += code - start;
5818 g_assert (code - start <= size);
5819 mono_arch_flush_icache (start, size);
5824 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5826 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5830 mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5832 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), regs, NULL);
5837 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5839 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5843 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5850 mono_arch_print_tree (MonoInst *tree, int arity)
5855 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5859 setup_tls_access ();
5860 if (monodomain_key == -1)
5863 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5864 ins->inst_offset = monodomain_key;
5869 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5873 setup_tls_access ();
5874 if (monothread_key == -1)
5877 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5878 ins->inst_offset = monothread_key;
5883 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5886 return MONO_CONTEXT_GET_SP (ctx);
5888 g_assert (reg >= ppc_r13);
5890 return (gpointer)ctx->regs [reg - ppc_r13];
5894 mono_arch_get_patch_offset (guint8 *code)
5900 * mono_aot_emit_load_got_addr:
5902 * Emit code to load the got address.
5903 * On PPC, the result is placed into r30.
5906 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5909 ppc_mflr (code, ppc_r30);
5911 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5913 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5914 /* arch_emit_got_address () patches this */
5915 #if defined(TARGET_POWERPC64)
5921 ppc_load32 (code, ppc_r0, 0);
5922 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5929 * mono_ppc_emit_load_aotconst:
5931 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5932 * TARGET from the mscorlib GOT in full-aot code.
5933 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5937 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5939 /* Load the mscorlib got address */
5940 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5941 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5942 /* arch_emit_got_access () patches this */
5943 ppc_load32 (code, ppc_r0, 0);
5944 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);