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>
18 #include <mono/utils/mono-mmap.h>
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
29 #include <sys/sysctl.h>
35 #define FORCE_INDIR_CALL 1
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps = 0;
48 static int cachelinesize = 0;
49 static int cachelineinc = 0;
51 PPC_ICACHE_SNOOP = 1 << 0,
52 PPC_MULTIPLE_LS_UNITS = 1 << 1,
53 PPC_SMP_CAPABLE = 1 << 2,
56 PPC_MOVE_FPR_GPR = 1 << 5,
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex;
67 int mono_exc_esp_offset = 0;
68 static int tls_mode = TLS_MODE_DETECT;
69 static int lmf_pthread_key = -1;
70 static int monodomain_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
82 offsets_from_pthread_key (guint32 key, int *offset2)
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
161 if (reg >= 0 && reg < 32)
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
177 if (reg >= 0 && reg < 32)
182 /* this function overwrites r0, r11, r12 */
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 //g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
283 int k, frame_size = 0;
284 int size, align, pad;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
292 arg_info [0].offset = offset;
295 frame_size += sizeof (gpointer);
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
317 arg_info [k + 1].offset = offset;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
329 #ifdef __mono_ppc64__
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
349 mono_ppc_is_direct_call_sequence (guint32 *code)
351 #ifdef __mono_ppc64__
352 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
357 if (!is_load_sequence (&code [-8]))
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
361 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
363 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code [-8]);
366 return is_load_sequence (&code [-6]);
370 g_assert(*code == 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code [-1]) == 31 &&
374 ppc_opcode (code [-2]) == 24 &&
375 ppc_opcode (code [-3]) == 15;
379 #define MAX_ARCH_DELEGATE_PARAMS 7
382 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
384 guint8 *code, *start;
387 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
389 start = code = mono_global_codeman_reserve (size);
391 code = mono_ppc_create_pre_code_ftnptr (code);
393 /* Replace the this argument with the target */
394 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
395 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
396 /* it's a function descriptor */
397 /* Can't use ldptr as it doesn't work with r0 */
398 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
400 ppc_mtctr (code, ppc_r0);
401 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
402 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
404 g_assert ((code - start) <= size);
406 mono_arch_flush_icache (start, size);
410 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
411 start = code = mono_global_codeman_reserve (size);
413 code = mono_ppc_create_pre_code_ftnptr (code);
415 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
417 /* it's a function descriptor */
418 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
420 ppc_mtctr (code, ppc_r0);
421 /* slide down the arguments */
422 for (i = 0; i < param_count; ++i) {
423 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
425 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
427 g_assert ((code - start) <= size);
429 mono_arch_flush_icache (start, size);
433 *code_len = code - start;
439 mono_arch_get_delegate_invoke_impls (void)
446 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
447 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
449 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
450 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
451 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
458 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
460 guint8 *code, *start;
462 /* FIXME: Support more cases */
463 if (MONO_TYPE_ISSTRUCT (sig->ret))
467 static guint8* cached = NULL;
473 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
475 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
477 mono_memory_barrier ();
481 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
484 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
486 for (i = 0; i < sig->param_count; ++i)
487 if (!mono_is_regsize_var (sig->params [i]))
491 code = cache [sig->param_count];
496 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
497 start = mono_aot_get_trampoline (name);
500 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
503 mono_memory_barrier ();
505 cache [sig->param_count] = start;
511 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
513 mgreg_t *r = (mgreg_t*)regs;
515 return (gpointer)(gsize)r [ppc_r3];
523 #ifdef USE_ENVIRON_HACK
525 linux_find_auxv (int *count)
529 char **result = __environ;
530 /* Scan over the env vector looking for the ending NULL */
531 for (; *result != NULL; ++result) {
533 /* Bump the pointer one more step, which should be the auxv. */
535 vec = (AuxVec *)result;
536 if (vec->type != 22 /*AT_IGNOREPPC*/) {
540 while (vec->type != 0 /*AT_NULL*/) {
545 return (AuxVec *)result;
549 #define MAX_AUX_ENTRIES 128
551 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
552 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
554 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
556 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
557 #define ISA_64 0x40000000
559 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
560 #define ISA_MOVE_FPR_GPR 0x00000200
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
570 * Initialize architecture specific code.
573 mono_arch_init (void)
575 #if defined(MONO_CROSS_COMPILE)
576 #elif defined(__APPLE__)
580 mib [1] = HW_CACHELINE;
581 len = sizeof (cachelinesize);
582 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
586 cachelineinc = cachelinesize;
588 #elif defined(__linux__)
589 AuxVec vec [MAX_AUX_ENTRIES];
590 int i, vec_entries = 0;
591 /* sadly this will work only with 2.6 kernels... */
592 FILE* f = fopen ("/proc/self/auxv", "rb");
594 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
596 #ifdef USE_ENVIRON_HACK
598 AuxVec *evec = linux_find_auxv (&vec_entries);
600 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
603 for (i = 0; i < vec_entries; i++) {
604 int type = vec [i].type;
605 if (type == 19) { /* AT_DCACHEBSIZE */
606 cachelinesize = vec [i].value;
608 } else if (type == 16) { /* AT_HWCAP */
609 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
610 cpu_hw_caps |= PPC_ICACHE_SNOOP;
611 if (vec [i].value & ISA_2X)
612 cpu_hw_caps |= PPC_ISA_2X;
613 if (vec [i].value & ISA_64)
614 cpu_hw_caps |= PPC_ISA_64;
615 if (vec [i].value & ISA_MOVE_FPR_GPR)
616 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
618 } else if (type == 15) { /* AT_PLATFORM */
619 const char *arch = (char*)vec [i].value;
620 if (strcmp (arch, "ppc970") == 0 ||
621 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
622 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
623 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
627 #elif defined(G_COMPILER_CODEWARRIOR)
631 //#error Need a way to get cache line size
636 cachelineinc = cachelinesize;
638 if (mono_cpu_count () > 1)
639 cpu_hw_caps |= PPC_SMP_CAPABLE;
640 InitializeCriticalSection (&mini_arch_mutex);
642 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
643 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
644 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
646 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
650 * Cleanup architecture specific code.
653 mono_arch_cleanup (void)
655 DeleteCriticalSection (&mini_arch_mutex);
659 * This function returns the optimizations supported on this cpu.
662 mono_arch_cpu_optimizations (guint32 *exclude_mask)
666 /* no ppc-specific optimizations yet */
672 * This function test for all SIMD functions supported.
674 * Returns a bitmask corresponding to all supported versions.
678 mono_arch_cpu_enumerate_simd_versions (void)
680 /* SIMD is currently unimplemented */
684 #ifdef __mono_ppc64__
685 #define CASE_PPC32(c)
686 #define CASE_PPC64(c) case c:
688 #define CASE_PPC32(c) case c:
689 #define CASE_PPC64(c)
693 is_regsize_var (MonoType *t) {
696 t = mini_type_get_underlying_type (NULL, t);
700 CASE_PPC64 (MONO_TYPE_I8)
701 CASE_PPC64 (MONO_TYPE_U8)
705 case MONO_TYPE_FNPTR:
707 case MONO_TYPE_OBJECT:
708 case MONO_TYPE_STRING:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_SZARRAY:
711 case MONO_TYPE_ARRAY:
713 case MONO_TYPE_GENERICINST:
714 if (!mono_type_generic_inst_is_valuetype (t))
717 case MONO_TYPE_VALUETYPE:
725 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
730 for (i = 0; i < cfg->num_varinfo; i++) {
731 MonoInst *ins = cfg->varinfo [i];
732 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
735 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
738 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
741 /* we can only allocate 32 bit values */
742 if (is_regsize_var (ins->inst_vtype)) {
743 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
744 g_assert (i == vmv->idx);
745 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
751 #endif /* ifndef DISABLE_JIT */
754 mono_arch_get_global_int_regs (MonoCompile *cfg)
758 if (cfg->frame_reg != ppc_sp)
760 /* ppc_r13 is used by the system on PPC EABI */
761 for (i = 14; i < top; ++i) {
763 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
764 * since the trampolines can clobber r11.
766 if (!(cfg->compile_aot && i == 29))
767 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
774 * mono_arch_regalloc_cost:
776 * Return the cost, in number of memory references, of the action of
777 * allocating the variable VMV into a register during global register
781 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
788 mono_arch_flush_icache (guint8 *code, gint size)
790 #ifdef MONO_CROSS_COMPILE
793 guint8 *endp, *start;
797 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
798 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
799 #if defined(G_COMPILER_CODEWARRIOR)
800 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
801 for (p = start; p < endp; p += cachelineinc) {
805 for (p = start; p < endp; p += cachelineinc) {
811 for (p = start; p < endp; p += cachelineinc) {
822 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
823 * The sync is required to insure that the store queue is completely empty.
824 * While the icbi performs no cache operations, icbi/isync is required to
825 * kill local prefetch.
827 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
829 asm ("icbi 0,%0;" : : "r"(code) : "memory");
833 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
834 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
835 for (p = start; p < endp; p += cachelineinc) {
836 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
839 for (p = start; p < endp; p += cachelineinc) {
840 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
845 for (p = start; p < endp; p += cachelineinc) {
846 /* for ISA2.0+ implementations we should not need any extra sync between the
847 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
848 * So I am not sure which chip had this problem but its not an issue on
849 * of the ISA V2 chips.
851 if (cpu_hw_caps & PPC_ISA_2X)
852 asm ("icbi 0,%0;" : : "r"(p) : "memory");
854 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
856 if (!(cpu_hw_caps & PPC_ISA_2X))
864 mono_arch_flush_register_windows (void)
869 #define ALWAYS_ON_STACK(s) s
870 #define FP_ALSO_IN_REG(s) s
872 #ifdef __mono_ppc64__
873 #define ALWAYS_ON_STACK(s) s
874 #define FP_ALSO_IN_REG(s) s
876 #define ALWAYS_ON_STACK(s)
877 #define FP_ALSO_IN_REG(s)
879 #define ALIGN_DOUBLES
892 guint32 vtsize; /* in param area */
894 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
895 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
896 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
897 guint8 bytes : 4; /* size in bytes - only valid for
898 RegTypeStructByVal if the struct fits
899 in one word, otherwise it's 0*/
908 gboolean vtype_retaddr;
916 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
918 #ifdef __mono_ppc64__
923 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
924 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
925 ainfo->reg = ppc_sp; /* in the caller */
926 ainfo->regtype = RegTypeBase;
927 *stack_size += sizeof (gpointer);
929 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
933 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
935 //*stack_size += (*stack_size % 8);
937 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
938 ainfo->reg = ppc_sp; /* in the caller */
939 ainfo->regtype = RegTypeBase;
946 ALWAYS_ON_STACK (*stack_size += 8);
954 #if defined(__APPLE__) || defined(__mono_ppc64__)
956 has_only_a_r48_field (MonoClass *klass)
960 gboolean have_field = FALSE;
962 while ((f = mono_class_get_fields (klass, &iter))) {
963 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
966 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
977 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
979 guint i, fr, gr, pstart;
980 int n = sig->hasthis + sig->param_count;
981 MonoType *simpletype;
982 guint32 stack_size = 0;
983 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
984 gboolean is_pinvoke = sig->pinvoke;
986 fr = PPC_FIRST_FPARG_REG;
987 gr = PPC_FIRST_ARG_REG;
989 /* FIXME: handle returning a struct */
990 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
991 cinfo->vtype_retaddr = TRUE;
997 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
998 * the first argument, allowing 'this' to be always passed in the first arg reg.
999 * Also do this if the first argument is a reference type, since virtual calls
1000 * are sometimes made using calli without sig->hasthis set, like in the delegate
1003 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1005 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1008 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1012 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1013 cinfo->struct_ret = cinfo->ret.reg;
1014 cinfo->vret_arg_index = 1;
1018 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1022 if (cinfo->vtype_retaddr) {
1023 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1024 cinfo->struct_ret = cinfo->ret.reg;
1028 DEBUG(printf("params: %d\n", sig->param_count));
1029 for (i = pstart; i < sig->param_count; ++i) {
1030 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1031 /* Prevent implicit arguments and sig_cookie from
1032 being passed in registers */
1033 gr = PPC_LAST_ARG_REG + 1;
1034 /* FIXME: don't we have to set fr, too? */
1035 /* Emit the signature cookie just before the implicit arguments */
1036 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1038 DEBUG(printf("param %d: ", i));
1039 if (sig->params [i]->byref) {
1040 DEBUG(printf("byref\n"));
1041 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1045 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1046 switch (simpletype->type) {
1047 case MONO_TYPE_BOOLEAN:
1050 cinfo->args [n].size = 1;
1051 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1054 case MONO_TYPE_CHAR:
1057 cinfo->args [n].size = 2;
1058 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1063 cinfo->args [n].size = 4;
1064 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1070 case MONO_TYPE_FNPTR:
1071 case MONO_TYPE_CLASS:
1072 case MONO_TYPE_OBJECT:
1073 case MONO_TYPE_STRING:
1074 case MONO_TYPE_SZARRAY:
1075 case MONO_TYPE_ARRAY:
1076 cinfo->args [n].size = sizeof (gpointer);
1077 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1080 case MONO_TYPE_GENERICINST:
1081 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1082 cinfo->args [n].size = sizeof (gpointer);
1083 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1088 case MONO_TYPE_VALUETYPE:
1089 case MONO_TYPE_TYPEDBYREF: {
1093 klass = mono_class_from_mono_type (sig->params [i]);
1094 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1095 size = sizeof (MonoTypedRef);
1096 else if (is_pinvoke)
1097 size = mono_class_native_size (klass, NULL);
1099 size = mono_class_value_size (klass, NULL);
1101 #if defined(__APPLE__) || defined(__mono_ppc64__)
1102 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1103 cinfo->args [n].size = size;
1105 /* It was 7, now it is 8 in LinuxPPC */
1106 if (fr <= PPC_LAST_FPARG_REG) {
1107 cinfo->args [n].regtype = RegTypeFP;
1108 cinfo->args [n].reg = fr;
1110 FP_ALSO_IN_REG (gr ++);
1112 FP_ALSO_IN_REG (gr ++);
1113 ALWAYS_ON_STACK (stack_size += size);
1115 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1116 cinfo->args [n].regtype = RegTypeBase;
1117 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1124 DEBUG(printf ("load %d bytes struct\n",
1125 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1127 #if PPC_PASS_STRUCTS_BY_VALUE
1129 int align_size = size;
1131 int rest = PPC_LAST_ARG_REG - gr + 1;
1134 align_size += (sizeof (gpointer) - 1);
1135 align_size &= ~(sizeof (gpointer) - 1);
1136 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1137 n_in_regs = MIN (rest, nregs);
1141 /* FIXME: check this */
1142 if (size >= 3 && size % 4 != 0)
1145 cinfo->args [n].regtype = RegTypeStructByVal;
1146 cinfo->args [n].vtregs = n_in_regs;
1147 cinfo->args [n].size = n_in_regs;
1148 cinfo->args [n].vtsize = nregs - n_in_regs;
1149 cinfo->args [n].reg = gr;
1151 #ifdef __mono_ppc64__
1152 if (nregs == 1 && is_pinvoke)
1153 cinfo->args [n].bytes = size;
1156 cinfo->args [n].bytes = 0;
1158 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1159 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1160 stack_size += nregs * sizeof (gpointer);
1163 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1164 cinfo->args [n].regtype = RegTypeStructByAddr;
1165 cinfo->args [n].vtsize = size;
1172 cinfo->args [n].size = 8;
1173 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1177 cinfo->args [n].size = 4;
1179 /* It was 7, now it is 8 in LinuxPPC */
1180 if (fr <= PPC_LAST_FPARG_REG) {
1181 cinfo->args [n].regtype = RegTypeFP;
1182 cinfo->args [n].reg = fr;
1184 FP_ALSO_IN_REG (gr ++);
1185 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1187 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1188 cinfo->args [n].regtype = RegTypeBase;
1189 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1190 stack_size += SIZEOF_REGISTER;
1195 cinfo->args [n].size = 8;
1196 /* It was 7, now it is 8 in LinuxPPC */
1197 if (fr <= PPC_LAST_FPARG_REG) {
1198 cinfo->args [n].regtype = RegTypeFP;
1199 cinfo->args [n].reg = fr;
1201 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1202 ALWAYS_ON_STACK (stack_size += 8);
1204 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1205 cinfo->args [n].regtype = RegTypeBase;
1206 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1212 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1217 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1218 /* Prevent implicit arguments and sig_cookie from
1219 being passed in registers */
1220 gr = PPC_LAST_ARG_REG + 1;
1221 /* Emit the signature cookie just before the implicit arguments */
1222 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1226 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1227 switch (simpletype->type) {
1228 case MONO_TYPE_BOOLEAN:
1233 case MONO_TYPE_CHAR:
1239 case MONO_TYPE_FNPTR:
1240 case MONO_TYPE_CLASS:
1241 case MONO_TYPE_OBJECT:
1242 case MONO_TYPE_SZARRAY:
1243 case MONO_TYPE_ARRAY:
1244 case MONO_TYPE_STRING:
1245 cinfo->ret.reg = ppc_r3;
1249 cinfo->ret.reg = ppc_r3;
1253 cinfo->ret.reg = ppc_f1;
1254 cinfo->ret.regtype = RegTypeFP;
1256 case MONO_TYPE_GENERICINST:
1257 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1258 cinfo->ret.reg = ppc_r3;
1262 case MONO_TYPE_VALUETYPE:
1264 case MONO_TYPE_TYPEDBYREF:
1265 case MONO_TYPE_VOID:
1268 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1272 /* align stack size to 16 */
1273 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1274 stack_size = (stack_size + 15) & ~15;
1276 cinfo->stack_usage = stack_size;
1280 G_GNUC_UNUSED static void
1285 G_GNUC_UNUSED static gboolean
1288 static int count = 0;
1291 if (!getenv ("COUNT"))
1294 if (count == atoi (getenv ("COUNT"))) {
1298 if (count > atoi (getenv ("COUNT"))) {
1306 mono_ppc_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1312 c1 = get_call_info (NULL, caller_sig);
1313 c2 = get_call_info (NULL, callee_sig);
1314 res = c1->stack_usage >= c2->stack_usage;
1315 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1316 /* An address on the callee's stack is passed as the first argument */
1318 for (i = 0; i < c2->nargs; ++i) {
1319 if (c2->args [i].regtype == RegTypeStructByAddr)
1320 /* An address on the callee's stack is passed as the argument */
1325 if (!debug_count ())
1336 * Set var information according to the calling convention. ppc version.
1337 * The locals var stuff should most likely be split in another method.
1340 mono_arch_allocate_vars (MonoCompile *m)
1342 MonoMethodSignature *sig;
1343 MonoMethodHeader *header;
1345 int i, offset, size, align, curinst;
1346 int frame_reg = ppc_sp;
1348 guint32 locals_stack_size, locals_stack_align;
1350 m->flags |= MONO_CFG_HAS_SPILLUP;
1352 /* allow room for the vararg method args: void* and long/double */
1353 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1354 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1355 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1356 * call convs needs to be handled this way.
1358 if (m->flags & MONO_CFG_HAS_VARARGS)
1359 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1360 /* gtk-sharp and other broken code will dllimport vararg functions even with
1361 * non-varargs signatures. Since there is little hope people will get this right
1362 * we assume they won't.
1364 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1365 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1370 * We use the frame register also for any method that has
1371 * exception clauses. This way, when the handlers are called,
1372 * the code will reference local variables using the frame reg instead of
1373 * the stack pointer: if we had to restore the stack pointer, we'd
1374 * corrupt the method frames that are already on the stack (since
1375 * filters get called before stack unwinding happens) when the filter
1376 * code would call any method (this also applies to finally etc.).
1378 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1379 frame_reg = ppc_r31;
1380 m->frame_reg = frame_reg;
1381 if (frame_reg != ppc_sp) {
1382 m->used_int_regs |= 1 << frame_reg;
1385 sig = mono_method_signature (m->method);
1389 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1390 m->ret->opcode = OP_REGVAR;
1391 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1393 /* FIXME: handle long values? */
1394 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1395 case MONO_TYPE_VOID:
1399 m->ret->opcode = OP_REGVAR;
1400 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1403 m->ret->opcode = OP_REGVAR;
1404 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1408 /* local vars are at a positive offset from the stack pointer */
1410 * also note that if the function uses alloca, we use ppc_r31
1411 * to point at the local variables.
1413 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1414 /* align the offset to 16 bytes: not sure this is needed here */
1416 //offset &= ~(16 - 1);
1418 /* add parameter area size for called functions */
1419 offset += m->param_area;
1421 offset &= ~(16 - 1);
1423 /* allow room to save the return value */
1424 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1427 /* the MonoLMF structure is stored just below the stack pointer */
1430 /* this stuff should not be needed on ppc and the new jit,
1431 * because a call on ppc to the handlers doesn't change the
1432 * stack pointer and the jist doesn't manipulate the stack pointer
1433 * for operations involving valuetypes.
1435 /* reserve space to store the esp */
1436 offset += sizeof (gpointer);
1438 /* this is a global constant */
1439 mono_exc_esp_offset = offset;
1442 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1443 offset += sizeof(gpointer) - 1;
1444 offset &= ~(sizeof(gpointer) - 1);
1446 m->vret_addr->opcode = OP_REGOFFSET;
1447 m->vret_addr->inst_basereg = frame_reg;
1448 m->vret_addr->inst_offset = offset;
1450 if (G_UNLIKELY (m->verbose_level > 1)) {
1451 printf ("vret_addr =");
1452 mono_print_ins (m->vret_addr);
1455 offset += sizeof(gpointer);
1458 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1459 if (locals_stack_align) {
1460 offset += (locals_stack_align - 1);
1461 offset &= ~(locals_stack_align - 1);
1463 for (i = m->locals_start; i < m->num_varinfo; i++) {
1464 if (offsets [i] != -1) {
1465 MonoInst *inst = m->varinfo [i];
1466 inst->opcode = OP_REGOFFSET;
1467 inst->inst_basereg = frame_reg;
1468 inst->inst_offset = offset + offsets [i];
1470 g_print ("allocating local %d (%s) to %d\n",
1471 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1475 offset += locals_stack_size;
1479 inst = m->args [curinst];
1480 if (inst->opcode != OP_REGVAR) {
1481 inst->opcode = OP_REGOFFSET;
1482 inst->inst_basereg = frame_reg;
1483 offset += sizeof (gpointer) - 1;
1484 offset &= ~(sizeof (gpointer) - 1);
1485 inst->inst_offset = offset;
1486 offset += sizeof (gpointer);
1491 for (i = 0; i < sig->param_count; ++i) {
1492 inst = m->args [curinst];
1493 if (inst->opcode != OP_REGVAR) {
1494 inst->opcode = OP_REGOFFSET;
1495 inst->inst_basereg = frame_reg;
1497 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1498 inst->backend.is_pinvoke = 1;
1500 size = mono_type_size (sig->params [i], &align);
1502 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1503 size = align = sizeof (gpointer);
1505 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1506 * they are saved using std in the prolog.
1508 align = sizeof (gpointer);
1509 offset += align - 1;
1510 offset &= ~(align - 1);
1511 inst->inst_offset = offset;
1517 /* some storage for fp conversions */
1520 m->arch.fp_conv_var_offset = offset;
1523 /* align the offset to 16 bytes */
1525 offset &= ~(16 - 1);
1528 m->stack_offset = offset;
1530 if (sig->call_convention == MONO_CALL_VARARG) {
1531 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1533 m->sig_cookie = cinfo->sig_cookie.offset;
1540 mono_arch_create_vars (MonoCompile *cfg)
1542 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1544 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1545 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1549 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1550 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1554 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1556 int sig_reg = mono_alloc_ireg (cfg);
1558 /* FIXME: Add support for signature tokens to AOT */
1559 cfg->disable_aot = TRUE;
1561 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1562 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1563 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1567 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1570 MonoMethodSignature *sig;
1574 sig = call->signature;
1575 n = sig->param_count + sig->hasthis;
1577 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1579 for (i = 0; i < n; ++i) {
1580 ArgInfo *ainfo = cinfo->args + i;
1583 if (i >= sig->hasthis)
1584 t = sig->params [i - sig->hasthis];
1586 t = &mono_defaults.int_class->byval_arg;
1587 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1589 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1590 emit_sig_cookie (cfg, call, cinfo);
1592 in = call->args [i];
1594 if (ainfo->regtype == RegTypeGeneral) {
1595 #ifndef __mono_ppc64__
1596 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1597 MONO_INST_NEW (cfg, ins, OP_MOVE);
1598 ins->dreg = mono_alloc_ireg (cfg);
1599 ins->sreg1 = in->dreg + 1;
1600 MONO_ADD_INS (cfg->cbb, ins);
1601 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1603 MONO_INST_NEW (cfg, ins, OP_MOVE);
1604 ins->dreg = mono_alloc_ireg (cfg);
1605 ins->sreg1 = in->dreg + 2;
1606 MONO_ADD_INS (cfg->cbb, ins);
1607 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1611 MONO_INST_NEW (cfg, ins, OP_MOVE);
1612 ins->dreg = mono_alloc_ireg (cfg);
1613 ins->sreg1 = in->dreg;
1614 MONO_ADD_INS (cfg->cbb, ins);
1616 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1618 } else if (ainfo->regtype == RegTypeStructByAddr) {
1619 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1620 ins->opcode = OP_OUTARG_VT;
1621 ins->sreg1 = in->dreg;
1622 ins->klass = in->klass;
1623 ins->inst_p0 = call;
1624 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1625 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1626 MONO_ADD_INS (cfg->cbb, ins);
1627 } else if (ainfo->regtype == RegTypeStructByVal) {
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);
1637 } else if (ainfo->regtype == RegTypeBase) {
1638 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1639 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1640 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1641 if (t->type == MONO_TYPE_R8)
1642 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1644 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1646 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1648 } else if (ainfo->regtype == RegTypeFP) {
1649 if (t->type == MONO_TYPE_VALUETYPE) {
1650 /* this is further handled in mono_arch_emit_outarg_vt () */
1651 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1652 ins->opcode = OP_OUTARG_VT;
1653 ins->sreg1 = in->dreg;
1654 ins->klass = in->klass;
1655 ins->inst_p0 = call;
1656 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1657 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1658 MONO_ADD_INS (cfg->cbb, ins);
1660 cfg->flags |= MONO_CFG_HAS_FPOUT;
1662 int dreg = mono_alloc_freg (cfg);
1664 if (ainfo->size == 4) {
1665 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1667 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1669 ins->sreg1 = in->dreg;
1670 MONO_ADD_INS (cfg->cbb, ins);
1673 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1674 cfg->flags |= MONO_CFG_HAS_FPOUT;
1677 g_assert_not_reached ();
1681 /* Emit the signature cookie in the case that there is no
1682 additional argument */
1683 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1684 emit_sig_cookie (cfg, call, cinfo);
1686 if (cinfo->struct_ret) {
1689 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1690 vtarg->sreg1 = call->vret_var->dreg;
1691 vtarg->dreg = mono_alloc_preg (cfg);
1692 MONO_ADD_INS (cfg->cbb, vtarg);
1694 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1697 call->stack_usage = cinfo->stack_usage;
1698 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1699 cfg->flags |= MONO_CFG_HAS_CALLS;
1707 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1709 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1710 ArgInfo *ainfo = ins->inst_p1;
1711 int ovf_size = ainfo->vtsize;
1712 int doffset = ainfo->offset;
1713 int i, soffset, dreg;
1715 if (ainfo->regtype == RegTypeStructByVal) {
1722 * Darwin pinvokes needs some special handling for 1
1723 * and 2 byte arguments
1725 g_assert (ins->klass);
1726 if (call->signature->pinvoke)
1727 size = mono_class_native_size (ins->klass, NULL);
1728 if (size == 2 || size == 1) {
1729 int tmpr = mono_alloc_ireg (cfg);
1731 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1733 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1734 dreg = mono_alloc_ireg (cfg);
1735 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1736 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1739 for (i = 0; i < ainfo->vtregs; ++i) {
1740 int antipadding = 0;
1743 antipadding = sizeof (gpointer) - ainfo->bytes;
1745 dreg = mono_alloc_ireg (cfg);
1746 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1748 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1749 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1750 soffset += sizeof (gpointer);
1753 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1754 } else if (ainfo->regtype == RegTypeFP) {
1755 int tmpr = mono_alloc_freg (cfg);
1756 if (ainfo->size == 4)
1757 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1759 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1760 dreg = mono_alloc_freg (cfg);
1761 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1762 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1764 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1768 /* FIXME: alignment? */
1769 if (call->signature->pinvoke) {
1770 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1771 vtcopy->backend.is_pinvoke = 1;
1773 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1776 g_assert (ovf_size > 0);
1778 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1779 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1782 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1784 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1789 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1791 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1792 mono_method_signature (method)->ret);
1795 #ifndef __mono_ppc64__
1796 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1799 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1800 ins->sreg1 = val->dreg + 1;
1801 ins->sreg2 = val->dreg + 2;
1802 MONO_ADD_INS (cfg->cbb, ins);
1806 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1807 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1811 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1814 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1816 mono_arch_is_inst_imm (gint64 imm)
1821 #endif /* DISABLE_JIT */
1824 * Allow tracing to work with this interface (with an optional argument)
1828 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1832 ppc_load_ptr (code, ppc_r3, cfg->method);
1833 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1834 ppc_load_func (code, ppc_r0, func);
1835 ppc_mtlr (code, ppc_r0);
1849 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1852 int save_mode = SAVE_NONE;
1854 MonoMethod *method = cfg->method;
1855 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1856 mono_method_signature (method)->ret)->type;
1857 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1861 offset = code - cfg->native_code;
1862 /* we need about 16 instructions */
1863 if (offset > (cfg->code_size - 16 * 4)) {
1864 cfg->code_size *= 2;
1865 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1866 code = cfg->native_code + offset;
1870 case MONO_TYPE_VOID:
1871 /* special case string .ctor icall */
1872 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1873 save_mode = SAVE_ONE;
1875 save_mode = SAVE_NONE;
1877 #ifndef __mono_ppc64__
1880 save_mode = SAVE_TWO;
1885 save_mode = SAVE_FP;
1887 case MONO_TYPE_VALUETYPE:
1888 save_mode = SAVE_STRUCT;
1891 save_mode = SAVE_ONE;
1895 switch (save_mode) {
1897 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1898 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1899 if (enable_arguments) {
1900 ppc_mr (code, ppc_r5, ppc_r4);
1901 ppc_mr (code, ppc_r4, ppc_r3);
1905 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1906 if (enable_arguments) {
1907 ppc_mr (code, ppc_r4, ppc_r3);
1911 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1912 if (enable_arguments) {
1913 /* FIXME: what reg? */
1914 ppc_fmr (code, ppc_f3, ppc_f1);
1915 /* FIXME: use 8 byte load on PPC64 */
1916 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1917 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1921 if (enable_arguments) {
1922 /* FIXME: get the actual address */
1923 ppc_mr (code, ppc_r4, ppc_r3);
1931 ppc_load_ptr (code, ppc_r3, cfg->method);
1932 ppc_load_func (code, ppc_r0, func);
1933 ppc_mtlr (code, ppc_r0);
1936 switch (save_mode) {
1938 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1939 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1942 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1945 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1955 * Conditional branches have a small offset, so if it is likely overflowed,
1956 * we do a branch to the end of the method (uncond branches have much larger
1957 * offsets) where we perform the conditional and jump back unconditionally.
1958 * It's slightly slower, since we add two uncond branches, but it's very simple
1959 * with the current patch implementation and such large methods are likely not
1960 * going to be perf critical anyway.
1965 const char *exception;
1972 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1973 if (0 && ins->inst_true_bb->native_offset) { \
1974 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1976 int br_disp = ins->inst_true_bb->max_offset - offset; \
1977 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1978 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1979 ovfj->data.bb = ins->inst_true_bb; \
1980 ovfj->ip_offset = 0; \
1981 ovfj->b0_cond = (b0); \
1982 ovfj->b1_cond = (b1); \
1983 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1986 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1987 ppc_bc (code, (b0), (b1), 0); \
1991 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1993 /* emit an exception if condition is fail
1995 * We assign the extra code used to throw the implicit exceptions
1996 * to cfg->bb_exit as far as the big branch handling is concerned
1998 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2000 int br_disp = cfg->bb_exit->max_offset - offset; \
2001 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2002 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2003 ovfj->data.exception = (exc_name); \
2004 ovfj->ip_offset = code - cfg->native_code; \
2005 ovfj->b0_cond = (b0); \
2006 ovfj->b1_cond = (b1); \
2007 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2009 cfg->bb_exit->max_offset += 24; \
2011 mono_add_patch_info (cfg, code - cfg->native_code, \
2012 MONO_PATCH_INFO_EXC, exc_name); \
2013 ppc_bcl (code, (b0), (b1), 0); \
2017 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2020 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2025 normalize_opcode (int opcode)
2028 #ifndef __mono_ilp32__
2029 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2030 return OP_LOAD_MEMBASE;
2031 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2032 return OP_LOAD_MEMINDEX;
2033 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2034 return OP_STORE_MEMBASE_REG;
2035 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2036 return OP_STORE_MEMBASE_IMM;
2037 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2038 return OP_STORE_MEMINDEX;
2040 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2042 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2043 return OP_SHR_UN_IMM;
2050 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2052 MonoInst *ins, *n, *last_ins = NULL;
2054 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2055 switch (normalize_opcode (ins->opcode)) {
2057 /* remove unnecessary multiplication with 1 */
2058 if (ins->inst_imm == 1) {
2059 if (ins->dreg != ins->sreg1) {
2060 ins->opcode = OP_MOVE;
2062 MONO_DELETE_INS (bb, ins);
2066 int power2 = mono_is_power_of_two (ins->inst_imm);
2068 ins->opcode = OP_SHL_IMM;
2069 ins->inst_imm = power2;
2073 case OP_LOAD_MEMBASE:
2075 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2076 * OP_LOAD_MEMBASE offset(basereg), reg
2078 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2079 ins->inst_basereg == last_ins->inst_destbasereg &&
2080 ins->inst_offset == last_ins->inst_offset) {
2081 if (ins->dreg == last_ins->sreg1) {
2082 MONO_DELETE_INS (bb, ins);
2085 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2086 ins->opcode = OP_MOVE;
2087 ins->sreg1 = last_ins->sreg1;
2091 * Note: reg1 must be different from the basereg in the second load
2092 * OP_LOAD_MEMBASE offset(basereg), reg1
2093 * OP_LOAD_MEMBASE offset(basereg), reg2
2095 * OP_LOAD_MEMBASE offset(basereg), reg1
2096 * OP_MOVE reg1, reg2
2098 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2099 ins->inst_basereg != last_ins->dreg &&
2100 ins->inst_basereg == last_ins->inst_basereg &&
2101 ins->inst_offset == last_ins->inst_offset) {
2103 if (ins->dreg == last_ins->dreg) {
2104 MONO_DELETE_INS (bb, ins);
2107 ins->opcode = OP_MOVE;
2108 ins->sreg1 = last_ins->dreg;
2111 //g_assert_not_reached ();
2115 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2116 * OP_LOAD_MEMBASE offset(basereg), reg
2118 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2119 * OP_ICONST reg, imm
2121 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2122 ins->inst_basereg == last_ins->inst_destbasereg &&
2123 ins->inst_offset == last_ins->inst_offset) {
2124 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2125 ins->opcode = OP_ICONST;
2126 ins->inst_c0 = last_ins->inst_imm;
2127 g_assert_not_reached (); // check this rule
2131 case OP_LOADU1_MEMBASE:
2132 case OP_LOADI1_MEMBASE:
2133 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2134 ins->inst_basereg == last_ins->inst_destbasereg &&
2135 ins->inst_offset == last_ins->inst_offset) {
2136 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2137 ins->sreg1 = last_ins->sreg1;
2140 case OP_LOADU2_MEMBASE:
2141 case OP_LOADI2_MEMBASE:
2142 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2143 ins->inst_basereg == last_ins->inst_destbasereg &&
2144 ins->inst_offset == last_ins->inst_offset) {
2145 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2146 ins->sreg1 = last_ins->sreg1;
2149 #ifdef __mono_ppc64__
2150 case OP_LOADU4_MEMBASE:
2151 case OP_LOADI4_MEMBASE:
2152 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2153 ins->inst_basereg == last_ins->inst_destbasereg &&
2154 ins->inst_offset == last_ins->inst_offset) {
2155 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2156 ins->sreg1 = last_ins->sreg1;
2161 ins->opcode = OP_MOVE;
2165 if (ins->dreg == ins->sreg1) {
2166 MONO_DELETE_INS (bb, ins);
2170 * OP_MOVE sreg, dreg
2171 * OP_MOVE dreg, sreg
2173 if (last_ins && last_ins->opcode == OP_MOVE &&
2174 ins->sreg1 == last_ins->dreg &&
2175 ins->dreg == last_ins->sreg1) {
2176 MONO_DELETE_INS (bb, ins);
2184 bb->last_ins = last_ins;
2188 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2190 switch (ins->opcode) {
2191 case OP_ICONV_TO_R_UN: {
2192 #if G_BYTE_ORDER == G_BIG_ENDIAN
2193 static const guint64 adjust_val = 0x4330000000000000ULL;
2195 static const guint64 adjust_val = 0x0000000000003043ULL;
2197 int msw_reg = mono_alloc_ireg (cfg);
2198 int adj_reg = mono_alloc_freg (cfg);
2199 int tmp_reg = mono_alloc_freg (cfg);
2200 int basereg = ppc_sp;
2202 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2203 if (!ppc_is_imm16 (offset + 4)) {
2204 basereg = mono_alloc_ireg (cfg);
2205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2207 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2208 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2209 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2210 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2211 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2212 ins->opcode = OP_NOP;
2215 #ifndef __mono_ppc64__
2216 case OP_ICONV_TO_R4:
2217 case OP_ICONV_TO_R8: {
2218 /* If we have a PPC_FEATURE_64 machine we can avoid
2219 this and use the fcfid instruction. Otherwise
2220 on an old 32-bit chip and we have to do this the
2222 if (!(cpu_hw_caps & PPC_ISA_64)) {
2223 /* FIXME: change precision for CEE_CONV_R4 */
2224 static const guint64 adjust_val = 0x4330000080000000ULL;
2225 int msw_reg = mono_alloc_ireg (cfg);
2226 int xored = mono_alloc_ireg (cfg);
2227 int adj_reg = mono_alloc_freg (cfg);
2228 int tmp_reg = mono_alloc_freg (cfg);
2229 int basereg = ppc_sp;
2231 if (!ppc_is_imm16 (offset + 4)) {
2232 basereg = mono_alloc_ireg (cfg);
2233 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2235 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2236 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2237 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2238 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2239 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2240 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2241 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2242 if (ins->opcode == OP_ICONV_TO_R4)
2243 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2244 ins->opcode = OP_NOP;
2250 int msw_reg = mono_alloc_ireg (cfg);
2251 int basereg = ppc_sp;
2253 if (!ppc_is_imm16 (offset + 4)) {
2254 basereg = mono_alloc_ireg (cfg);
2255 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2257 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2258 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2259 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2260 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2261 ins->opcode = OP_NOP;
2264 #ifdef __mono_ppc64__
2266 case OP_IADD_OVF_UN:
2268 int shifted1_reg = mono_alloc_ireg (cfg);
2269 int shifted2_reg = mono_alloc_ireg (cfg);
2270 int result_shifted_reg = mono_alloc_ireg (cfg);
2272 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2273 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2274 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2275 if (ins->opcode == OP_IADD_OVF_UN)
2276 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2278 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2279 ins->opcode = OP_NOP;
2286 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2288 switch (ins->opcode) {
2290 /* ADC sets the condition code */
2291 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2292 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2295 case OP_LADD_OVF_UN:
2296 /* ADC sets the condition code */
2297 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2298 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2302 /* SBB sets the condition code */
2303 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2304 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2307 case OP_LSUB_OVF_UN:
2308 /* SBB sets the condition code */
2309 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2310 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2314 /* From gcc generated code */
2315 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2316 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2325 * the branch_b0_table should maintain the order of these
2339 branch_b0_table [] = {
2354 branch_b1_table [] = {
2368 #define NEW_INS(cfg,dest,op) do { \
2369 MONO_INST_NEW((cfg), (dest), (op)); \
2370 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2374 map_to_reg_reg_op (int op)
2383 case OP_COMPARE_IMM:
2385 case OP_ICOMPARE_IMM:
2387 case OP_LCOMPARE_IMM:
2403 case OP_LOAD_MEMBASE:
2404 return OP_LOAD_MEMINDEX;
2405 case OP_LOADI4_MEMBASE:
2406 return OP_LOADI4_MEMINDEX;
2407 case OP_LOADU4_MEMBASE:
2408 return OP_LOADU4_MEMINDEX;
2409 case OP_LOADI8_MEMBASE:
2410 return OP_LOADI8_MEMINDEX;
2411 case OP_LOADU1_MEMBASE:
2412 return OP_LOADU1_MEMINDEX;
2413 case OP_LOADI2_MEMBASE:
2414 return OP_LOADI2_MEMINDEX;
2415 case OP_LOADU2_MEMBASE:
2416 return OP_LOADU2_MEMINDEX;
2417 case OP_LOADI1_MEMBASE:
2418 return OP_LOADI1_MEMINDEX;
2419 case OP_LOADR4_MEMBASE:
2420 return OP_LOADR4_MEMINDEX;
2421 case OP_LOADR8_MEMBASE:
2422 return OP_LOADR8_MEMINDEX;
2423 case OP_STOREI1_MEMBASE_REG:
2424 return OP_STOREI1_MEMINDEX;
2425 case OP_STOREI2_MEMBASE_REG:
2426 return OP_STOREI2_MEMINDEX;
2427 case OP_STOREI4_MEMBASE_REG:
2428 return OP_STOREI4_MEMINDEX;
2429 case OP_STOREI8_MEMBASE_REG:
2430 return OP_STOREI8_MEMINDEX;
2431 case OP_STORE_MEMBASE_REG:
2432 return OP_STORE_MEMINDEX;
2433 case OP_STORER4_MEMBASE_REG:
2434 return OP_STORER4_MEMINDEX;
2435 case OP_STORER8_MEMBASE_REG:
2436 return OP_STORER8_MEMINDEX;
2437 case OP_STORE_MEMBASE_IMM:
2438 return OP_STORE_MEMBASE_REG;
2439 case OP_STOREI1_MEMBASE_IMM:
2440 return OP_STOREI1_MEMBASE_REG;
2441 case OP_STOREI2_MEMBASE_IMM:
2442 return OP_STOREI2_MEMBASE_REG;
2443 case OP_STOREI4_MEMBASE_IMM:
2444 return OP_STOREI4_MEMBASE_REG;
2445 case OP_STOREI8_MEMBASE_IMM:
2446 return OP_STOREI8_MEMBASE_REG;
2448 return mono_op_imm_to_op (op);
2451 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2453 #define compare_opcode_is_unsigned(opcode) \
2454 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2455 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2456 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2457 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2458 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2459 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2460 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2461 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2464 * Remove from the instruction list the instructions that can't be
2465 * represented with very simple instructions with no register
2469 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2471 MonoInst *ins, *next, *temp, *last_ins = NULL;
2474 MONO_BB_FOR_EACH_INS (bb, ins) {
2476 switch (ins->opcode) {
2477 case OP_IDIV_UN_IMM:
2480 case OP_IREM_UN_IMM:
2481 NEW_INS (cfg, temp, OP_ICONST);
2482 temp->inst_c0 = ins->inst_imm;
2483 temp->dreg = mono_alloc_ireg (cfg);
2484 ins->sreg2 = temp->dreg;
2485 if (ins->opcode == OP_IDIV_IMM)
2486 ins->opcode = OP_IDIV;
2487 else if (ins->opcode == OP_IREM_IMM)
2488 ins->opcode = OP_IREM;
2489 else if (ins->opcode == OP_IDIV_UN_IMM)
2490 ins->opcode = OP_IDIV_UN;
2491 else if (ins->opcode == OP_IREM_UN_IMM)
2492 ins->opcode = OP_IREM_UN;
2494 /* handle rem separately */
2498 CASE_PPC64 (OP_LREM)
2499 CASE_PPC64 (OP_LREM_UN) {
2501 /* we change a rem dest, src1, src2 to
2502 * div temp1, src1, src2
2503 * mul temp2, temp1, src2
2504 * sub dest, src1, temp2
2506 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2507 NEW_INS (cfg, mul, OP_IMUL);
2508 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2509 ins->opcode = OP_ISUB;
2511 NEW_INS (cfg, mul, OP_LMUL);
2512 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2513 ins->opcode = OP_LSUB;
2515 temp->sreg1 = ins->sreg1;
2516 temp->sreg2 = ins->sreg2;
2517 temp->dreg = mono_alloc_ireg (cfg);
2518 mul->sreg1 = temp->dreg;
2519 mul->sreg2 = ins->sreg2;
2520 mul->dreg = mono_alloc_ireg (cfg);
2521 ins->sreg2 = mul->dreg;
2525 CASE_PPC64 (OP_LADD_IMM)
2528 if (!ppc_is_imm16 (ins->inst_imm)) {
2529 NEW_INS (cfg, temp, OP_ICONST);
2530 temp->inst_c0 = ins->inst_imm;
2531 temp->dreg = mono_alloc_ireg (cfg);
2532 ins->sreg2 = temp->dreg;
2533 ins->opcode = map_to_reg_reg_op (ins->opcode);
2537 CASE_PPC64 (OP_LSUB_IMM)
2539 if (!ppc_is_imm16 (-ins->inst_imm)) {
2540 NEW_INS (cfg, temp, OP_ICONST);
2541 temp->inst_c0 = ins->inst_imm;
2542 temp->dreg = mono_alloc_ireg (cfg);
2543 ins->sreg2 = temp->dreg;
2544 ins->opcode = map_to_reg_reg_op (ins->opcode);
2556 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2557 #ifdef __mono_ppc64__
2558 if (ins->inst_imm & 0xffffffff00000000ULL)
2562 NEW_INS (cfg, temp, OP_ICONST);
2563 temp->inst_c0 = ins->inst_imm;
2564 temp->dreg = mono_alloc_ireg (cfg);
2565 ins->sreg2 = temp->dreg;
2566 ins->opcode = map_to_reg_reg_op (ins->opcode);
2575 NEW_INS (cfg, temp, OP_ICONST);
2576 temp->inst_c0 = ins->inst_imm;
2577 temp->dreg = mono_alloc_ireg (cfg);
2578 ins->sreg2 = temp->dreg;
2579 ins->opcode = map_to_reg_reg_op (ins->opcode);
2581 case OP_COMPARE_IMM:
2582 case OP_ICOMPARE_IMM:
2583 CASE_PPC64 (OP_LCOMPARE_IMM)
2585 /* Branch opts can eliminate the branch */
2586 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2587 ins->opcode = OP_NOP;
2591 if (compare_opcode_is_unsigned (next->opcode)) {
2592 if (!ppc_is_uimm16 (ins->inst_imm)) {
2593 NEW_INS (cfg, temp, OP_ICONST);
2594 temp->inst_c0 = ins->inst_imm;
2595 temp->dreg = mono_alloc_ireg (cfg);
2596 ins->sreg2 = temp->dreg;
2597 ins->opcode = map_to_reg_reg_op (ins->opcode);
2600 if (!ppc_is_imm16 (ins->inst_imm)) {
2601 NEW_INS (cfg, temp, OP_ICONST);
2602 temp->inst_c0 = ins->inst_imm;
2603 temp->dreg = mono_alloc_ireg (cfg);
2604 ins->sreg2 = temp->dreg;
2605 ins->opcode = map_to_reg_reg_op (ins->opcode);
2611 if (ins->inst_imm == 1) {
2612 ins->opcode = OP_MOVE;
2615 if (ins->inst_imm == 0) {
2616 ins->opcode = OP_ICONST;
2620 imm = mono_is_power_of_two (ins->inst_imm);
2622 ins->opcode = OP_SHL_IMM;
2623 ins->inst_imm = imm;
2626 if (!ppc_is_imm16 (ins->inst_imm)) {
2627 NEW_INS (cfg, temp, OP_ICONST);
2628 temp->inst_c0 = ins->inst_imm;
2629 temp->dreg = mono_alloc_ireg (cfg);
2630 ins->sreg2 = temp->dreg;
2631 ins->opcode = map_to_reg_reg_op (ins->opcode);
2634 case OP_LOCALLOC_IMM:
2635 NEW_INS (cfg, temp, OP_ICONST);
2636 temp->inst_c0 = ins->inst_imm;
2637 temp->dreg = mono_alloc_ireg (cfg);
2638 ins->sreg1 = temp->dreg;
2639 ins->opcode = OP_LOCALLOC;
2641 case OP_LOAD_MEMBASE:
2642 case OP_LOADI4_MEMBASE:
2643 CASE_PPC64 (OP_LOADI8_MEMBASE)
2644 case OP_LOADU4_MEMBASE:
2645 case OP_LOADI2_MEMBASE:
2646 case OP_LOADU2_MEMBASE:
2647 case OP_LOADI1_MEMBASE:
2648 case OP_LOADU1_MEMBASE:
2649 case OP_LOADR4_MEMBASE:
2650 case OP_LOADR8_MEMBASE:
2651 case OP_STORE_MEMBASE_REG:
2652 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2653 case OP_STOREI4_MEMBASE_REG:
2654 case OP_STOREI2_MEMBASE_REG:
2655 case OP_STOREI1_MEMBASE_REG:
2656 case OP_STORER4_MEMBASE_REG:
2657 case OP_STORER8_MEMBASE_REG:
2658 /* we can do two things: load the immed in a register
2659 * and use an indexed load, or see if the immed can be
2660 * represented as an ad_imm + a load with a smaller offset
2661 * that fits. We just do the first for now, optimize later.
2663 if (ppc_is_imm16 (ins->inst_offset))
2665 NEW_INS (cfg, temp, OP_ICONST);
2666 temp->inst_c0 = ins->inst_offset;
2667 temp->dreg = mono_alloc_ireg (cfg);
2668 ins->sreg2 = temp->dreg;
2669 ins->opcode = map_to_reg_reg_op (ins->opcode);
2671 case OP_STORE_MEMBASE_IMM:
2672 case OP_STOREI1_MEMBASE_IMM:
2673 case OP_STOREI2_MEMBASE_IMM:
2674 case OP_STOREI4_MEMBASE_IMM:
2675 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2676 NEW_INS (cfg, temp, OP_ICONST);
2677 temp->inst_c0 = ins->inst_imm;
2678 temp->dreg = mono_alloc_ireg (cfg);
2679 ins->sreg1 = temp->dreg;
2680 ins->opcode = map_to_reg_reg_op (ins->opcode);
2682 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2685 if (cfg->compile_aot) {
2686 /* Keep these in the aot case */
2689 NEW_INS (cfg, temp, OP_ICONST);
2690 temp->inst_c0 = (gulong)ins->inst_p0;
2691 temp->dreg = mono_alloc_ireg (cfg);
2692 ins->inst_basereg = temp->dreg;
2693 ins->inst_offset = 0;
2694 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2696 /* make it handle the possibly big ins->inst_offset
2697 * later optimize to use lis + load_membase
2703 bb->last_ins = last_ins;
2704 bb->max_vreg = cfg->next_vreg;
2708 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2710 long offset = cfg->arch.fp_conv_var_offset;
2712 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2713 #ifdef __mono_ppc64__
2715 ppc_fctidz (code, ppc_f0, sreg);
2720 ppc_fctiwz (code, ppc_f0, sreg);
2723 if (ppc_is_imm16 (offset + sub_offset)) {
2724 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2726 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2728 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2730 ppc_load (code, dreg, offset);
2731 ppc_add (code, dreg, dreg, cfg->frame_reg);
2732 ppc_stfd (code, ppc_f0, 0, dreg);
2734 ppc_ldr (code, dreg, sub_offset, dreg);
2736 ppc_lwz (code, dreg, sub_offset, dreg);
2740 ppc_andid (code, dreg, dreg, 0xff);
2742 ppc_andid (code, dreg, dreg, 0xffff);
2743 #ifdef __mono_ppc64__
2745 ppc_clrldi (code, dreg, dreg, 32);
2749 ppc_extsb (code, dreg, dreg);
2751 ppc_extsh (code, dreg, dreg);
2752 #ifdef __mono_ppc64__
2754 ppc_extsw (code, dreg, dreg);
2762 const guchar *target;
2767 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2770 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2771 #ifdef __mono_ppc64__
2772 g_assert_not_reached ();
2774 PatchData *pdata = (PatchData*)user_data;
2775 guchar *code = data;
2776 guint32 *thunks = data;
2777 guint32 *endthunks = (guint32*)(code + bsize);
2781 int difflow, diffhigh;
2783 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2784 difflow = (char*)pdata->code - (char*)thunks;
2785 diffhigh = (char*)pdata->code - (char*)endthunks;
2786 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2789 templ = (guchar*)load;
2790 ppc_load_sequence (templ, ppc_r0, pdata->target);
2792 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2793 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2794 while (thunks < endthunks) {
2795 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2796 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2797 ppc_patch (pdata->code, (guchar*)thunks);
2800 static int num_thunks = 0;
2802 if ((num_thunks % 20) == 0)
2803 g_print ("num_thunks lookup: %d\n", num_thunks);
2806 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2807 /* found a free slot instead: emit thunk */
2808 code = (guchar*)thunks;
2809 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2810 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2811 ppc_mtctr (code, ppc_r0);
2812 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2813 mono_arch_flush_icache ((guchar*)thunks, 16);
2815 ppc_patch (pdata->code, (guchar*)thunks);
2818 static int num_thunks = 0;
2820 if ((num_thunks % 20) == 0)
2821 g_print ("num_thunks: %d\n", num_thunks);
2825 /* skip 16 bytes, the size of the thunk */
2829 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2836 handle_thunk (int absolute, guchar *code, const guchar *target) {
2837 MonoDomain *domain = mono_domain_get ();
2841 pdata.target = target;
2842 pdata.absolute = absolute;
2845 mono_domain_lock (domain);
2846 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2849 /* this uses the first available slot */
2851 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2853 mono_domain_unlock (domain);
2855 if (pdata.found != 1)
2856 g_print ("thunk failed for %p from %p\n", target, code);
2857 g_assert (pdata.found == 1);
2861 patch_ins (guint8 *code, guint32 ins)
2863 *(guint32*)code = GUINT32_TO_BE (ins);
2864 mono_arch_flush_icache (code, 4);
2868 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2870 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2871 guint32 prim = ins >> 26;
2874 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2876 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2877 gint diff = target - code;
2880 if (diff <= 33554431){
2881 ins = (18 << 26) | (diff) | (ins & 1);
2882 patch_ins (code, ins);
2886 /* diff between 0 and -33554432 */
2887 if (diff >= -33554432){
2888 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2889 patch_ins (code, ins);
2894 if ((glong)target >= 0){
2895 if ((glong)target <= 33554431){
2896 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2897 patch_ins (code, ins);
2901 if ((glong)target >= -33554432){
2902 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2903 patch_ins (code, ins);
2908 handle_thunk (TRUE, code, target);
2911 g_assert_not_reached ();
2919 guint32 li = (gulong)target;
2920 ins = (ins & 0xffff0000) | (ins & 3);
2921 ovf = li & 0xffff0000;
2922 if (ovf != 0 && ovf != 0xffff0000)
2923 g_assert_not_reached ();
2926 // FIXME: assert the top bits of li are 0
2928 gint diff = target - code;
2929 ins = (ins & 0xffff0000) | (ins & 3);
2930 ovf = diff & 0xffff0000;
2931 if (ovf != 0 && ovf != 0xffff0000)
2932 g_assert_not_reached ();
2936 patch_ins (code, ins);
2940 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2941 #ifdef __mono_ppc64__
2942 guint32 *seq = (guint32*)code;
2943 guint32 *branch_ins;
2945 /* the trampoline code will try to patch the blrl, blr, bcctr */
2946 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2948 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2953 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2954 branch_ins = seq + 8;
2956 branch_ins = seq + 6;
2959 seq = (guint32*)code;
2960 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2961 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2963 if (ppc_is_load_op (seq [5])) {
2964 g_assert (ppc_is_load_op (seq [6]));
2967 guint8 *buf = (guint8*)&seq [5];
2968 ppc_mr (buf, ppc_r0, ppc_r11);
2973 target = mono_get_addr_from_ftnptr ((gpointer)target);
2976 /* FIXME: make this thread safe */
2977 /* FIXME: we're assuming we're using r11 here */
2978 ppc_load_ptr_sequence (code, ppc_r11, target);
2979 mono_arch_flush_icache ((guint8*)seq, 28);
2982 /* the trampoline code will try to patch the blrl, blr, bcctr */
2983 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2986 /* this is the lis/ori/mtlr/blrl sequence */
2987 seq = (guint32*)code;
2988 g_assert ((seq [0] >> 26) == 15);
2989 g_assert ((seq [1] >> 26) == 24);
2990 g_assert ((seq [2] >> 26) == 31);
2991 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2992 /* FIXME: make this thread safe */
2993 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2994 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2995 mono_arch_flush_icache (code - 8, 8);
2998 g_assert_not_reached ();
3000 // g_print ("patched with 0x%08x\n", ins);
3004 ppc_patch (guchar *code, const guchar *target)
3006 ppc_patch_full (code, target, FALSE);
3010 mono_ppc_patch (guchar *code, const guchar *target)
3012 ppc_patch (code, target);
3016 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3018 switch (ins->opcode) {
3021 case OP_FCALL_MEMBASE:
3022 if (ins->dreg != ppc_f1)
3023 ppc_fmr (code, ins->dreg, ppc_f1);
3031 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3033 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3037 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3039 long size = cfg->param_area;
3041 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3042 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3047 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3048 if (ppc_is_imm16 (-size)) {
3049 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3051 ppc_load (code, ppc_r11, -size);
3052 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3059 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3061 long size = cfg->param_area;
3063 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3064 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3069 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3070 if (ppc_is_imm16 (size)) {
3071 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3073 ppc_load (code, ppc_r11, size);
3074 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3080 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3084 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3086 MonoInst *ins, *next;
3089 guint8 *code = cfg->native_code + cfg->code_len;
3090 MonoInst *last_ins = NULL;
3091 guint last_offset = 0;
3095 /* we don't align basic blocks of loops on ppc */
3097 if (cfg->verbose_level > 2)
3098 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3100 cpos = bb->max_offset;
3102 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3103 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3104 //g_assert (!mono_compile_aot);
3107 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3108 /* this is not thread save, but good enough */
3109 /* fixme: howto handle overflows? */
3110 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3113 MONO_BB_FOR_EACH_INS (bb, ins) {
3114 offset = code - cfg->native_code;
3116 max_len = ins_native_length (cfg, ins);
3118 if (offset > (cfg->code_size - max_len - 16)) {
3119 cfg->code_size *= 2;
3120 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3121 code = cfg->native_code + offset;
3123 // if (ins->cil_code)
3124 // g_print ("cil code\n");
3125 mono_debug_record_line_number (cfg, ins, offset);
3127 switch (normalize_opcode (ins->opcode)) {
3128 case OP_RELAXED_NOP:
3131 case OP_DUMMY_STORE:
3132 case OP_NOT_REACHED:
3135 case OP_SEQ_POINT: {
3138 if (cfg->compile_aot)
3142 * Read from the single stepping trigger page. This will cause a
3143 * SIGSEGV when single stepping is enabled.
3144 * We do this _before_ the breakpoint, so single stepping after
3145 * a breakpoint is hit will step to the next IL offset.
3147 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3148 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3149 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3152 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3155 * A placeholder for a possible breakpoint inserted by
3156 * mono_arch_set_breakpoint ().
3158 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3163 emit_tls_access (code, ins->dreg, ins->inst_offset);
3166 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3167 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3168 ppc_mr (code, ppc_r4, ppc_r0);
3171 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3172 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3173 ppc_mr (code, ppc_r4, ppc_r0);
3175 case OP_MEMORY_BARRIER:
3178 case OP_STOREI1_MEMBASE_REG:
3179 if (ppc_is_imm16 (ins->inst_offset)) {
3180 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3182 if (ppc_is_imm32 (ins->inst_offset)) {
3183 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3184 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3186 ppc_load (code, ppc_r0, ins->inst_offset);
3187 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3191 case OP_STOREI2_MEMBASE_REG:
3192 if (ppc_is_imm16 (ins->inst_offset)) {
3193 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3195 if (ppc_is_imm32 (ins->inst_offset)) {
3196 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3197 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3199 ppc_load (code, ppc_r0, ins->inst_offset);
3200 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3204 case OP_STORE_MEMBASE_REG:
3205 if (ppc_is_imm16 (ins->inst_offset)) {
3206 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3208 if (ppc_is_imm32 (ins->inst_offset)) {
3209 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3210 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3212 ppc_load (code, ppc_r0, ins->inst_offset);
3213 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3217 #ifdef __mono_ilp32__
3218 case OP_STOREI8_MEMBASE_REG:
3219 if (ppc_is_imm16 (ins->inst_offset)) {
3220 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3222 ppc_load (code, ppc_r0, ins->inst_offset);
3223 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3227 case OP_STOREI1_MEMINDEX:
3228 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3230 case OP_STOREI2_MEMINDEX:
3231 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3233 case OP_STORE_MEMINDEX:
3234 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3237 g_assert_not_reached ();
3239 case OP_LOAD_MEMBASE:
3240 if (ppc_is_imm16 (ins->inst_offset)) {
3241 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3243 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3244 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3245 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3247 ppc_load (code, ppc_r0, ins->inst_offset);
3248 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3252 case OP_LOADI4_MEMBASE:
3253 #ifdef __mono_ppc64__
3254 if (ppc_is_imm16 (ins->inst_offset)) {
3255 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3257 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3258 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3259 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3261 ppc_load (code, ppc_r0, ins->inst_offset);
3262 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3267 case OP_LOADU4_MEMBASE:
3268 if (ppc_is_imm16 (ins->inst_offset)) {
3269 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3271 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3272 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3273 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3275 ppc_load (code, ppc_r0, ins->inst_offset);
3276 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3280 case OP_LOADI1_MEMBASE:
3281 case OP_LOADU1_MEMBASE:
3282 if (ppc_is_imm16 (ins->inst_offset)) {
3283 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3285 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3286 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3287 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3289 ppc_load (code, ppc_r0, ins->inst_offset);
3290 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3293 if (ins->opcode == OP_LOADI1_MEMBASE)
3294 ppc_extsb (code, ins->dreg, ins->dreg);
3296 case OP_LOADU2_MEMBASE:
3297 if (ppc_is_imm16 (ins->inst_offset)) {
3298 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3300 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3301 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3302 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3304 ppc_load (code, ppc_r0, ins->inst_offset);
3305 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3309 case OP_LOADI2_MEMBASE:
3310 if (ppc_is_imm16 (ins->inst_offset)) {
3311 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3313 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3314 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3315 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3317 ppc_load (code, ppc_r0, ins->inst_offset);
3318 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3322 #ifdef __mono_ilp32__
3323 case OP_LOADI8_MEMBASE:
3324 if (ppc_is_imm16 (ins->inst_offset)) {
3325 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3327 ppc_load (code, ppc_r0, ins->inst_offset);
3328 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3332 case OP_LOAD_MEMINDEX:
3333 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3335 case OP_LOADI4_MEMINDEX:
3336 #ifdef __mono_ppc64__
3337 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3340 case OP_LOADU4_MEMINDEX:
3341 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3343 case OP_LOADU2_MEMINDEX:
3344 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3346 case OP_LOADI2_MEMINDEX:
3347 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3349 case OP_LOADU1_MEMINDEX:
3350 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3352 case OP_LOADI1_MEMINDEX:
3353 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3354 ppc_extsb (code, ins->dreg, ins->dreg);
3356 case OP_ICONV_TO_I1:
3357 CASE_PPC64 (OP_LCONV_TO_I1)
3358 ppc_extsb (code, ins->dreg, ins->sreg1);
3360 case OP_ICONV_TO_I2:
3361 CASE_PPC64 (OP_LCONV_TO_I2)
3362 ppc_extsh (code, ins->dreg, ins->sreg1);
3364 case OP_ICONV_TO_U1:
3365 CASE_PPC64 (OP_LCONV_TO_U1)
3366 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3368 case OP_ICONV_TO_U2:
3369 CASE_PPC64 (OP_LCONV_TO_U2)
3370 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3374 CASE_PPC64 (OP_LCOMPARE)
3375 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3377 if (next && compare_opcode_is_unsigned (next->opcode))
3378 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3380 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3382 case OP_COMPARE_IMM:
3383 case OP_ICOMPARE_IMM:
3384 CASE_PPC64 (OP_LCOMPARE_IMM)
3385 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3387 if (next && compare_opcode_is_unsigned (next->opcode)) {
3388 if (ppc_is_uimm16 (ins->inst_imm)) {
3389 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3391 g_assert_not_reached ();
3394 if (ppc_is_imm16 (ins->inst_imm)) {
3395 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3397 g_assert_not_reached ();
3403 * gdb does not like encountering a trap in the debugged code. So
3404 * instead of emitting a trap, we emit a call a C function and place a
3408 ppc_mr (code, ppc_r3, ins->sreg1);
3409 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3410 (gpointer)"mono_break");
3411 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3412 ppc_load_func (code, ppc_r0, 0);
3413 ppc_mtlr (code, ppc_r0);
3421 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3424 CASE_PPC64 (OP_LADD)
3425 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3429 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3432 if (ppc_is_imm16 (ins->inst_imm)) {
3433 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3435 g_assert_not_reached ();
3440 CASE_PPC64 (OP_LADD_IMM)
3441 if (ppc_is_imm16 (ins->inst_imm)) {
3442 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3444 g_assert_not_reached ();
3448 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3450 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3451 ppc_mfspr (code, ppc_r0, ppc_xer);
3452 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3453 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3455 case OP_IADD_OVF_UN:
3456 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3458 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3459 ppc_mfspr (code, ppc_r0, ppc_xer);
3460 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3461 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3464 CASE_PPC64 (OP_LSUB_OVF)
3465 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3467 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3468 ppc_mfspr (code, ppc_r0, ppc_xer);
3469 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3470 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3472 case OP_ISUB_OVF_UN:
3473 CASE_PPC64 (OP_LSUB_OVF_UN)
3474 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3476 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3477 ppc_mfspr (code, ppc_r0, ppc_xer);
3478 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3479 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3481 case OP_ADD_OVF_CARRY:
3482 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3484 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3485 ppc_mfspr (code, ppc_r0, ppc_xer);
3486 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3487 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3489 case OP_ADD_OVF_UN_CARRY:
3490 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3492 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3493 ppc_mfspr (code, ppc_r0, ppc_xer);
3494 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3495 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3497 case OP_SUB_OVF_CARRY:
3498 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3500 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3501 ppc_mfspr (code, ppc_r0, ppc_xer);
3502 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3503 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3505 case OP_SUB_OVF_UN_CARRY:
3506 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3508 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3509 ppc_mfspr (code, ppc_r0, ppc_xer);
3510 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3511 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3515 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3518 CASE_PPC64 (OP_LSUB)
3519 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3523 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3527 CASE_PPC64 (OP_LSUB_IMM)
3528 // we add the negated value
3529 if (ppc_is_imm16 (-ins->inst_imm))
3530 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3532 g_assert_not_reached ();
3536 g_assert (ppc_is_imm16 (ins->inst_imm));
3537 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3540 ppc_subfze (code, ins->dreg, ins->sreg1);
3543 CASE_PPC64 (OP_LAND)
3544 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3545 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3549 CASE_PPC64 (OP_LAND_IMM)
3550 if (!(ins->inst_imm & 0xffff0000)) {
3551 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3552 } else if (!(ins->inst_imm & 0xffff)) {
3553 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3555 g_assert_not_reached ();
3559 CASE_PPC64 (OP_LDIV) {
3560 guint8 *divisor_is_m1;
3561 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3563 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3564 divisor_is_m1 = code;
3565 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3566 ppc_lis (code, ppc_r0, 0x8000);
3567 #ifdef __mono_ppc64__
3568 if (ins->opcode == OP_LDIV)
3569 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3571 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3572 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3573 ppc_patch (divisor_is_m1, code);
3574 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3576 if (ins->opcode == OP_IDIV)
3577 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3578 #ifdef __mono_ppc64__
3580 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3582 ppc_mfspr (code, ppc_r0, ppc_xer);
3583 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3584 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3588 CASE_PPC64 (OP_LDIV_UN)
3589 if (ins->opcode == OP_IDIV_UN)
3590 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3591 #ifdef __mono_ppc64__
3593 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3595 ppc_mfspr (code, ppc_r0, ppc_xer);
3596 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3597 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3603 g_assert_not_reached ();
3606 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3610 CASE_PPC64 (OP_LOR_IMM)
3611 if (!(ins->inst_imm & 0xffff0000)) {
3612 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3613 } else if (!(ins->inst_imm & 0xffff)) {
3614 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3616 g_assert_not_reached ();
3620 CASE_PPC64 (OP_LXOR)
3621 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 CASE_PPC64 (OP_LXOR_IMM)
3626 if (!(ins->inst_imm & 0xffff0000)) {
3627 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3628 } else if (!(ins->inst_imm & 0xffff)) {
3629 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3631 g_assert_not_reached ();
3635 CASE_PPC64 (OP_LSHL)
3636 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3640 CASE_PPC64 (OP_LSHL_IMM)
3641 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3644 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3647 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3650 if (MASK_SHIFT_IMM (ins->inst_imm))
3651 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3653 ppc_mr (code, ins->dreg, ins->sreg1);
3656 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3659 CASE_PPC64 (OP_LNOT)
3660 ppc_not (code, ins->dreg, ins->sreg1);
3663 CASE_PPC64 (OP_LNEG)
3664 ppc_neg (code, ins->dreg, ins->sreg1);
3667 CASE_PPC64 (OP_LMUL)
3668 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3672 CASE_PPC64 (OP_LMUL_IMM)
3673 if (ppc_is_imm16 (ins->inst_imm)) {
3674 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3676 g_assert_not_reached ();
3680 CASE_PPC64 (OP_LMUL_OVF)
3681 /* we annot use mcrxr, since it's not implemented on some processors
3682 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3684 if (ins->opcode == OP_IMUL_OVF)
3685 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3686 #ifdef __mono_ppc64__
3688 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3690 ppc_mfspr (code, ppc_r0, ppc_xer);
3691 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3692 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3694 case OP_IMUL_OVF_UN:
3695 CASE_PPC64 (OP_LMUL_OVF_UN)
3696 /* we first multiply to get the high word and compare to 0
3697 * to set the flags, then the result is discarded and then
3698 * we multiply to get the lower * bits result
3700 if (ins->opcode == OP_IMUL_OVF_UN)
3701 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3702 #ifdef __mono_ppc64__
3704 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3706 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3707 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3708 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3711 ppc_load (code, ins->dreg, ins->inst_c0);
3714 ppc_load (code, ins->dreg, ins->inst_l);
3717 case OP_LOAD_GOTADDR:
3718 /* The PLT implementation depends on this */
3719 g_assert (ins->dreg == ppc_r30);
3721 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3724 // FIXME: Fix max instruction length
3725 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3726 /* arch_emit_got_access () patches this */
3727 ppc_load32 (code, ppc_r0, 0);
3728 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3731 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3732 ppc_load_sequence (code, ins->dreg, 0);
3734 CASE_PPC32 (OP_ICONV_TO_I4)
3735 CASE_PPC32 (OP_ICONV_TO_U4)
3737 ppc_mr (code, ins->dreg, ins->sreg1);
3740 int saved = ins->sreg1;
3741 if (ins->sreg1 == ppc_r3) {
3742 ppc_mr (code, ppc_r0, ins->sreg1);
3745 if (ins->sreg2 != ppc_r3)
3746 ppc_mr (code, ppc_r3, ins->sreg2);
3747 if (saved != ppc_r4)
3748 ppc_mr (code, ppc_r4, saved);
3752 ppc_fmr (code, ins->dreg, ins->sreg1);
3754 case OP_FCONV_TO_R4:
3755 ppc_frsp (code, ins->dreg, ins->sreg1);
3759 MonoCallInst *call = (MonoCallInst*)ins;
3762 * Keep in sync with mono_arch_emit_epilog
3764 g_assert (!cfg->method->save_lmf);
3766 * Note: we can use ppc_r11 here because it is dead anyway:
3767 * we're leaving the method.
3769 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3770 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3771 if (ppc_is_imm16 (ret_offset)) {
3772 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3774 ppc_load (code, ppc_r11, ret_offset);
3775 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3777 ppc_mtlr (code, ppc_r0);
3780 if (ppc_is_imm16 (cfg->stack_usage)) {
3781 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3783 /* cfg->stack_usage is an int, so we can use
3784 * an addis/addi sequence here even in 64-bit. */
3785 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3786 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3788 if (!cfg->method->save_lmf) {
3790 for (i = 31; i >= 13; --i) {
3791 if (cfg->used_int_regs & (1 << i)) {
3792 pos += sizeof (gpointer);
3793 ppc_ldptr (code, i, -pos, ppc_r11);
3797 /* FIXME restore from MonoLMF: though this can't happen yet */
3800 /* Copy arguments on the stack to our argument area */
3801 if (call->stack_usage) {
3802 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3803 /* r11 was clobbered */
3804 g_assert (cfg->frame_reg == ppc_sp);
3805 if (ppc_is_imm16 (cfg->stack_usage)) {
3806 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3808 /* cfg->stack_usage is an int, so we can use
3809 * an addis/addi sequence here even in 64-bit. */
3810 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3811 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3815 ppc_mr (code, ppc_sp, ppc_r11);
3816 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3817 if (cfg->compile_aot) {
3818 /* arch_emit_got_access () patches this */
3819 ppc_load32 (code, ppc_r0, 0);
3820 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3821 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3822 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3824 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3826 ppc_mtctr (code, ppc_r0);
3827 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3834 /* ensure ins->sreg1 is not NULL */
3835 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3838 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3839 if (ppc_is_imm16 (cookie_offset)) {
3840 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3842 ppc_load (code, ppc_r0, cookie_offset);
3843 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3845 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3854 call = (MonoCallInst*)ins;
3855 if (ins->flags & MONO_INST_HAS_METHOD)
3856 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3858 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3859 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3860 ppc_load_func (code, ppc_r0, 0);
3861 ppc_mtlr (code, ppc_r0);
3866 /* FIXME: this should be handled somewhere else in the new jit */
3867 code = emit_move_return_value (cfg, ins, code);
3873 case OP_VOIDCALL_REG:
3875 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3876 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3877 /* FIXME: if we know that this is a method, we
3878 can omit this load */
3879 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3880 ppc_mtlr (code, ppc_r0);
3882 ppc_mtlr (code, ins->sreg1);
3885 /* FIXME: this should be handled somewhere else in the new jit */
3886 code = emit_move_return_value (cfg, ins, code);
3888 case OP_FCALL_MEMBASE:
3889 case OP_LCALL_MEMBASE:
3890 case OP_VCALL_MEMBASE:
3891 case OP_VCALL2_MEMBASE:
3892 case OP_VOIDCALL_MEMBASE:
3893 case OP_CALL_MEMBASE:
3894 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3895 /* The trampolines clobber this */
3896 ppc_mr (code, ppc_r29, ins->sreg1);
3897 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3899 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3901 ppc_mtlr (code, ppc_r0);
3903 /* FIXME: this should be handled somewhere else in the new jit */
3904 code = emit_move_return_value (cfg, ins, code);
3907 guint8 * zero_loop_jump, * zero_loop_start;
3908 /* keep alignment */
3909 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3910 int area_offset = alloca_waste;
3912 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3913 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3914 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3915 /* use ctr to store the number of words to 0 if needed */
3916 if (ins->flags & MONO_INST_INIT) {
3917 /* we zero 4 bytes at a time:
3918 * we add 7 instead of 3 so that we set the counter to
3919 * at least 1, otherwise the bdnz instruction will make
3920 * it negative and iterate billions of times.
3922 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3923 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3924 ppc_mtctr (code, ppc_r0);
3926 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3927 ppc_neg (code, ppc_r11, ppc_r11);
3928 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3930 /* FIXME: make this loop work in 8 byte
3931 increments on PPC64 */
3932 if (ins->flags & MONO_INST_INIT) {
3933 /* adjust the dest reg by -4 so we can use stwu */
3934 /* we actually adjust -8 because we let the loop
3937 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3938 ppc_li (code, ppc_r11, 0);
3939 zero_loop_start = code;
3940 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3941 zero_loop_jump = code;
3942 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3943 ppc_patch (zero_loop_jump, zero_loop_start);
3945 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3950 ppc_mr (code, ppc_r3, ins->sreg1);
3951 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3952 (gpointer)"mono_arch_throw_exception");
3953 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3954 ppc_load_func (code, ppc_r0, 0);
3955 ppc_mtlr (code, ppc_r0);
3964 ppc_mr (code, ppc_r3, ins->sreg1);
3965 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3966 (gpointer)"mono_arch_rethrow_exception");
3967 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3968 ppc_load_func (code, ppc_r0, 0);
3969 ppc_mtlr (code, ppc_r0);
3976 case OP_START_HANDLER: {
3977 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3978 g_assert (spvar->inst_basereg != ppc_sp);
3979 code = emit_reserve_param_area (cfg, code);
3980 ppc_mflr (code, ppc_r0);
3981 if (ppc_is_imm16 (spvar->inst_offset)) {
3982 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3984 ppc_load (code, ppc_r11, spvar->inst_offset);
3985 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3989 case OP_ENDFILTER: {
3990 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3991 g_assert (spvar->inst_basereg != ppc_sp);
3992 code = emit_unreserve_param_area (cfg, code);
3993 if (ins->sreg1 != ppc_r3)
3994 ppc_mr (code, ppc_r3, ins->sreg1);
3995 if (ppc_is_imm16 (spvar->inst_offset)) {
3996 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3998 ppc_load (code, ppc_r11, spvar->inst_offset);
3999 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4001 ppc_mtlr (code, ppc_r0);
4005 case OP_ENDFINALLY: {
4006 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4007 g_assert (spvar->inst_basereg != ppc_sp);
4008 code = emit_unreserve_param_area (cfg, code);
4009 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4010 ppc_mtlr (code, ppc_r0);
4014 case OP_CALL_HANDLER:
4015 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4017 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4020 ins->inst_c0 = code - cfg->native_code;
4023 /*if (ins->inst_target_bb->native_offset) {
4025 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4027 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4032 ppc_mtctr (code, ins->sreg1);
4033 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4037 CASE_PPC64 (OP_LCEQ)
4038 ppc_li (code, ins->dreg, 0);
4039 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4040 ppc_li (code, ins->dreg, 1);
4046 CASE_PPC64 (OP_LCLT)
4047 CASE_PPC64 (OP_LCLT_UN)
4048 ppc_li (code, ins->dreg, 1);
4049 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4050 ppc_li (code, ins->dreg, 0);
4056 CASE_PPC64 (OP_LCGT)
4057 CASE_PPC64 (OP_LCGT_UN)
4058 ppc_li (code, ins->dreg, 1);
4059 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4060 ppc_li (code, ins->dreg, 0);
4062 case OP_COND_EXC_EQ:
4063 case OP_COND_EXC_NE_UN:
4064 case OP_COND_EXC_LT:
4065 case OP_COND_EXC_LT_UN:
4066 case OP_COND_EXC_GT:
4067 case OP_COND_EXC_GT_UN:
4068 case OP_COND_EXC_GE:
4069 case OP_COND_EXC_GE_UN:
4070 case OP_COND_EXC_LE:
4071 case OP_COND_EXC_LE_UN:
4072 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4074 case OP_COND_EXC_IEQ:
4075 case OP_COND_EXC_INE_UN:
4076 case OP_COND_EXC_ILT:
4077 case OP_COND_EXC_ILT_UN:
4078 case OP_COND_EXC_IGT:
4079 case OP_COND_EXC_IGT_UN:
4080 case OP_COND_EXC_IGE:
4081 case OP_COND_EXC_IGE_UN:
4082 case OP_COND_EXC_ILE:
4083 case OP_COND_EXC_ILE_UN:
4084 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4096 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4099 /* floating point opcodes */
4101 g_assert (cfg->compile_aot);
4103 /* FIXME: Optimize this */
4105 ppc_mflr (code, ppc_r11);
4107 *(double*)code = *(double*)ins->inst_p0;
4109 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4112 g_assert_not_reached ();
4114 case OP_STORER8_MEMBASE_REG:
4115 if (ppc_is_imm16 (ins->inst_offset)) {
4116 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4118 if (ppc_is_imm32 (ins->inst_offset)) {
4119 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4120 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4122 ppc_load (code, ppc_r0, ins->inst_offset);
4123 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4127 case OP_LOADR8_MEMBASE:
4128 if (ppc_is_imm16 (ins->inst_offset)) {
4129 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4131 if (ppc_is_imm32 (ins->inst_offset)) {
4132 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4133 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4135 ppc_load (code, ppc_r0, ins->inst_offset);
4136 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4140 case OP_STORER4_MEMBASE_REG:
4141 ppc_frsp (code, ins->sreg1, ins->sreg1);
4142 if (ppc_is_imm16 (ins->inst_offset)) {
4143 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4145 if (ppc_is_imm32 (ins->inst_offset)) {
4146 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4147 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4149 ppc_load (code, ppc_r0, ins->inst_offset);
4150 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4154 case OP_LOADR4_MEMBASE:
4155 if (ppc_is_imm16 (ins->inst_offset)) {
4156 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4158 if (ppc_is_imm32 (ins->inst_offset)) {
4159 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4160 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4162 ppc_load (code, ppc_r0, ins->inst_offset);
4163 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4167 case OP_LOADR4_MEMINDEX:
4168 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4170 case OP_LOADR8_MEMINDEX:
4171 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4173 case OP_STORER4_MEMINDEX:
4174 ppc_frsp (code, ins->sreg1, ins->sreg1);
4175 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4177 case OP_STORER8_MEMINDEX:
4178 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4181 case CEE_CONV_R4: /* FIXME: change precision */
4183 g_assert_not_reached ();
4184 case OP_FCONV_TO_I1:
4185 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4187 case OP_FCONV_TO_U1:
4188 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4190 case OP_FCONV_TO_I2:
4191 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4193 case OP_FCONV_TO_U2:
4194 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4196 case OP_FCONV_TO_I4:
4198 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4200 case OP_FCONV_TO_U4:
4202 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4204 case OP_LCONV_TO_R_UN:
4205 g_assert_not_reached ();
4206 /* Implemented as helper calls */
4208 case OP_LCONV_TO_OVF_I4_2:
4209 case OP_LCONV_TO_OVF_I: {
4210 #ifdef __mono_ppc64__
4213 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4214 // Check if its negative
4215 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4216 negative_branch = code;
4217 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4218 // Its positive msword == 0
4219 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4220 msword_positive_branch = code;
4221 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4223 ovf_ex_target = code;
4224 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4226 ppc_patch (negative_branch, code);
4227 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4228 msword_negative_branch = code;
4229 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4230 ppc_patch (msword_negative_branch, ovf_ex_target);
4232 ppc_patch (msword_positive_branch, code);
4233 if (ins->dreg != ins->sreg1)
4234 ppc_mr (code, ins->dreg, ins->sreg1);
4239 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4242 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4245 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4248 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4251 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4254 ppc_fneg (code, ins->dreg, ins->sreg1);
4258 g_assert_not_reached ();
4261 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4264 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4265 ppc_li (code, ins->dreg, 0);
4266 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4267 ppc_li (code, ins->dreg, 1);
4270 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4271 ppc_li (code, ins->dreg, 1);
4272 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4273 ppc_li (code, ins->dreg, 0);
4276 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4277 ppc_li (code, ins->dreg, 1);
4278 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4279 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4280 ppc_li (code, ins->dreg, 0);
4283 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4284 ppc_li (code, ins->dreg, 1);
4285 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4286 ppc_li (code, ins->dreg, 0);
4289 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4290 ppc_li (code, ins->dreg, 1);
4291 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4292 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4293 ppc_li (code, ins->dreg, 0);
4296 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4299 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4302 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4303 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4306 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4307 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4310 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4311 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4314 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4315 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4318 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4319 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4322 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4325 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4326 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4329 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4332 g_assert_not_reached ();
4333 case OP_CHECK_FINITE: {
4334 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4335 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4336 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4337 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4340 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4341 #ifdef __mono_ppc64__
4342 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4344 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4349 #ifdef __mono_ppc64__
4350 case OP_ICONV_TO_I4:
4352 ppc_extsw (code, ins->dreg, ins->sreg1);
4354 case OP_ICONV_TO_U4:
4356 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4358 case OP_ICONV_TO_R4:
4359 case OP_ICONV_TO_R8:
4360 case OP_LCONV_TO_R4:
4361 case OP_LCONV_TO_R8: {
4363 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4364 ppc_extsw (code, ppc_r0, ins->sreg1);
4369 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4370 ppc_mffgpr (code, ins->dreg, tmp);
4372 ppc_str (code, tmp, -8, ppc_r1);
4373 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4375 ppc_fcfid (code, ins->dreg, ins->dreg);
4376 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4377 ppc_frsp (code, ins->dreg, ins->dreg);
4381 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4384 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4387 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4389 ppc_mfspr (code, ppc_r0, ppc_xer);
4390 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4391 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4393 case OP_COND_EXC_OV:
4394 ppc_mfspr (code, ppc_r0, ppc_xer);
4395 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4396 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4408 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4410 case OP_FCONV_TO_I8:
4411 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4413 case OP_FCONV_TO_U8:
4414 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4416 case OP_STOREI4_MEMBASE_REG:
4417 if (ppc_is_imm16 (ins->inst_offset)) {
4418 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4420 ppc_load (code, ppc_r0, ins->inst_offset);
4421 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4424 case OP_STOREI4_MEMINDEX:
4425 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4428 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4430 case OP_ISHR_UN_IMM:
4431 if (ins->inst_imm & 0x1f)
4432 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4434 ppc_mr (code, ins->dreg, ins->sreg1);
4436 case OP_ATOMIC_ADD_NEW_I4:
4437 case OP_ATOMIC_ADD_NEW_I8: {
4438 guint8 *loop = code, *branch;
4439 g_assert (ins->inst_offset == 0);
4440 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4441 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4443 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4444 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4445 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4446 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4448 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4450 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4451 ppc_patch (branch, loop);
4452 ppc_mr (code, ins->dreg, ppc_r0);
4456 case OP_ICONV_TO_R4:
4457 case OP_ICONV_TO_R8: {
4458 if (cpu_hw_caps & PPC_ISA_64) {
4459 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4460 ppc_stw (code, ppc_r0, -8, ppc_r1);
4461 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4462 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4463 ppc_fcfid (code, ins->dreg, ins->dreg);
4464 if (ins->opcode == OP_ICONV_TO_R4)
4465 ppc_frsp (code, ins->dreg, ins->dreg);
4470 case OP_ATOMIC_CAS_I4:
4471 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4472 int location = ins->sreg1;
4473 int value = ins->sreg2;
4474 int comparand = ins->sreg3;
4475 guint8 *start, *not_equal, *lost_reservation;
4478 if (ins->opcode == OP_ATOMIC_CAS_I4)
4479 ppc_lwarx (code, ppc_r0, 0, location);
4480 #ifdef __mono_ppc64__
4482 ppc_ldarx (code, ppc_r0, 0, location);
4484 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4487 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4488 if (ins->opcode == OP_ATOMIC_CAS_I4)
4489 ppc_stwcxd (code, value, 0, location);
4490 #ifdef __mono_ppc64__
4492 ppc_stdcxd (code, value, 0, location);
4495 lost_reservation = code;
4496 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4497 ppc_patch (lost_reservation, start);
4499 ppc_patch (not_equal, code);
4500 ppc_mr (code, ins->dreg, ppc_r0);
4505 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4506 g_assert_not_reached ();
4509 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4510 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4511 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4512 g_assert_not_reached ();
4518 last_offset = offset;
4521 cfg->code_len = code - cfg->native_code;
4523 #endif /* !DISABLE_JIT */
4526 mono_arch_register_lowlevel_calls (void)
4528 /* The signature doesn't matter */
4529 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4532 #ifdef __mono_ppc64__
4533 #define patch_load_sequence(ip,val) do {\
4534 guint16 *__load = (guint16*)(ip); \
4535 g_assert (sizeof (val) == sizeof (gsize)); \
4536 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4537 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4538 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4539 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4542 #define patch_load_sequence(ip,val) do {\
4543 guint16 *__lis_ori = (guint16*)(ip); \
4544 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4545 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4551 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4553 MonoJumpInfo *patch_info;
4554 gboolean compile_aot = !run_cctors;
4556 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4557 unsigned char *ip = patch_info->ip.i + code;
4558 unsigned char *target;
4559 gboolean is_fd = FALSE;
4561 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4564 switch (patch_info->type) {
4565 case MONO_PATCH_INFO_BB:
4566 case MONO_PATCH_INFO_LABEL:
4569 /* No need to patch these */
4574 switch (patch_info->type) {
4575 case MONO_PATCH_INFO_IP:
4576 patch_load_sequence (ip, ip);
4578 case MONO_PATCH_INFO_METHOD_REL:
4579 g_assert_not_reached ();
4580 *((gpointer *)(ip)) = code + patch_info->data.offset;
4582 case MONO_PATCH_INFO_SWITCH: {
4583 gpointer *table = (gpointer *)patch_info->data.table->table;
4586 patch_load_sequence (ip, table);
4588 for (i = 0; i < patch_info->data.table->table_size; i++) {
4589 table [i] = (glong)patch_info->data.table->table [i] + code;
4591 /* we put into the table the absolute address, no need for ppc_patch in this case */
4594 case MONO_PATCH_INFO_METHODCONST:
4595 case MONO_PATCH_INFO_CLASS:
4596 case MONO_PATCH_INFO_IMAGE:
4597 case MONO_PATCH_INFO_FIELD:
4598 case MONO_PATCH_INFO_VTABLE:
4599 case MONO_PATCH_INFO_IID:
4600 case MONO_PATCH_INFO_SFLDA:
4601 case MONO_PATCH_INFO_LDSTR:
4602 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4603 case MONO_PATCH_INFO_LDTOKEN:
4604 /* from OP_AOTCONST : lis + ori */
4605 patch_load_sequence (ip, target);
4607 case MONO_PATCH_INFO_R4:
4608 case MONO_PATCH_INFO_R8:
4609 g_assert_not_reached ();
4610 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4612 case MONO_PATCH_INFO_EXC_NAME:
4613 g_assert_not_reached ();
4614 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4616 case MONO_PATCH_INFO_NONE:
4617 case MONO_PATCH_INFO_BB_OVF:
4618 case MONO_PATCH_INFO_EXC_OVF:
4619 /* everything is dealt with at epilog output time */
4621 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4622 case MONO_PATCH_INFO_INTERNAL_METHOD:
4623 case MONO_PATCH_INFO_ABS:
4624 case MONO_PATCH_INFO_CLASS_INIT:
4625 case MONO_PATCH_INFO_RGCTX_FETCH:
4632 ppc_patch_full (ip, target, is_fd);
4637 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4638 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4639 * the instruction offset immediate for all the registers.
4642 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4646 for (i = 13; i <= 31; i++) {
4647 if (used_int_regs & (1 << i)) {
4648 ppc_str (code, i, pos, base_reg);
4649 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4650 pos += sizeof (mgreg_t);
4654 /* pos is the start of the MonoLMF structure */
4655 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4656 for (i = 13; i <= 31; i++) {
4657 ppc_str (code, i, offset, base_reg);
4658 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4659 offset += sizeof (mgreg_t);
4661 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4662 for (i = 14; i < 32; i++) {
4663 ppc_stfd (code, i, offset, base_reg);
4664 offset += sizeof (gdouble);
4671 * Stack frame layout:
4673 * ------------------- sp
4674 * MonoLMF structure or saved registers
4675 * -------------------
4677 * -------------------
4679 * -------------------
4680 * optional 8 bytes for tracing
4681 * -------------------
4682 * param area size is cfg->param_area
4683 * -------------------
4684 * linkage area size is PPC_STACK_PARAM_OFFSET
4685 * ------------------- sp
4689 mono_arch_emit_prolog (MonoCompile *cfg)
4691 MonoMethod *method = cfg->method;
4693 MonoMethodSignature *sig;
4695 long alloc_size, pos, max_offset, cfa_offset;
4701 int tailcall_struct_index;
4703 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4706 sig = mono_method_signature (method);
4707 cfg->code_size = 512 + sig->param_count * 32;
4708 code = cfg->native_code = g_malloc (cfg->code_size);
4712 /* We currently emit unwind info for aot, but don't use it */
4713 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4715 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4716 ppc_mflr (code, ppc_r0);
4717 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4718 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4721 alloc_size = cfg->stack_offset;
4724 if (!method->save_lmf) {
4725 for (i = 31; i >= 13; --i) {
4726 if (cfg->used_int_regs & (1 << i)) {
4727 pos += sizeof (mgreg_t);
4731 pos += sizeof (MonoLMF);
4735 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4736 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4737 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4738 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4741 cfg->stack_usage = alloc_size;
4742 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4744 if (ppc_is_imm16 (-alloc_size)) {
4745 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4746 cfa_offset = alloc_size;
4747 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4748 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4751 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4752 ppc_load (code, ppc_r0, -alloc_size);
4753 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4754 cfa_offset = alloc_size;
4755 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4756 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4759 if (cfg->frame_reg != ppc_sp) {
4760 ppc_mr (code, cfg->frame_reg, ppc_sp);
4761 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4764 /* store runtime generic context */
4765 if (cfg->rgctx_var) {
4766 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4767 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4769 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4772 /* compute max_offset in order to use short forward jumps
4773 * we always do it on ppc because the immediate displacement
4774 * for jumps is too small
4777 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4779 bb->max_offset = max_offset;
4781 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4784 MONO_BB_FOR_EACH_INS (bb, ins)
4785 max_offset += ins_native_length (cfg, ins);
4788 /* load arguments allocated to register from the stack */
4791 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4793 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4794 ArgInfo *ainfo = &cinfo->ret;
4796 inst = cfg->vret_addr;
4799 if (ppc_is_imm16 (inst->inst_offset)) {
4800 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4802 ppc_load (code, ppc_r11, inst->inst_offset);
4803 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4807 tailcall_struct_index = 0;
4808 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4809 ArgInfo *ainfo = cinfo->args + i;
4810 inst = cfg->args [pos];
4812 if (cfg->verbose_level > 2)
4813 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4814 if (inst->opcode == OP_REGVAR) {
4815 if (ainfo->regtype == RegTypeGeneral)
4816 ppc_mr (code, inst->dreg, ainfo->reg);
4817 else if (ainfo->regtype == RegTypeFP)
4818 ppc_fmr (code, inst->dreg, ainfo->reg);
4819 else if (ainfo->regtype == RegTypeBase) {
4820 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4821 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4823 g_assert_not_reached ();
4825 if (cfg->verbose_level > 2)
4826 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4828 /* the argument should be put on the stack: FIXME handle size != word */
4829 if (ainfo->regtype == RegTypeGeneral) {
4830 switch (ainfo->size) {
4832 if (ppc_is_imm16 (inst->inst_offset)) {
4833 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4835 if (ppc_is_imm32 (inst->inst_offset)) {
4836 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4837 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4839 ppc_load (code, ppc_r11, inst->inst_offset);
4840 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4845 if (ppc_is_imm16 (inst->inst_offset)) {
4846 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4848 if (ppc_is_imm32 (inst->inst_offset)) {
4849 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4850 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4852 ppc_load (code, ppc_r11, inst->inst_offset);
4853 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4857 #ifdef __mono_ppc64__
4859 if (ppc_is_imm16 (inst->inst_offset)) {
4860 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4862 if (ppc_is_imm32 (inst->inst_offset)) {
4863 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4864 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4866 ppc_load (code, ppc_r11, inst->inst_offset);
4867 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4872 if (ppc_is_imm16 (inst->inst_offset)) {
4873 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4875 ppc_load (code, ppc_r11, inst->inst_offset);
4876 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4881 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4882 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4883 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4885 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4886 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4887 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4888 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4893 if (ppc_is_imm16 (inst->inst_offset)) {
4894 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4896 if (ppc_is_imm32 (inst->inst_offset)) {
4897 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4898 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4900 ppc_load (code, ppc_r11, inst->inst_offset);
4901 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4906 } else if (ainfo->regtype == RegTypeBase) {
4907 g_assert (ppc_is_imm16 (ainfo->offset));
4908 /* load the previous stack pointer in r11 */
4909 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4910 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4911 switch (ainfo->size) {
4913 if (ppc_is_imm16 (inst->inst_offset)) {
4914 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4916 if (ppc_is_imm32 (inst->inst_offset)) {
4917 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4918 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4920 ppc_load (code, ppc_r11, inst->inst_offset);
4921 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4926 if (ppc_is_imm16 (inst->inst_offset)) {
4927 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4929 if (ppc_is_imm32 (inst->inst_offset)) {
4930 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4931 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4933 ppc_load (code, ppc_r11, inst->inst_offset);
4934 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4938 #ifdef __mono_ppc64__
4940 if (ppc_is_imm16 (inst->inst_offset)) {
4941 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4943 if (ppc_is_imm32 (inst->inst_offset)) {
4944 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4945 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4947 ppc_load (code, ppc_r11, inst->inst_offset);
4948 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4953 if (ppc_is_imm16 (inst->inst_offset)) {
4954 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4956 ppc_load (code, ppc_r11, inst->inst_offset);
4957 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4962 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4963 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4964 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4965 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4966 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4968 /* use r12 to load the 2nd half of the long before we clobber r11. */
4969 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4970 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4971 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4972 ppc_stw (code, ppc_r0, 0, ppc_r11);
4973 ppc_stw (code, ppc_r12, 4, ppc_r11);
4978 if (ppc_is_imm16 (inst->inst_offset)) {
4979 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4981 if (ppc_is_imm32 (inst->inst_offset)) {
4982 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4983 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4985 ppc_load (code, ppc_r11, inst->inst_offset);
4986 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4991 } else if (ainfo->regtype == RegTypeFP) {
4992 g_assert (ppc_is_imm16 (inst->inst_offset));
4993 if (ainfo->size == 8)
4994 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4995 else if (ainfo->size == 4)
4996 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4998 g_assert_not_reached ();
4999 } else if (ainfo->regtype == RegTypeStructByVal) {
5000 int doffset = inst->inst_offset;
5004 g_assert (ppc_is_imm16 (inst->inst_offset));
5005 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5006 /* FIXME: what if there is no class? */
5007 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5008 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5009 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5012 * Darwin handles 1 and 2 byte
5013 * structs specially by
5014 * loading h/b into the arg
5015 * register. Only done for
5019 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5021 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5025 #ifdef __mono_ppc64__
5027 g_assert (cur_reg == 0);
5028 ppc_sldi (code, ppc_r0, ainfo->reg,
5029 (sizeof (gpointer) - ainfo->bytes) * 8);
5030 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5034 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5035 inst->inst_basereg);
5038 soffset += sizeof (gpointer);
5039 doffset += sizeof (gpointer);
5041 if (ainfo->vtsize) {
5042 /* FIXME: we need to do the shifting here, too */
5045 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5046 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5047 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5048 code = emit_memcpy (code, size - soffset,
5049 inst->inst_basereg, doffset,
5050 ppc_r11, ainfo->offset + soffset);
5052 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5053 inst->inst_basereg, doffset,
5054 ppc_r11, ainfo->offset + soffset);
5057 } else if (ainfo->regtype == RegTypeStructByAddr) {
5058 /* if it was originally a RegTypeBase */
5059 if (ainfo->offset) {
5060 /* load the previous stack pointer in r11 */
5061 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5062 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5064 ppc_mr (code, ppc_r11, ainfo->reg);
5067 if (cfg->tailcall_valuetype_addrs) {
5068 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5070 g_assert (ppc_is_imm16 (addr->inst_offset));
5071 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5073 tailcall_struct_index++;
5076 g_assert (ppc_is_imm16 (inst->inst_offset));
5077 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5078 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5080 g_assert_not_reached ();
5085 if (method->save_lmf) {
5086 if (lmf_pthread_key != -1) {
5087 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5088 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5089 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5091 if (cfg->compile_aot) {
5092 /* Compute the got address which is needed by the PLT entry */
5093 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5095 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5096 (gpointer)"mono_get_lmf_addr");
5097 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5098 ppc_load_func (code, ppc_r0, 0);
5099 ppc_mtlr (code, ppc_r0);
5105 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5106 /* lmf_offset is the offset from the previous stack pointer,
5107 * alloc_size is the total stack space allocated, so the offset
5108 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5109 * The pointer to the struct is put in ppc_r11 (new_lmf).
5110 * The callee-saved registers are already in the MonoLMF structure
5112 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5113 /* ppc_r3 is the result from mono_get_lmf_addr () */
5114 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5115 /* new_lmf->previous_lmf = *lmf_addr */
5116 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5117 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5118 /* *(lmf_addr) = r11 */
5119 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5120 /* save method info */
5121 if (cfg->compile_aot)
5123 ppc_load (code, ppc_r0, 0);
5125 ppc_load_ptr (code, ppc_r0, method);
5126 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5127 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5128 /* save the current IP */
5129 if (cfg->compile_aot) {
5131 ppc_mflr (code, ppc_r0);
5133 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5134 #ifdef __mono_ppc64__
5135 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5137 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5140 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5144 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5146 cfg->code_len = code - cfg->native_code;
5147 g_assert (cfg->code_len <= cfg->code_size);
5154 mono_arch_emit_epilog (MonoCompile *cfg)
5156 MonoMethod *method = cfg->method;
5158 int max_epilog_size = 16 + 20*4;
5161 if (cfg->method->save_lmf)
5162 max_epilog_size += 128;
5164 if (mono_jit_trace_calls != NULL)
5165 max_epilog_size += 50;
5167 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5168 max_epilog_size += 50;
5170 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5171 cfg->code_size *= 2;
5172 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5173 cfg->stat_code_reallocs++;
5177 * Keep in sync with OP_JMP
5179 code = cfg->native_code + cfg->code_len;
5181 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5182 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5186 if (method->save_lmf) {
5188 pos += sizeof (MonoLMF);
5190 /* save the frame reg in r8 */
5191 ppc_mr (code, ppc_r8, cfg->frame_reg);
5192 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5193 /* r5 = previous_lmf */
5194 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5196 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5197 /* *(lmf_addr) = previous_lmf */
5198 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5199 /* FIXME: speedup: there is no actual need to restore the registers if
5200 * we didn't actually change them (idea from Zoltan).
5203 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5205 /*for (i = 14; i < 32; i++) {
5206 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5208 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5209 /* use the saved copy of the frame reg in r8 */
5210 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5211 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5212 ppc_mtlr (code, ppc_r0);
5214 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5216 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5217 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5218 if (ppc_is_imm16 (return_offset)) {
5219 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5221 ppc_load (code, ppc_r11, return_offset);
5222 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5224 ppc_mtlr (code, ppc_r0);
5226 if (ppc_is_imm16 (cfg->stack_usage)) {
5227 int offset = cfg->stack_usage;
5228 for (i = 13; i <= 31; i++) {
5229 if (cfg->used_int_regs & (1 << i))
5230 offset -= sizeof (mgreg_t);
5232 if (cfg->frame_reg != ppc_sp)
5233 ppc_mr (code, ppc_r11, cfg->frame_reg);
5234 /* note r31 (possibly the frame register) is restored last */
5235 for (i = 13; i <= 31; i++) {
5236 if (cfg->used_int_regs & (1 << i)) {
5237 ppc_ldr (code, i, offset, cfg->frame_reg);
5238 offset += sizeof (mgreg_t);
5241 if (cfg->frame_reg != ppc_sp)
5242 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5244 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5246 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5247 if (cfg->used_int_regs) {
5248 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5249 for (i = 31; i >= 13; --i) {
5250 if (cfg->used_int_regs & (1 << i)) {
5251 pos += sizeof (mgreg_t);
5252 ppc_ldr (code, i, -pos, ppc_r11);
5255 ppc_mr (code, ppc_sp, ppc_r11);
5257 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5264 cfg->code_len = code - cfg->native_code;
5266 g_assert (cfg->code_len < cfg->code_size);
5269 #endif /* ifndef DISABLE_JIT */
5271 /* remove once throw_exception_by_name is eliminated */
5273 exception_id_by_name (const char *name)
5275 if (strcmp (name, "IndexOutOfRangeException") == 0)
5276 return MONO_EXC_INDEX_OUT_OF_RANGE;
5277 if (strcmp (name, "OverflowException") == 0)
5278 return MONO_EXC_OVERFLOW;
5279 if (strcmp (name, "ArithmeticException") == 0)
5280 return MONO_EXC_ARITHMETIC;
5281 if (strcmp (name, "DivideByZeroException") == 0)
5282 return MONO_EXC_DIVIDE_BY_ZERO;
5283 if (strcmp (name, "InvalidCastException") == 0)
5284 return MONO_EXC_INVALID_CAST;
5285 if (strcmp (name, "NullReferenceException") == 0)
5286 return MONO_EXC_NULL_REF;
5287 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5288 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5289 if (strcmp (name, "ArgumentException") == 0)
5290 return MONO_EXC_ARGUMENT;
5291 g_error ("Unknown intrinsic exception %s\n", name);
5297 mono_arch_emit_exceptions (MonoCompile *cfg)
5299 MonoJumpInfo *patch_info;
5302 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5303 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5304 int max_epilog_size = 50;
5306 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5307 exc_throw_pos [i] = NULL;
5308 exc_throw_found [i] = 0;
5311 /* count the number of exception infos */
5314 * make sure we have enough space for exceptions
5316 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5317 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5318 i = exception_id_by_name (patch_info->data.target);
5319 if (!exc_throw_found [i]) {
5320 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5321 exc_throw_found [i] = TRUE;
5323 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5324 max_epilog_size += 12;
5325 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5326 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5327 i = exception_id_by_name (ovfj->data.exception);
5328 if (!exc_throw_found [i]) {
5329 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5330 exc_throw_found [i] = TRUE;
5332 max_epilog_size += 8;
5336 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5337 cfg->code_size *= 2;
5338 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5339 cfg->stat_code_reallocs++;
5342 code = cfg->native_code + cfg->code_len;
5344 /* add code to raise exceptions */
5345 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5346 switch (patch_info->type) {
5347 case MONO_PATCH_INFO_BB_OVF: {
5348 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5349 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5350 /* patch the initial jump */
5351 ppc_patch (ip, code);
5352 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5354 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5355 /* jump back to the true target */
5357 ip = ovfj->data.bb->native_offset + cfg->native_code;
5358 ppc_patch (code - 4, ip);
5359 patch_info->type = MONO_PATCH_INFO_NONE;
5362 case MONO_PATCH_INFO_EXC_OVF: {
5363 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5364 MonoJumpInfo *newji;
5365 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5366 unsigned char *bcl = code;
5367 /* patch the initial jump: we arrived here with a call */
5368 ppc_patch (ip, code);
5369 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5371 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5372 /* patch the conditional jump to the right handler */
5373 /* make it processed next */
5374 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5375 newji->type = MONO_PATCH_INFO_EXC;
5376 newji->ip.i = bcl - cfg->native_code;
5377 newji->data.target = ovfj->data.exception;
5378 newji->next = patch_info->next;
5379 patch_info->next = newji;
5380 patch_info->type = MONO_PATCH_INFO_NONE;
5383 case MONO_PATCH_INFO_EXC: {
5384 MonoClass *exc_class;
5386 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5387 i = exception_id_by_name (patch_info->data.target);
5388 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5389 ppc_patch (ip, exc_throw_pos [i]);
5390 patch_info->type = MONO_PATCH_INFO_NONE;
5393 exc_throw_pos [i] = code;
5396 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5397 g_assert (exc_class);
5399 ppc_patch (ip, code);
5400 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5401 ppc_load (code, ppc_r3, exc_class->type_token);
5402 /* we got here from a conditional call, so the calling ip is set in lr */
5403 ppc_mflr (code, ppc_r4);
5404 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5405 patch_info->data.name = "mono_arch_throw_corlib_exception";
5406 patch_info->ip.i = code - cfg->native_code;
5407 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5408 ppc_load_func (code, ppc_r0, 0);
5409 ppc_mtctr (code, ppc_r0);
5410 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5422 cfg->code_len = code - cfg->native_code;
5424 g_assert (cfg->code_len <= cfg->code_size);
5430 try_offset_access (void *value, guint32 idx)
5432 register void* me __asm__ ("r2");
5433 void ***p = (void***)((char*)me + 284);
5434 int idx1 = idx / 32;
5435 int idx2 = idx % 32;
5438 if (value != p[idx1][idx2])
5445 setup_tls_access (void)
5449 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5450 size_t conf_size = 0;
5453 /* FIXME for darwin */
5454 guint32 *ins, *code;
5455 guint32 cmplwi_1023, li_0x48, blr_ins;
5459 tls_mode = TLS_MODE_FAILED;
5462 if (tls_mode == TLS_MODE_FAILED)
5464 if (g_getenv ("MONO_NO_TLS")) {
5465 tls_mode = TLS_MODE_FAILED;
5469 if (tls_mode == TLS_MODE_DETECT) {
5470 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5471 tls_mode = TLS_MODE_DARWIN_G4;
5472 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5473 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5474 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5475 tls_mode = TLS_MODE_NPTL;
5476 #elif !defined(TARGET_PS3)
5477 ins = (guint32*)pthread_getspecific;
5478 /* uncond branch to the real method */
5479 if ((*ins >> 26) == 18) {
5481 val = (*ins & ~3) << 6;
5485 ins = (guint32*)(long)val;
5487 ins = (guint32*) ((char*)ins + val);
5490 code = &cmplwi_1023;
5491 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5493 ppc_li (code, ppc_r4, 0x48);
5496 if (*ins == cmplwi_1023) {
5497 int found_lwz_284 = 0;
5498 for (ptk = 0; ptk < 20; ++ptk) {
5500 if (!*ins || *ins == blr_ins)
5502 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5507 if (!found_lwz_284) {
5508 tls_mode = TLS_MODE_FAILED;
5511 tls_mode = TLS_MODE_LTHREADS;
5512 } else if (*ins == li_0x48) {
5514 /* uncond branch to the real method */
5515 if ((*ins >> 26) == 18) {
5517 val = (*ins & ~3) << 6;
5521 ins = (guint32*)(long)val;
5523 ins = (guint32*) ((char*)ins + val);
5525 code = (guint32*)&val;
5526 ppc_li (code, ppc_r0, 0x7FF2);
5527 if (ins [1] == val) {
5528 /* Darwin on G4, implement */
5529 tls_mode = TLS_MODE_FAILED;
5532 code = (guint32*)&val;
5533 ppc_mfspr (code, ppc_r3, 104);
5534 if (ins [1] != val) {
5535 tls_mode = TLS_MODE_FAILED;
5538 tls_mode = TLS_MODE_DARWIN_G5;
5541 tls_mode = TLS_MODE_FAILED;
5545 tls_mode = TLS_MODE_FAILED;
5551 if (tls_mode == TLS_MODE_DETECT)
5552 tls_mode = TLS_MODE_FAILED;
5553 if (tls_mode == TLS_MODE_FAILED)
5555 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5556 monodomain_key = mono_domain_get_tls_offset();
5558 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5559 mono_domain_get_tls_offset returning -1) then use keyed access. */
5560 if (monodomain_key == -1) {
5561 ptk = mono_domain_get_tls_key ();
5563 monodomain_key = ptk;
5566 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5567 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5571 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5572 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5573 if (lmf_pthread_key == -1) {
5574 ptk = mono_jit_tls_id;
5576 /*g_print ("MonoLMF at: %d\n", ptk);*/
5577 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5578 init_tls_failed = 1;
5581 lmf_pthread_key = ptk;
5590 mono_arch_finish_init (void)
5592 setup_tls_access ();
5596 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5600 #ifdef MONO_ARCH_HAVE_IMT
5602 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5604 #define LOADSTORE_SIZE 4
5605 #define JUMP_IMM_SIZE 12
5606 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5607 #define ENABLE_WRONG_METHOD_CHECK 0
5610 * LOCKING: called with the domain lock held
5613 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5614 gpointer fail_tramp)
5618 guint8 *code, *start;
5620 for (i = 0; i < count; ++i) {
5621 MonoIMTCheckItem *item = imt_entries [i];
5622 if (item->is_equals) {
5623 if (item->check_target_idx) {
5624 if (!item->compare_done)
5625 item->chunk_size += CMP_SIZE;
5626 if (item->has_target_code)
5627 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5629 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5632 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5633 if (!item->has_target_code)
5634 item->chunk_size += LOADSTORE_SIZE;
5636 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5637 #if ENABLE_WRONG_METHOD_CHECK
5638 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5643 item->chunk_size += CMP_SIZE + BR_SIZE;
5644 imt_entries [item->check_target_idx]->compare_done = TRUE;
5646 size += item->chunk_size;
5648 /* the initial load of the vtable address */
5649 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5651 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5653 code = mono_domain_code_reserve (domain, size);
5658 * We need to save and restore r11 because it might be
5659 * used by the caller as the vtable register, so
5660 * clobbering it will trip up the magic trampoline.
5662 * FIXME: Get rid of this by making sure that r11 is
5663 * not used as the vtable register in interface calls.
5665 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5666 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5668 for (i = 0; i < count; ++i) {
5669 MonoIMTCheckItem *item = imt_entries [i];
5670 item->code_target = code;
5671 if (item->is_equals) {
5672 if (item->check_target_idx) {
5673 if (!item->compare_done) {
5674 ppc_load (code, ppc_r0, (gsize)item->key);
5675 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5677 item->jmp_code = code;
5678 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5679 if (item->has_target_code) {
5680 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5682 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5683 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5685 ppc_mtctr (code, ppc_r0);
5686 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5689 ppc_load (code, ppc_r0, (gulong)item->key);
5690 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5691 item->jmp_code = code;
5692 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5693 if (item->has_target_code) {
5694 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5697 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5698 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5700 ppc_mtctr (code, ppc_r0);
5701 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5702 ppc_patch (item->jmp_code, code);
5703 ppc_load_ptr (code, ppc_r0, fail_tramp);
5704 ppc_mtctr (code, ppc_r0);
5705 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5706 item->jmp_code = NULL;
5708 /* enable the commented code to assert on wrong method */
5709 #if ENABLE_WRONG_METHOD_CHECK
5710 ppc_load (code, ppc_r0, (guint32)item->key);
5711 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5712 item->jmp_code = code;
5713 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5715 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5716 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5717 ppc_mtctr (code, ppc_r0);
5718 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5719 #if ENABLE_WRONG_METHOD_CHECK
5720 ppc_patch (item->jmp_code, code);
5722 item->jmp_code = NULL;
5727 ppc_load (code, ppc_r0, (gulong)item->key);
5728 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5729 item->jmp_code = code;
5730 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5733 /* patch the branches to get to the target items */
5734 for (i = 0; i < count; ++i) {
5735 MonoIMTCheckItem *item = imt_entries [i];
5736 if (item->jmp_code) {
5737 if (item->check_target_idx) {
5738 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5744 mono_stats.imt_thunks_size += code - start;
5745 g_assert (code - start <= size);
5746 mono_arch_flush_icache (start, size);
5751 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5753 mgreg_t *r = (mgreg_t*)regs;
5755 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5760 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5762 mgreg_t *r = (mgreg_t*)regs;
5764 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5768 mono_arch_get_cie_program (void)
5772 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5778 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5785 mono_arch_print_tree (MonoInst *tree, int arity)
5790 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5794 setup_tls_access ();
5795 if (monodomain_key == -1)
5798 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5799 ins->inst_offset = monodomain_key;
5804 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5807 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5809 g_assert (reg >= ppc_r13);
5811 return ctx->regs [reg - ppc_r13];
5815 mono_arch_get_patch_offset (guint8 *code)
5821 * mono_aot_emit_load_got_addr:
5823 * Emit code to load the got address.
5824 * On PPC, the result is placed into r30.
5827 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5830 ppc_mflr (code, ppc_r30);
5832 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5834 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5835 /* arch_emit_got_address () patches this */
5836 #if defined(TARGET_POWERPC64)
5842 ppc_load32 (code, ppc_r0, 0);
5843 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5850 * mono_ppc_emit_load_aotconst:
5852 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5853 * TARGET from the mscorlib GOT in full-aot code.
5854 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5858 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5860 /* Load the mscorlib got address */
5861 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5862 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5863 /* arch_emit_got_access () patches this */
5864 ppc_load32 (code, ppc_r0, 0);
5865 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5870 /* Soft Debug support */
5871 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5878 * mono_arch_set_breakpoint:
5880 * See mini-amd64.c for docs.
5883 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5886 guint8 *orig_code = code;
5888 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5889 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5891 g_assert (code - orig_code == BREAKPOINT_SIZE);
5893 mono_arch_flush_icache (orig_code, code - orig_code);
5897 * mono_arch_clear_breakpoint:
5899 * See mini-amd64.c for docs.
5902 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5907 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5910 mono_arch_flush_icache (ip, code - ip);
5914 * mono_arch_is_breakpoint_event:
5916 * See mini-amd64.c for docs.
5919 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5921 siginfo_t* sinfo = (siginfo_t*) info;
5922 /* Sometimes the address is off by 4 */
5923 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5930 * mono_arch_skip_breakpoint:
5932 * See mini-amd64.c for docs.
5935 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5937 /* skip the ldptr */
5938 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5946 * mono_arch_start_single_stepping:
5948 * See mini-amd64.c for docs.
5951 mono_arch_start_single_stepping (void)
5953 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5957 * mono_arch_stop_single_stepping:
5959 * See mini-amd64.c for docs.
5962 mono_arch_stop_single_stepping (void)
5964 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5968 * mono_arch_is_single_step_event:
5970 * See mini-amd64.c for docs.
5973 mono_arch_is_single_step_event (void *info, void *sigctx)
5975 siginfo_t* sinfo = (siginfo_t*) info;
5976 /* Sometimes the address is off by 4 */
5977 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5984 * mono_arch_skip_single_step:
5986 * See mini-amd64.c for docs.
5989 mono_arch_skip_single_step (MonoContext *ctx)
5991 /* skip the ldptr */
5992 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5996 * mono_arch_create_seq_point_info:
5998 * See mini-amd64.c for docs.
6001 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)