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 (MonoGenericSharingContext *gsctx, 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;
1281 mono_ppc_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1287 c1 = get_call_info (NULL, caller_sig);
1288 c2 = get_call_info (NULL, callee_sig);
1289 res = c1->stack_usage >= c2->stack_usage;
1290 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1291 /* An address on the callee's stack is passed as the first argument */
1293 for (i = 0; i < c2->nargs; ++i) {
1294 if (c2->args [i].regtype == RegTypeStructByAddr)
1295 /* An address on the callee's stack is passed as the argument */
1300 if (!mono_debug_count ())
1311 * Set var information according to the calling convention. ppc version.
1312 * The locals var stuff should most likely be split in another method.
1315 mono_arch_allocate_vars (MonoCompile *m)
1317 MonoMethodSignature *sig;
1318 MonoMethodHeader *header;
1320 int i, offset, size, align, curinst;
1321 int frame_reg = ppc_sp;
1323 guint32 locals_stack_size, locals_stack_align;
1325 m->flags |= MONO_CFG_HAS_SPILLUP;
1327 /* allow room for the vararg method args: void* and long/double */
1328 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1329 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1330 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1331 * call convs needs to be handled this way.
1333 if (m->flags & MONO_CFG_HAS_VARARGS)
1334 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1335 /* gtk-sharp and other broken code will dllimport vararg functions even with
1336 * non-varargs signatures. Since there is little hope people will get this right
1337 * we assume they won't.
1339 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1340 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1345 * We use the frame register also for any method that has
1346 * exception clauses. This way, when the handlers are called,
1347 * the code will reference local variables using the frame reg instead of
1348 * the stack pointer: if we had to restore the stack pointer, we'd
1349 * corrupt the method frames that are already on the stack (since
1350 * filters get called before stack unwinding happens) when the filter
1351 * code would call any method (this also applies to finally etc.).
1353 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1354 frame_reg = ppc_r31;
1355 m->frame_reg = frame_reg;
1356 if (frame_reg != ppc_sp) {
1357 m->used_int_regs |= 1 << frame_reg;
1360 sig = mono_method_signature (m->method);
1364 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1365 m->ret->opcode = OP_REGVAR;
1366 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1368 /* FIXME: handle long values? */
1369 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1370 case MONO_TYPE_VOID:
1374 m->ret->opcode = OP_REGVAR;
1375 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1378 m->ret->opcode = OP_REGVAR;
1379 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1383 /* local vars are at a positive offset from the stack pointer */
1385 * also note that if the function uses alloca, we use ppc_r31
1386 * to point at the local variables.
1388 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1389 /* align the offset to 16 bytes: not sure this is needed here */
1391 //offset &= ~(16 - 1);
1393 /* add parameter area size for called functions */
1394 offset += m->param_area;
1396 offset &= ~(16 - 1);
1398 /* allow room to save the return value */
1399 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1402 /* the MonoLMF structure is stored just below the stack pointer */
1405 /* this stuff should not be needed on ppc and the new jit,
1406 * because a call on ppc to the handlers doesn't change the
1407 * stack pointer and the jist doesn't manipulate the stack pointer
1408 * for operations involving valuetypes.
1410 /* reserve space to store the esp */
1411 offset += sizeof (gpointer);
1413 /* this is a global constant */
1414 mono_exc_esp_offset = offset;
1417 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1418 offset += sizeof(gpointer) - 1;
1419 offset &= ~(sizeof(gpointer) - 1);
1421 m->vret_addr->opcode = OP_REGOFFSET;
1422 m->vret_addr->inst_basereg = frame_reg;
1423 m->vret_addr->inst_offset = offset;
1425 if (G_UNLIKELY (m->verbose_level > 1)) {
1426 printf ("vret_addr =");
1427 mono_print_ins (m->vret_addr);
1430 offset += sizeof(gpointer);
1433 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1434 if (locals_stack_align) {
1435 offset += (locals_stack_align - 1);
1436 offset &= ~(locals_stack_align - 1);
1438 for (i = m->locals_start; i < m->num_varinfo; i++) {
1439 if (offsets [i] != -1) {
1440 MonoInst *inst = m->varinfo [i];
1441 inst->opcode = OP_REGOFFSET;
1442 inst->inst_basereg = frame_reg;
1443 inst->inst_offset = offset + offsets [i];
1445 g_print ("allocating local %d (%s) to %d\n",
1446 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1450 offset += locals_stack_size;
1454 inst = m->args [curinst];
1455 if (inst->opcode != OP_REGVAR) {
1456 inst->opcode = OP_REGOFFSET;
1457 inst->inst_basereg = frame_reg;
1458 offset += sizeof (gpointer) - 1;
1459 offset &= ~(sizeof (gpointer) - 1);
1460 inst->inst_offset = offset;
1461 offset += sizeof (gpointer);
1466 for (i = 0; i < sig->param_count; ++i) {
1467 inst = m->args [curinst];
1468 if (inst->opcode != OP_REGVAR) {
1469 inst->opcode = OP_REGOFFSET;
1470 inst->inst_basereg = frame_reg;
1472 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1473 inst->backend.is_pinvoke = 1;
1475 size = mono_type_size (sig->params [i], &align);
1477 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1478 size = align = sizeof (gpointer);
1480 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1481 * they are saved using std in the prolog.
1483 align = sizeof (gpointer);
1484 offset += align - 1;
1485 offset &= ~(align - 1);
1486 inst->inst_offset = offset;
1492 /* some storage for fp conversions */
1495 m->arch.fp_conv_var_offset = offset;
1498 /* align the offset to 16 bytes */
1500 offset &= ~(16 - 1);
1503 m->stack_offset = offset;
1505 if (sig->call_convention == MONO_CALL_VARARG) {
1506 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1508 m->sig_cookie = cinfo->sig_cookie.offset;
1515 mono_arch_create_vars (MonoCompile *cfg)
1517 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1519 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1520 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1524 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1525 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1529 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1531 int sig_reg = mono_alloc_ireg (cfg);
1533 /* FIXME: Add support for signature tokens to AOT */
1534 cfg->disable_aot = TRUE;
1536 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1537 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1538 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1542 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1545 MonoMethodSignature *sig;
1549 sig = call->signature;
1550 n = sig->param_count + sig->hasthis;
1552 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1554 for (i = 0; i < n; ++i) {
1555 ArgInfo *ainfo = cinfo->args + i;
1558 if (i >= sig->hasthis)
1559 t = sig->params [i - sig->hasthis];
1561 t = &mono_defaults.int_class->byval_arg;
1562 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1564 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1565 emit_sig_cookie (cfg, call, cinfo);
1567 in = call->args [i];
1569 if (ainfo->regtype == RegTypeGeneral) {
1570 #ifndef __mono_ppc64__
1571 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1572 MONO_INST_NEW (cfg, ins, OP_MOVE);
1573 ins->dreg = mono_alloc_ireg (cfg);
1574 ins->sreg1 = in->dreg + 1;
1575 MONO_ADD_INS (cfg->cbb, ins);
1576 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1578 MONO_INST_NEW (cfg, ins, OP_MOVE);
1579 ins->dreg = mono_alloc_ireg (cfg);
1580 ins->sreg1 = in->dreg + 2;
1581 MONO_ADD_INS (cfg->cbb, ins);
1582 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1586 MONO_INST_NEW (cfg, ins, OP_MOVE);
1587 ins->dreg = mono_alloc_ireg (cfg);
1588 ins->sreg1 = in->dreg;
1589 MONO_ADD_INS (cfg->cbb, ins);
1591 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1593 } else if (ainfo->regtype == RegTypeStructByAddr) {
1594 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1595 ins->opcode = OP_OUTARG_VT;
1596 ins->sreg1 = in->dreg;
1597 ins->klass = in->klass;
1598 ins->inst_p0 = call;
1599 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1600 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1601 MONO_ADD_INS (cfg->cbb, ins);
1602 } else if (ainfo->regtype == RegTypeStructByVal) {
1603 /* this is further handled in mono_arch_emit_outarg_vt () */
1604 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1605 ins->opcode = OP_OUTARG_VT;
1606 ins->sreg1 = in->dreg;
1607 ins->klass = in->klass;
1608 ins->inst_p0 = call;
1609 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1610 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1611 MONO_ADD_INS (cfg->cbb, ins);
1612 } else if (ainfo->regtype == RegTypeBase) {
1613 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1614 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1615 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1616 if (t->type == MONO_TYPE_R8)
1617 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1619 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1621 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1623 } else if (ainfo->regtype == RegTypeFP) {
1624 if (t->type == MONO_TYPE_VALUETYPE) {
1625 /* this is further handled in mono_arch_emit_outarg_vt () */
1626 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1627 ins->opcode = OP_OUTARG_VT;
1628 ins->sreg1 = in->dreg;
1629 ins->klass = in->klass;
1630 ins->inst_p0 = call;
1631 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1632 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1633 MONO_ADD_INS (cfg->cbb, ins);
1635 cfg->flags |= MONO_CFG_HAS_FPOUT;
1637 int dreg = mono_alloc_freg (cfg);
1639 if (ainfo->size == 4) {
1640 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1642 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1644 ins->sreg1 = in->dreg;
1645 MONO_ADD_INS (cfg->cbb, ins);
1648 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1649 cfg->flags |= MONO_CFG_HAS_FPOUT;
1652 g_assert_not_reached ();
1656 /* Emit the signature cookie in the case that there is no
1657 additional argument */
1658 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1659 emit_sig_cookie (cfg, call, cinfo);
1661 if (cinfo->struct_ret) {
1664 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1665 vtarg->sreg1 = call->vret_var->dreg;
1666 vtarg->dreg = mono_alloc_preg (cfg);
1667 MONO_ADD_INS (cfg->cbb, vtarg);
1669 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1672 call->stack_usage = cinfo->stack_usage;
1673 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1674 cfg->flags |= MONO_CFG_HAS_CALLS;
1682 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1684 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1685 ArgInfo *ainfo = ins->inst_p1;
1686 int ovf_size = ainfo->vtsize;
1687 int doffset = ainfo->offset;
1688 int i, soffset, dreg;
1690 if (ainfo->regtype == RegTypeStructByVal) {
1697 * Darwin pinvokes needs some special handling for 1
1698 * and 2 byte arguments
1700 g_assert (ins->klass);
1701 if (call->signature->pinvoke)
1702 size = mono_class_native_size (ins->klass, NULL);
1703 if (size == 2 || size == 1) {
1704 int tmpr = mono_alloc_ireg (cfg);
1706 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1708 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1709 dreg = mono_alloc_ireg (cfg);
1710 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1711 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1714 for (i = 0; i < ainfo->vtregs; ++i) {
1715 int antipadding = 0;
1718 antipadding = sizeof (gpointer) - ainfo->bytes;
1720 dreg = mono_alloc_ireg (cfg);
1721 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1723 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1724 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1725 soffset += sizeof (gpointer);
1728 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1729 } else if (ainfo->regtype == RegTypeFP) {
1730 int tmpr = mono_alloc_freg (cfg);
1731 if (ainfo->size == 4)
1732 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1734 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1735 dreg = mono_alloc_freg (cfg);
1736 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1737 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1739 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1743 /* FIXME: alignment? */
1744 if (call->signature->pinvoke) {
1745 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1746 vtcopy->backend.is_pinvoke = 1;
1748 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1751 g_assert (ovf_size > 0);
1753 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1754 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1757 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1759 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1764 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1766 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1767 mono_method_signature (method)->ret);
1770 #ifndef __mono_ppc64__
1771 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1774 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1775 ins->sreg1 = val->dreg + 1;
1776 ins->sreg2 = val->dreg + 2;
1777 MONO_ADD_INS (cfg->cbb, ins);
1781 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1782 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1786 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1789 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1791 mono_arch_is_inst_imm (gint64 imm)
1796 #endif /* DISABLE_JIT */
1799 * Allow tracing to work with this interface (with an optional argument)
1803 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1807 ppc_load_ptr (code, ppc_r3, cfg->method);
1808 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1809 ppc_load_func (code, ppc_r0, func);
1810 ppc_mtlr (code, ppc_r0);
1824 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1827 int save_mode = SAVE_NONE;
1829 MonoMethod *method = cfg->method;
1830 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1831 mono_method_signature (method)->ret)->type;
1832 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1836 offset = code - cfg->native_code;
1837 /* we need about 16 instructions */
1838 if (offset > (cfg->code_size - 16 * 4)) {
1839 cfg->code_size *= 2;
1840 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1841 code = cfg->native_code + offset;
1845 case MONO_TYPE_VOID:
1846 /* special case string .ctor icall */
1847 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1848 save_mode = SAVE_ONE;
1850 save_mode = SAVE_NONE;
1852 #ifndef __mono_ppc64__
1855 save_mode = SAVE_TWO;
1860 save_mode = SAVE_FP;
1862 case MONO_TYPE_VALUETYPE:
1863 save_mode = SAVE_STRUCT;
1866 save_mode = SAVE_ONE;
1870 switch (save_mode) {
1872 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1873 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1874 if (enable_arguments) {
1875 ppc_mr (code, ppc_r5, ppc_r4);
1876 ppc_mr (code, ppc_r4, ppc_r3);
1880 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1881 if (enable_arguments) {
1882 ppc_mr (code, ppc_r4, ppc_r3);
1886 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1887 if (enable_arguments) {
1888 /* FIXME: what reg? */
1889 ppc_fmr (code, ppc_f3, ppc_f1);
1890 /* FIXME: use 8 byte load on PPC64 */
1891 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1892 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1896 if (enable_arguments) {
1897 /* FIXME: get the actual address */
1898 ppc_mr (code, ppc_r4, ppc_r3);
1906 ppc_load_ptr (code, ppc_r3, cfg->method);
1907 ppc_load_func (code, ppc_r0, func);
1908 ppc_mtlr (code, ppc_r0);
1911 switch (save_mode) {
1913 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1914 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1917 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1920 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1930 * Conditional branches have a small offset, so if it is likely overflowed,
1931 * we do a branch to the end of the method (uncond branches have much larger
1932 * offsets) where we perform the conditional and jump back unconditionally.
1933 * It's slightly slower, since we add two uncond branches, but it's very simple
1934 * with the current patch implementation and such large methods are likely not
1935 * going to be perf critical anyway.
1940 const char *exception;
1947 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1948 if (0 && ins->inst_true_bb->native_offset) { \
1949 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1951 int br_disp = ins->inst_true_bb->max_offset - offset; \
1952 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1953 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1954 ovfj->data.bb = ins->inst_true_bb; \
1955 ovfj->ip_offset = 0; \
1956 ovfj->b0_cond = (b0); \
1957 ovfj->b1_cond = (b1); \
1958 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1961 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1962 ppc_bc (code, (b0), (b1), 0); \
1966 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1968 /* emit an exception if condition is fail
1970 * We assign the extra code used to throw the implicit exceptions
1971 * to cfg->bb_exit as far as the big branch handling is concerned
1973 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1975 int br_disp = cfg->bb_exit->max_offset - offset; \
1976 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1977 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1978 ovfj->data.exception = (exc_name); \
1979 ovfj->ip_offset = code - cfg->native_code; \
1980 ovfj->b0_cond = (b0); \
1981 ovfj->b1_cond = (b1); \
1982 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1984 cfg->bb_exit->max_offset += 24; \
1986 mono_add_patch_info (cfg, code - cfg->native_code, \
1987 MONO_PATCH_INFO_EXC, exc_name); \
1988 ppc_bcl (code, (b0), (b1), 0); \
1992 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1995 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2000 normalize_opcode (int opcode)
2003 #ifndef __mono_ilp32__
2004 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2005 return OP_LOAD_MEMBASE;
2006 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2007 return OP_LOAD_MEMINDEX;
2008 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2009 return OP_STORE_MEMBASE_REG;
2010 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2011 return OP_STORE_MEMBASE_IMM;
2012 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2013 return OP_STORE_MEMINDEX;
2015 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2017 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2018 return OP_SHR_UN_IMM;
2025 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2027 MonoInst *ins, *n, *last_ins = NULL;
2029 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2030 switch (normalize_opcode (ins->opcode)) {
2032 /* remove unnecessary multiplication with 1 */
2033 if (ins->inst_imm == 1) {
2034 if (ins->dreg != ins->sreg1) {
2035 ins->opcode = OP_MOVE;
2037 MONO_DELETE_INS (bb, ins);
2041 int power2 = mono_is_power_of_two (ins->inst_imm);
2043 ins->opcode = OP_SHL_IMM;
2044 ins->inst_imm = power2;
2048 case OP_LOAD_MEMBASE:
2050 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2051 * OP_LOAD_MEMBASE offset(basereg), reg
2053 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2054 ins->inst_basereg == last_ins->inst_destbasereg &&
2055 ins->inst_offset == last_ins->inst_offset) {
2056 if (ins->dreg == last_ins->sreg1) {
2057 MONO_DELETE_INS (bb, ins);
2060 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2061 ins->opcode = OP_MOVE;
2062 ins->sreg1 = last_ins->sreg1;
2066 * Note: reg1 must be different from the basereg in the second load
2067 * OP_LOAD_MEMBASE offset(basereg), reg1
2068 * OP_LOAD_MEMBASE offset(basereg), reg2
2070 * OP_LOAD_MEMBASE offset(basereg), reg1
2071 * OP_MOVE reg1, reg2
2073 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2074 ins->inst_basereg != last_ins->dreg &&
2075 ins->inst_basereg == last_ins->inst_basereg &&
2076 ins->inst_offset == last_ins->inst_offset) {
2078 if (ins->dreg == last_ins->dreg) {
2079 MONO_DELETE_INS (bb, ins);
2082 ins->opcode = OP_MOVE;
2083 ins->sreg1 = last_ins->dreg;
2086 //g_assert_not_reached ();
2090 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2091 * OP_LOAD_MEMBASE offset(basereg), reg
2093 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2094 * OP_ICONST reg, imm
2096 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2097 ins->inst_basereg == last_ins->inst_destbasereg &&
2098 ins->inst_offset == last_ins->inst_offset) {
2099 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2100 ins->opcode = OP_ICONST;
2101 ins->inst_c0 = last_ins->inst_imm;
2102 g_assert_not_reached (); // check this rule
2106 case OP_LOADU1_MEMBASE:
2107 case OP_LOADI1_MEMBASE:
2108 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2112 ins->sreg1 = last_ins->sreg1;
2115 case OP_LOADU2_MEMBASE:
2116 case OP_LOADI2_MEMBASE:
2117 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2118 ins->inst_basereg == last_ins->inst_destbasereg &&
2119 ins->inst_offset == last_ins->inst_offset) {
2120 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2121 ins->sreg1 = last_ins->sreg1;
2124 #ifdef __mono_ppc64__
2125 case OP_LOADU4_MEMBASE:
2126 case OP_LOADI4_MEMBASE:
2127 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2128 ins->inst_basereg == last_ins->inst_destbasereg &&
2129 ins->inst_offset == last_ins->inst_offset) {
2130 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2131 ins->sreg1 = last_ins->sreg1;
2136 ins->opcode = OP_MOVE;
2140 if (ins->dreg == ins->sreg1) {
2141 MONO_DELETE_INS (bb, ins);
2145 * OP_MOVE sreg, dreg
2146 * OP_MOVE dreg, sreg
2148 if (last_ins && last_ins->opcode == OP_MOVE &&
2149 ins->sreg1 == last_ins->dreg &&
2150 ins->dreg == last_ins->sreg1) {
2151 MONO_DELETE_INS (bb, ins);
2159 bb->last_ins = last_ins;
2163 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2165 switch (ins->opcode) {
2166 case OP_ICONV_TO_R_UN: {
2167 #if G_BYTE_ORDER == G_BIG_ENDIAN
2168 static const guint64 adjust_val = 0x4330000000000000ULL;
2170 static const guint64 adjust_val = 0x0000000000003043ULL;
2172 int msw_reg = mono_alloc_ireg (cfg);
2173 int adj_reg = mono_alloc_freg (cfg);
2174 int tmp_reg = mono_alloc_freg (cfg);
2175 int basereg = ppc_sp;
2177 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2178 if (!ppc_is_imm16 (offset + 4)) {
2179 basereg = mono_alloc_ireg (cfg);
2180 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2182 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2184 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2185 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2187 ins->opcode = OP_NOP;
2190 #ifndef __mono_ppc64__
2191 case OP_ICONV_TO_R4:
2192 case OP_ICONV_TO_R8: {
2193 /* If we have a PPC_FEATURE_64 machine we can avoid
2194 this and use the fcfid instruction. Otherwise
2195 on an old 32-bit chip and we have to do this the
2197 if (!(cpu_hw_caps & PPC_ISA_64)) {
2198 /* FIXME: change precision for CEE_CONV_R4 */
2199 static const guint64 adjust_val = 0x4330000080000000ULL;
2200 int msw_reg = mono_alloc_ireg (cfg);
2201 int xored = mono_alloc_ireg (cfg);
2202 int adj_reg = mono_alloc_freg (cfg);
2203 int tmp_reg = mono_alloc_freg (cfg);
2204 int basereg = ppc_sp;
2206 if (!ppc_is_imm16 (offset + 4)) {
2207 basereg = mono_alloc_ireg (cfg);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2210 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2211 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2212 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2213 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2214 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2215 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2216 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2217 if (ins->opcode == OP_ICONV_TO_R4)
2218 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2219 ins->opcode = OP_NOP;
2225 int msw_reg = mono_alloc_ireg (cfg);
2226 int basereg = ppc_sp;
2228 if (!ppc_is_imm16 (offset + 4)) {
2229 basereg = mono_alloc_ireg (cfg);
2230 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2232 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2233 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2234 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2235 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2236 ins->opcode = OP_NOP;
2239 #ifdef __mono_ppc64__
2241 case OP_IADD_OVF_UN:
2243 int shifted1_reg = mono_alloc_ireg (cfg);
2244 int shifted2_reg = mono_alloc_ireg (cfg);
2245 int result_shifted_reg = mono_alloc_ireg (cfg);
2247 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2249 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2250 if (ins->opcode == OP_IADD_OVF_UN)
2251 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2253 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2254 ins->opcode = OP_NOP;
2261 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2263 switch (ins->opcode) {
2265 /* ADC sets the condition code */
2266 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2270 case OP_LADD_OVF_UN:
2271 /* ADC sets the condition code */
2272 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2273 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2277 /* SBB sets the condition code */
2278 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2279 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2282 case OP_LSUB_OVF_UN:
2283 /* SBB sets the condition code */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2285 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2289 /* From gcc generated code */
2290 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2291 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2300 * the branch_b0_table should maintain the order of these
2314 branch_b0_table [] = {
2329 branch_b1_table [] = {
2343 #define NEW_INS(cfg,dest,op) do { \
2344 MONO_INST_NEW((cfg), (dest), (op)); \
2345 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2349 map_to_reg_reg_op (int op)
2358 case OP_COMPARE_IMM:
2360 case OP_ICOMPARE_IMM:
2362 case OP_LCOMPARE_IMM:
2378 case OP_LOAD_MEMBASE:
2379 return OP_LOAD_MEMINDEX;
2380 case OP_LOADI4_MEMBASE:
2381 return OP_LOADI4_MEMINDEX;
2382 case OP_LOADU4_MEMBASE:
2383 return OP_LOADU4_MEMINDEX;
2384 case OP_LOADI8_MEMBASE:
2385 return OP_LOADI8_MEMINDEX;
2386 case OP_LOADU1_MEMBASE:
2387 return OP_LOADU1_MEMINDEX;
2388 case OP_LOADI2_MEMBASE:
2389 return OP_LOADI2_MEMINDEX;
2390 case OP_LOADU2_MEMBASE:
2391 return OP_LOADU2_MEMINDEX;
2392 case OP_LOADI1_MEMBASE:
2393 return OP_LOADI1_MEMINDEX;
2394 case OP_LOADR4_MEMBASE:
2395 return OP_LOADR4_MEMINDEX;
2396 case OP_LOADR8_MEMBASE:
2397 return OP_LOADR8_MEMINDEX;
2398 case OP_STOREI1_MEMBASE_REG:
2399 return OP_STOREI1_MEMINDEX;
2400 case OP_STOREI2_MEMBASE_REG:
2401 return OP_STOREI2_MEMINDEX;
2402 case OP_STOREI4_MEMBASE_REG:
2403 return OP_STOREI4_MEMINDEX;
2404 case OP_STOREI8_MEMBASE_REG:
2405 return OP_STOREI8_MEMINDEX;
2406 case OP_STORE_MEMBASE_REG:
2407 return OP_STORE_MEMINDEX;
2408 case OP_STORER4_MEMBASE_REG:
2409 return OP_STORER4_MEMINDEX;
2410 case OP_STORER8_MEMBASE_REG:
2411 return OP_STORER8_MEMINDEX;
2412 case OP_STORE_MEMBASE_IMM:
2413 return OP_STORE_MEMBASE_REG;
2414 case OP_STOREI1_MEMBASE_IMM:
2415 return OP_STOREI1_MEMBASE_REG;
2416 case OP_STOREI2_MEMBASE_IMM:
2417 return OP_STOREI2_MEMBASE_REG;
2418 case OP_STOREI4_MEMBASE_IMM:
2419 return OP_STOREI4_MEMBASE_REG;
2420 case OP_STOREI8_MEMBASE_IMM:
2421 return OP_STOREI8_MEMBASE_REG;
2423 return mono_op_imm_to_op (op);
2426 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2428 #define compare_opcode_is_unsigned(opcode) \
2429 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2430 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2431 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2432 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2433 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2434 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2435 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2436 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2439 * Remove from the instruction list the instructions that can't be
2440 * represented with very simple instructions with no register
2444 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2446 MonoInst *ins, *next, *temp, *last_ins = NULL;
2449 MONO_BB_FOR_EACH_INS (bb, ins) {
2451 switch (ins->opcode) {
2452 case OP_IDIV_UN_IMM:
2455 case OP_IREM_UN_IMM:
2456 NEW_INS (cfg, temp, OP_ICONST);
2457 temp->inst_c0 = ins->inst_imm;
2458 temp->dreg = mono_alloc_ireg (cfg);
2459 ins->sreg2 = temp->dreg;
2460 if (ins->opcode == OP_IDIV_IMM)
2461 ins->opcode = OP_IDIV;
2462 else if (ins->opcode == OP_IREM_IMM)
2463 ins->opcode = OP_IREM;
2464 else if (ins->opcode == OP_IDIV_UN_IMM)
2465 ins->opcode = OP_IDIV_UN;
2466 else if (ins->opcode == OP_IREM_UN_IMM)
2467 ins->opcode = OP_IREM_UN;
2469 /* handle rem separately */
2473 CASE_PPC64 (OP_LREM)
2474 CASE_PPC64 (OP_LREM_UN) {
2476 /* we change a rem dest, src1, src2 to
2477 * div temp1, src1, src2
2478 * mul temp2, temp1, src2
2479 * sub dest, src1, temp2
2481 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2482 NEW_INS (cfg, mul, OP_IMUL);
2483 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2484 ins->opcode = OP_ISUB;
2486 NEW_INS (cfg, mul, OP_LMUL);
2487 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2488 ins->opcode = OP_LSUB;
2490 temp->sreg1 = ins->sreg1;
2491 temp->sreg2 = ins->sreg2;
2492 temp->dreg = mono_alloc_ireg (cfg);
2493 mul->sreg1 = temp->dreg;
2494 mul->sreg2 = ins->sreg2;
2495 mul->dreg = mono_alloc_ireg (cfg);
2496 ins->sreg2 = mul->dreg;
2500 CASE_PPC64 (OP_LADD_IMM)
2503 if (!ppc_is_imm16 (ins->inst_imm)) {
2504 NEW_INS (cfg, temp, OP_ICONST);
2505 temp->inst_c0 = ins->inst_imm;
2506 temp->dreg = mono_alloc_ireg (cfg);
2507 ins->sreg2 = temp->dreg;
2508 ins->opcode = map_to_reg_reg_op (ins->opcode);
2512 CASE_PPC64 (OP_LSUB_IMM)
2514 if (!ppc_is_imm16 (-ins->inst_imm)) {
2515 NEW_INS (cfg, temp, OP_ICONST);
2516 temp->inst_c0 = ins->inst_imm;
2517 temp->dreg = mono_alloc_ireg (cfg);
2518 ins->sreg2 = temp->dreg;
2519 ins->opcode = map_to_reg_reg_op (ins->opcode);
2531 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2532 #ifdef __mono_ppc64__
2533 if (ins->inst_imm & 0xffffffff00000000ULL)
2537 NEW_INS (cfg, temp, OP_ICONST);
2538 temp->inst_c0 = ins->inst_imm;
2539 temp->dreg = mono_alloc_ireg (cfg);
2540 ins->sreg2 = temp->dreg;
2541 ins->opcode = map_to_reg_reg_op (ins->opcode);
2550 NEW_INS (cfg, temp, OP_ICONST);
2551 temp->inst_c0 = ins->inst_imm;
2552 temp->dreg = mono_alloc_ireg (cfg);
2553 ins->sreg2 = temp->dreg;
2554 ins->opcode = map_to_reg_reg_op (ins->opcode);
2556 case OP_COMPARE_IMM:
2557 case OP_ICOMPARE_IMM:
2558 CASE_PPC64 (OP_LCOMPARE_IMM)
2560 /* Branch opts can eliminate the branch */
2561 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2562 ins->opcode = OP_NOP;
2566 if (compare_opcode_is_unsigned (next->opcode)) {
2567 if (!ppc_is_uimm16 (ins->inst_imm)) {
2568 NEW_INS (cfg, temp, OP_ICONST);
2569 temp->inst_c0 = ins->inst_imm;
2570 temp->dreg = mono_alloc_ireg (cfg);
2571 ins->sreg2 = temp->dreg;
2572 ins->opcode = map_to_reg_reg_op (ins->opcode);
2575 if (!ppc_is_imm16 (ins->inst_imm)) {
2576 NEW_INS (cfg, temp, OP_ICONST);
2577 temp->inst_c0 = ins->inst_imm;
2578 temp->dreg = mono_alloc_ireg (cfg);
2579 ins->sreg2 = temp->dreg;
2580 ins->opcode = map_to_reg_reg_op (ins->opcode);
2586 if (ins->inst_imm == 1) {
2587 ins->opcode = OP_MOVE;
2590 if (ins->inst_imm == 0) {
2591 ins->opcode = OP_ICONST;
2595 imm = mono_is_power_of_two (ins->inst_imm);
2597 ins->opcode = OP_SHL_IMM;
2598 ins->inst_imm = imm;
2601 if (!ppc_is_imm16 (ins->inst_imm)) {
2602 NEW_INS (cfg, temp, OP_ICONST);
2603 temp->inst_c0 = ins->inst_imm;
2604 temp->dreg = mono_alloc_ireg (cfg);
2605 ins->sreg2 = temp->dreg;
2606 ins->opcode = map_to_reg_reg_op (ins->opcode);
2609 case OP_LOCALLOC_IMM:
2610 NEW_INS (cfg, temp, OP_ICONST);
2611 temp->inst_c0 = ins->inst_imm;
2612 temp->dreg = mono_alloc_ireg (cfg);
2613 ins->sreg1 = temp->dreg;
2614 ins->opcode = OP_LOCALLOC;
2616 case OP_LOAD_MEMBASE:
2617 case OP_LOADI4_MEMBASE:
2618 CASE_PPC64 (OP_LOADI8_MEMBASE)
2619 case OP_LOADU4_MEMBASE:
2620 case OP_LOADI2_MEMBASE:
2621 case OP_LOADU2_MEMBASE:
2622 case OP_LOADI1_MEMBASE:
2623 case OP_LOADU1_MEMBASE:
2624 case OP_LOADR4_MEMBASE:
2625 case OP_LOADR8_MEMBASE:
2626 case OP_STORE_MEMBASE_REG:
2627 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2628 case OP_STOREI4_MEMBASE_REG:
2629 case OP_STOREI2_MEMBASE_REG:
2630 case OP_STOREI1_MEMBASE_REG:
2631 case OP_STORER4_MEMBASE_REG:
2632 case OP_STORER8_MEMBASE_REG:
2633 /* we can do two things: load the immed in a register
2634 * and use an indexed load, or see if the immed can be
2635 * represented as an ad_imm + a load with a smaller offset
2636 * that fits. We just do the first for now, optimize later.
2638 if (ppc_is_imm16 (ins->inst_offset))
2640 NEW_INS (cfg, temp, OP_ICONST);
2641 temp->inst_c0 = ins->inst_offset;
2642 temp->dreg = mono_alloc_ireg (cfg);
2643 ins->sreg2 = temp->dreg;
2644 ins->opcode = map_to_reg_reg_op (ins->opcode);
2646 case OP_STORE_MEMBASE_IMM:
2647 case OP_STOREI1_MEMBASE_IMM:
2648 case OP_STOREI2_MEMBASE_IMM:
2649 case OP_STOREI4_MEMBASE_IMM:
2650 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2651 NEW_INS (cfg, temp, OP_ICONST);
2652 temp->inst_c0 = ins->inst_imm;
2653 temp->dreg = mono_alloc_ireg (cfg);
2654 ins->sreg1 = temp->dreg;
2655 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2660 if (cfg->compile_aot) {
2661 /* Keep these in the aot case */
2664 NEW_INS (cfg, temp, OP_ICONST);
2665 temp->inst_c0 = (gulong)ins->inst_p0;
2666 temp->dreg = mono_alloc_ireg (cfg);
2667 ins->inst_basereg = temp->dreg;
2668 ins->inst_offset = 0;
2669 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2671 /* make it handle the possibly big ins->inst_offset
2672 * later optimize to use lis + load_membase
2678 bb->last_ins = last_ins;
2679 bb->max_vreg = cfg->next_vreg;
2683 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2685 long offset = cfg->arch.fp_conv_var_offset;
2687 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2688 #ifdef __mono_ppc64__
2690 ppc_fctidz (code, ppc_f0, sreg);
2695 ppc_fctiwz (code, ppc_f0, sreg);
2698 if (ppc_is_imm16 (offset + sub_offset)) {
2699 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2701 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2703 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2705 ppc_load (code, dreg, offset);
2706 ppc_add (code, dreg, dreg, cfg->frame_reg);
2707 ppc_stfd (code, ppc_f0, 0, dreg);
2709 ppc_ldr (code, dreg, sub_offset, dreg);
2711 ppc_lwz (code, dreg, sub_offset, dreg);
2715 ppc_andid (code, dreg, dreg, 0xff);
2717 ppc_andid (code, dreg, dreg, 0xffff);
2718 #ifdef __mono_ppc64__
2720 ppc_clrldi (code, dreg, dreg, 32);
2724 ppc_extsb (code, dreg, dreg);
2726 ppc_extsh (code, dreg, dreg);
2727 #ifdef __mono_ppc64__
2729 ppc_extsw (code, dreg, dreg);
2737 const guchar *target;
2742 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2745 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2746 #ifdef __mono_ppc64__
2747 g_assert_not_reached ();
2749 PatchData *pdata = (PatchData*)user_data;
2750 guchar *code = data;
2751 guint32 *thunks = data;
2752 guint32 *endthunks = (guint32*)(code + bsize);
2756 int difflow, diffhigh;
2758 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2759 difflow = (char*)pdata->code - (char*)thunks;
2760 diffhigh = (char*)pdata->code - (char*)endthunks;
2761 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2764 templ = (guchar*)load;
2765 ppc_load_sequence (templ, ppc_r0, pdata->target);
2767 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2768 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2769 while (thunks < endthunks) {
2770 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2771 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2772 ppc_patch (pdata->code, (guchar*)thunks);
2775 static int num_thunks = 0;
2777 if ((num_thunks % 20) == 0)
2778 g_print ("num_thunks lookup: %d\n", num_thunks);
2781 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2782 /* found a free slot instead: emit thunk */
2783 code = (guchar*)thunks;
2784 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2785 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2786 ppc_mtctr (code, ppc_r0);
2787 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2788 mono_arch_flush_icache ((guchar*)thunks, 16);
2790 ppc_patch (pdata->code, (guchar*)thunks);
2793 static int num_thunks = 0;
2795 if ((num_thunks % 20) == 0)
2796 g_print ("num_thunks: %d\n", num_thunks);
2800 /* skip 16 bytes, the size of the thunk */
2804 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2811 handle_thunk (int absolute, guchar *code, const guchar *target) {
2812 MonoDomain *domain = mono_domain_get ();
2816 pdata.target = target;
2817 pdata.absolute = absolute;
2820 mono_domain_lock (domain);
2821 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2824 /* this uses the first available slot */
2826 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2828 mono_domain_unlock (domain);
2830 if (pdata.found != 1)
2831 g_print ("thunk failed for %p from %p\n", target, code);
2832 g_assert (pdata.found == 1);
2836 patch_ins (guint8 *code, guint32 ins)
2838 *(guint32*)code = GUINT32_TO_BE (ins);
2839 mono_arch_flush_icache (code, 4);
2843 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2845 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2846 guint32 prim = ins >> 26;
2849 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2851 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2852 gint diff = target - code;
2855 if (diff <= 33554431){
2856 ins = (18 << 26) | (diff) | (ins & 1);
2857 patch_ins (code, ins);
2861 /* diff between 0 and -33554432 */
2862 if (diff >= -33554432){
2863 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2864 patch_ins (code, ins);
2869 if ((glong)target >= 0){
2870 if ((glong)target <= 33554431){
2871 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2872 patch_ins (code, ins);
2876 if ((glong)target >= -33554432){
2877 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2878 patch_ins (code, ins);
2883 handle_thunk (TRUE, code, target);
2886 g_assert_not_reached ();
2894 guint32 li = (gulong)target;
2895 ins = (ins & 0xffff0000) | (ins & 3);
2896 ovf = li & 0xffff0000;
2897 if (ovf != 0 && ovf != 0xffff0000)
2898 g_assert_not_reached ();
2901 // FIXME: assert the top bits of li are 0
2903 gint diff = target - code;
2904 ins = (ins & 0xffff0000) | (ins & 3);
2905 ovf = diff & 0xffff0000;
2906 if (ovf != 0 && ovf != 0xffff0000)
2907 g_assert_not_reached ();
2911 patch_ins (code, ins);
2915 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2916 #ifdef __mono_ppc64__
2917 guint32 *seq = (guint32*)code;
2918 guint32 *branch_ins;
2920 /* the trampoline code will try to patch the blrl, blr, bcctr */
2921 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2923 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2928 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2929 branch_ins = seq + 8;
2931 branch_ins = seq + 6;
2934 seq = (guint32*)code;
2935 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2936 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2938 if (ppc_is_load_op (seq [5])) {
2939 g_assert (ppc_is_load_op (seq [6]));
2942 guint8 *buf = (guint8*)&seq [5];
2943 ppc_mr (buf, ppc_r0, ppc_r11);
2948 target = mono_get_addr_from_ftnptr ((gpointer)target);
2951 /* FIXME: make this thread safe */
2952 /* FIXME: we're assuming we're using r11 here */
2953 ppc_load_ptr_sequence (code, ppc_r11, target);
2954 mono_arch_flush_icache ((guint8*)seq, 28);
2957 /* the trampoline code will try to patch the blrl, blr, bcctr */
2958 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2961 /* this is the lis/ori/mtlr/blrl sequence */
2962 seq = (guint32*)code;
2963 g_assert ((seq [0] >> 26) == 15);
2964 g_assert ((seq [1] >> 26) == 24);
2965 g_assert ((seq [2] >> 26) == 31);
2966 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2967 /* FIXME: make this thread safe */
2968 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2969 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2970 mono_arch_flush_icache (code - 8, 8);
2973 g_assert_not_reached ();
2975 // g_print ("patched with 0x%08x\n", ins);
2979 ppc_patch (guchar *code, const guchar *target)
2981 ppc_patch_full (code, target, FALSE);
2985 mono_ppc_patch (guchar *code, const guchar *target)
2987 ppc_patch (code, target);
2991 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2993 switch (ins->opcode) {
2996 case OP_FCALL_MEMBASE:
2997 if (ins->dreg != ppc_f1)
2998 ppc_fmr (code, ins->dreg, ppc_f1);
3006 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3008 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3012 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3014 long size = cfg->param_area;
3016 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3017 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3022 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3023 if (ppc_is_imm16 (-size)) {
3024 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3026 ppc_load (code, ppc_r11, -size);
3027 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3034 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3036 long size = cfg->param_area;
3038 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3039 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3044 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3045 if (ppc_is_imm16 (size)) {
3046 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3048 ppc_load (code, ppc_r11, size);
3049 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3055 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3059 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3061 MonoInst *ins, *next;
3064 guint8 *code = cfg->native_code + cfg->code_len;
3065 MonoInst *last_ins = NULL;
3066 guint last_offset = 0;
3070 /* we don't align basic blocks of loops on ppc */
3072 if (cfg->verbose_level > 2)
3073 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3075 cpos = bb->max_offset;
3077 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3078 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3079 //g_assert (!mono_compile_aot);
3082 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3083 /* this is not thread save, but good enough */
3084 /* fixme: howto handle overflows? */
3085 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3088 MONO_BB_FOR_EACH_INS (bb, ins) {
3089 offset = code - cfg->native_code;
3091 max_len = ins_native_length (cfg, ins);
3093 if (offset > (cfg->code_size - max_len - 16)) {
3094 cfg->code_size *= 2;
3095 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3096 code = cfg->native_code + offset;
3098 // if (ins->cil_code)
3099 // g_print ("cil code\n");
3100 mono_debug_record_line_number (cfg, ins, offset);
3102 switch (normalize_opcode (ins->opcode)) {
3103 case OP_RELAXED_NOP:
3106 case OP_DUMMY_STORE:
3107 case OP_NOT_REACHED:
3110 case OP_SEQ_POINT: {
3113 if (cfg->compile_aot)
3117 * Read from the single stepping trigger page. This will cause a
3118 * SIGSEGV when single stepping is enabled.
3119 * We do this _before_ the breakpoint, so single stepping after
3120 * a breakpoint is hit will step to the next IL offset.
3122 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3123 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3124 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3127 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3130 * A placeholder for a possible breakpoint inserted by
3131 * mono_arch_set_breakpoint ().
3133 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3138 emit_tls_access (code, ins->dreg, ins->inst_offset);
3141 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3142 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3143 ppc_mr (code, ppc_r4, ppc_r0);
3146 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3147 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3148 ppc_mr (code, ppc_r4, ppc_r0);
3150 case OP_MEMORY_BARRIER:
3153 case OP_STOREI1_MEMBASE_REG:
3154 if (ppc_is_imm16 (ins->inst_offset)) {
3155 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3157 if (ppc_is_imm32 (ins->inst_offset)) {
3158 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3159 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3161 ppc_load (code, ppc_r0, ins->inst_offset);
3162 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3166 case OP_STOREI2_MEMBASE_REG:
3167 if (ppc_is_imm16 (ins->inst_offset)) {
3168 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3170 if (ppc_is_imm32 (ins->inst_offset)) {
3171 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3172 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3174 ppc_load (code, ppc_r0, ins->inst_offset);
3175 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3179 case OP_STORE_MEMBASE_REG:
3180 if (ppc_is_imm16 (ins->inst_offset)) {
3181 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3183 if (ppc_is_imm32 (ins->inst_offset)) {
3184 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3185 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3187 ppc_load (code, ppc_r0, ins->inst_offset);
3188 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3192 #ifdef __mono_ilp32__
3193 case OP_STOREI8_MEMBASE_REG:
3194 if (ppc_is_imm16 (ins->inst_offset)) {
3195 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3197 ppc_load (code, ppc_r0, ins->inst_offset);
3198 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3202 case OP_STOREI1_MEMINDEX:
3203 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3205 case OP_STOREI2_MEMINDEX:
3206 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3208 case OP_STORE_MEMINDEX:
3209 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3212 g_assert_not_reached ();
3214 case OP_LOAD_MEMBASE:
3215 if (ppc_is_imm16 (ins->inst_offset)) {
3216 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3218 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3219 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3220 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3222 ppc_load (code, ppc_r0, ins->inst_offset);
3223 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3227 case OP_LOADI4_MEMBASE:
3228 #ifdef __mono_ppc64__
3229 if (ppc_is_imm16 (ins->inst_offset)) {
3230 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3232 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3233 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3234 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3236 ppc_load (code, ppc_r0, ins->inst_offset);
3237 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3242 case OP_LOADU4_MEMBASE:
3243 if (ppc_is_imm16 (ins->inst_offset)) {
3244 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3246 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3247 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3248 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3250 ppc_load (code, ppc_r0, ins->inst_offset);
3251 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3255 case OP_LOADI1_MEMBASE:
3256 case OP_LOADU1_MEMBASE:
3257 if (ppc_is_imm16 (ins->inst_offset)) {
3258 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3260 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3261 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3262 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3264 ppc_load (code, ppc_r0, ins->inst_offset);
3265 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3268 if (ins->opcode == OP_LOADI1_MEMBASE)
3269 ppc_extsb (code, ins->dreg, ins->dreg);
3271 case OP_LOADU2_MEMBASE:
3272 if (ppc_is_imm16 (ins->inst_offset)) {
3273 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3275 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3276 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3277 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3279 ppc_load (code, ppc_r0, ins->inst_offset);
3280 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3284 case OP_LOADI2_MEMBASE:
3285 if (ppc_is_imm16 (ins->inst_offset)) {
3286 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3288 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3289 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3290 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3292 ppc_load (code, ppc_r0, ins->inst_offset);
3293 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3297 #ifdef __mono_ilp32__
3298 case OP_LOADI8_MEMBASE:
3299 if (ppc_is_imm16 (ins->inst_offset)) {
3300 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3302 ppc_load (code, ppc_r0, ins->inst_offset);
3303 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3307 case OP_LOAD_MEMINDEX:
3308 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3310 case OP_LOADI4_MEMINDEX:
3311 #ifdef __mono_ppc64__
3312 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3315 case OP_LOADU4_MEMINDEX:
3316 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3318 case OP_LOADU2_MEMINDEX:
3319 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3321 case OP_LOADI2_MEMINDEX:
3322 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3324 case OP_LOADU1_MEMINDEX:
3325 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3327 case OP_LOADI1_MEMINDEX:
3328 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3329 ppc_extsb (code, ins->dreg, ins->dreg);
3331 case OP_ICONV_TO_I1:
3332 CASE_PPC64 (OP_LCONV_TO_I1)
3333 ppc_extsb (code, ins->dreg, ins->sreg1);
3335 case OP_ICONV_TO_I2:
3336 CASE_PPC64 (OP_LCONV_TO_I2)
3337 ppc_extsh (code, ins->dreg, ins->sreg1);
3339 case OP_ICONV_TO_U1:
3340 CASE_PPC64 (OP_LCONV_TO_U1)
3341 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3343 case OP_ICONV_TO_U2:
3344 CASE_PPC64 (OP_LCONV_TO_U2)
3345 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3349 CASE_PPC64 (OP_LCOMPARE)
3350 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3352 if (next && compare_opcode_is_unsigned (next->opcode))
3353 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3355 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3357 case OP_COMPARE_IMM:
3358 case OP_ICOMPARE_IMM:
3359 CASE_PPC64 (OP_LCOMPARE_IMM)
3360 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3362 if (next && compare_opcode_is_unsigned (next->opcode)) {
3363 if (ppc_is_uimm16 (ins->inst_imm)) {
3364 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3366 g_assert_not_reached ();
3369 if (ppc_is_imm16 (ins->inst_imm)) {
3370 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3372 g_assert_not_reached ();
3378 * gdb does not like encountering a trap in the debugged code. So
3379 * instead of emitting a trap, we emit a call a C function and place a
3383 ppc_mr (code, ppc_r3, ins->sreg1);
3384 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3385 (gpointer)"mono_break");
3386 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3387 ppc_load_func (code, ppc_r0, 0);
3388 ppc_mtlr (code, ppc_r0);
3396 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3399 CASE_PPC64 (OP_LADD)
3400 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3404 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3407 if (ppc_is_imm16 (ins->inst_imm)) {
3408 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3410 g_assert_not_reached ();
3415 CASE_PPC64 (OP_LADD_IMM)
3416 if (ppc_is_imm16 (ins->inst_imm)) {
3417 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3419 g_assert_not_reached ();
3423 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3425 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3426 ppc_mfspr (code, ppc_r0, ppc_xer);
3427 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3428 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3430 case OP_IADD_OVF_UN:
3431 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3433 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3434 ppc_mfspr (code, ppc_r0, ppc_xer);
3435 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3436 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3439 CASE_PPC64 (OP_LSUB_OVF)
3440 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3442 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3443 ppc_mfspr (code, ppc_r0, ppc_xer);
3444 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3445 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3447 case OP_ISUB_OVF_UN:
3448 CASE_PPC64 (OP_LSUB_OVF_UN)
3449 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3451 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3452 ppc_mfspr (code, ppc_r0, ppc_xer);
3453 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3454 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3456 case OP_ADD_OVF_CARRY:
3457 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3459 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3460 ppc_mfspr (code, ppc_r0, ppc_xer);
3461 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3462 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3464 case OP_ADD_OVF_UN_CARRY:
3465 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3467 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 ppc_mfspr (code, ppc_r0, ppc_xer);
3469 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3470 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3472 case OP_SUB_OVF_CARRY:
3473 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3475 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3476 ppc_mfspr (code, ppc_r0, ppc_xer);
3477 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3478 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3480 case OP_SUB_OVF_UN_CARRY:
3481 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3483 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3484 ppc_mfspr (code, ppc_r0, ppc_xer);
3485 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3486 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3490 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3493 CASE_PPC64 (OP_LSUB)
3494 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3498 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3502 CASE_PPC64 (OP_LSUB_IMM)
3503 // we add the negated value
3504 if (ppc_is_imm16 (-ins->inst_imm))
3505 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3507 g_assert_not_reached ();
3511 g_assert (ppc_is_imm16 (ins->inst_imm));
3512 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3515 ppc_subfze (code, ins->dreg, ins->sreg1);
3518 CASE_PPC64 (OP_LAND)
3519 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3520 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3524 CASE_PPC64 (OP_LAND_IMM)
3525 if (!(ins->inst_imm & 0xffff0000)) {
3526 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3527 } else if (!(ins->inst_imm & 0xffff)) {
3528 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3530 g_assert_not_reached ();
3534 CASE_PPC64 (OP_LDIV) {
3535 guint8 *divisor_is_m1;
3536 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3538 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3539 divisor_is_m1 = code;
3540 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3541 ppc_lis (code, ppc_r0, 0x8000);
3542 #ifdef __mono_ppc64__
3543 if (ins->opcode == OP_LDIV)
3544 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3546 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3547 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3548 ppc_patch (divisor_is_m1, code);
3549 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3551 if (ins->opcode == OP_IDIV)
3552 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3553 #ifdef __mono_ppc64__
3555 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3557 ppc_mfspr (code, ppc_r0, ppc_xer);
3558 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3563 CASE_PPC64 (OP_LDIV_UN)
3564 if (ins->opcode == OP_IDIV_UN)
3565 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 #ifdef __mono_ppc64__
3568 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3570 ppc_mfspr (code, ppc_r0, ppc_xer);
3571 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3572 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3578 g_assert_not_reached ();
3581 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3585 CASE_PPC64 (OP_LOR_IMM)
3586 if (!(ins->inst_imm & 0xffff0000)) {
3587 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3588 } else if (!(ins->inst_imm & 0xffff)) {
3589 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3591 g_assert_not_reached ();
3595 CASE_PPC64 (OP_LXOR)
3596 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3600 CASE_PPC64 (OP_LXOR_IMM)
3601 if (!(ins->inst_imm & 0xffff0000)) {
3602 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3603 } else if (!(ins->inst_imm & 0xffff)) {
3604 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3606 g_assert_not_reached ();
3610 CASE_PPC64 (OP_LSHL)
3611 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 CASE_PPC64 (OP_LSHL_IMM)
3616 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3619 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3622 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3625 if (MASK_SHIFT_IMM (ins->inst_imm))
3626 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3628 ppc_mr (code, ins->dreg, ins->sreg1);
3631 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3634 CASE_PPC64 (OP_LNOT)
3635 ppc_not (code, ins->dreg, ins->sreg1);
3638 CASE_PPC64 (OP_LNEG)
3639 ppc_neg (code, ins->dreg, ins->sreg1);
3642 CASE_PPC64 (OP_LMUL)
3643 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3647 CASE_PPC64 (OP_LMUL_IMM)
3648 if (ppc_is_imm16 (ins->inst_imm)) {
3649 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3651 g_assert_not_reached ();
3655 CASE_PPC64 (OP_LMUL_OVF)
3656 /* we annot use mcrxr, since it's not implemented on some processors
3657 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3659 if (ins->opcode == OP_IMUL_OVF)
3660 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 #ifdef __mono_ppc64__
3663 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3665 ppc_mfspr (code, ppc_r0, ppc_xer);
3666 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3667 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3669 case OP_IMUL_OVF_UN:
3670 CASE_PPC64 (OP_LMUL_OVF_UN)
3671 /* we first multiply to get the high word and compare to 0
3672 * to set the flags, then the result is discarded and then
3673 * we multiply to get the lower * bits result
3675 if (ins->opcode == OP_IMUL_OVF_UN)
3676 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3677 #ifdef __mono_ppc64__
3679 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3681 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3682 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3683 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3686 ppc_load (code, ins->dreg, ins->inst_c0);
3689 ppc_load (code, ins->dreg, ins->inst_l);
3692 case OP_LOAD_GOTADDR:
3693 /* The PLT implementation depends on this */
3694 g_assert (ins->dreg == ppc_r30);
3696 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3699 // FIXME: Fix max instruction length
3700 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3701 /* arch_emit_got_access () patches this */
3702 ppc_load32 (code, ppc_r0, 0);
3703 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3706 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3707 ppc_load_sequence (code, ins->dreg, 0);
3709 CASE_PPC32 (OP_ICONV_TO_I4)
3710 CASE_PPC32 (OP_ICONV_TO_U4)
3712 ppc_mr (code, ins->dreg, ins->sreg1);
3715 int saved = ins->sreg1;
3716 if (ins->sreg1 == ppc_r3) {
3717 ppc_mr (code, ppc_r0, ins->sreg1);
3720 if (ins->sreg2 != ppc_r3)
3721 ppc_mr (code, ppc_r3, ins->sreg2);
3722 if (saved != ppc_r4)
3723 ppc_mr (code, ppc_r4, saved);
3727 ppc_fmr (code, ins->dreg, ins->sreg1);
3729 case OP_FCONV_TO_R4:
3730 ppc_frsp (code, ins->dreg, ins->sreg1);
3734 MonoCallInst *call = (MonoCallInst*)ins;
3737 * Keep in sync with mono_arch_emit_epilog
3739 g_assert (!cfg->method->save_lmf);
3741 * Note: we can use ppc_r11 here because it is dead anyway:
3742 * we're leaving the method.
3744 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3745 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3746 if (ppc_is_imm16 (ret_offset)) {
3747 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3749 ppc_load (code, ppc_r11, ret_offset);
3750 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3752 ppc_mtlr (code, ppc_r0);
3755 if (ppc_is_imm16 (cfg->stack_usage)) {
3756 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3758 /* cfg->stack_usage is an int, so we can use
3759 * an addis/addi sequence here even in 64-bit. */
3760 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3761 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3763 if (!cfg->method->save_lmf) {
3765 for (i = 31; i >= 13; --i) {
3766 if (cfg->used_int_regs & (1 << i)) {
3767 pos += sizeof (gpointer);
3768 ppc_ldptr (code, i, -pos, ppc_r11);
3772 /* FIXME restore from MonoLMF: though this can't happen yet */
3775 /* Copy arguments on the stack to our argument area */
3776 if (call->stack_usage) {
3777 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3778 /* r11 was clobbered */
3779 g_assert (cfg->frame_reg == ppc_sp);
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);
3790 ppc_mr (code, ppc_sp, ppc_r11);
3791 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3792 if (cfg->compile_aot) {
3793 /* arch_emit_got_access () patches this */
3794 ppc_load32 (code, ppc_r0, 0);
3795 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3796 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3797 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3799 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3801 ppc_mtctr (code, ppc_r0);
3802 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3809 /* ensure ins->sreg1 is not NULL */
3810 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3813 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3814 if (ppc_is_imm16 (cookie_offset)) {
3815 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3817 ppc_load (code, ppc_r0, cookie_offset);
3818 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3820 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3829 call = (MonoCallInst*)ins;
3830 if (ins->flags & MONO_INST_HAS_METHOD)
3831 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3833 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3834 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3835 ppc_load_func (code, ppc_r0, 0);
3836 ppc_mtlr (code, ppc_r0);
3841 /* FIXME: this should be handled somewhere else in the new jit */
3842 code = emit_move_return_value (cfg, ins, code);
3848 case OP_VOIDCALL_REG:
3850 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3851 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3852 /* FIXME: if we know that this is a method, we
3853 can omit this load */
3854 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3855 ppc_mtlr (code, ppc_r0);
3857 ppc_mtlr (code, ins->sreg1);
3860 /* FIXME: this should be handled somewhere else in the new jit */
3861 code = emit_move_return_value (cfg, ins, code);
3863 case OP_FCALL_MEMBASE:
3864 case OP_LCALL_MEMBASE:
3865 case OP_VCALL_MEMBASE:
3866 case OP_VCALL2_MEMBASE:
3867 case OP_VOIDCALL_MEMBASE:
3868 case OP_CALL_MEMBASE:
3869 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3870 /* The trampolines clobber this */
3871 ppc_mr (code, ppc_r29, ins->sreg1);
3872 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3874 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3876 ppc_mtlr (code, ppc_r0);
3878 /* FIXME: this should be handled somewhere else in the new jit */
3879 code = emit_move_return_value (cfg, ins, code);
3882 guint8 * zero_loop_jump, * zero_loop_start;
3883 /* keep alignment */
3884 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3885 int area_offset = alloca_waste;
3887 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3888 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3889 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3890 /* use ctr to store the number of words to 0 if needed */
3891 if (ins->flags & MONO_INST_INIT) {
3892 /* we zero 4 bytes at a time:
3893 * we add 7 instead of 3 so that we set the counter to
3894 * at least 1, otherwise the bdnz instruction will make
3895 * it negative and iterate billions of times.
3897 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3898 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3899 ppc_mtctr (code, ppc_r0);
3901 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3902 ppc_neg (code, ppc_r11, ppc_r11);
3903 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3905 /* FIXME: make this loop work in 8 byte
3906 increments on PPC64 */
3907 if (ins->flags & MONO_INST_INIT) {
3908 /* adjust the dest reg by -4 so we can use stwu */
3909 /* we actually adjust -8 because we let the loop
3912 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3913 ppc_li (code, ppc_r11, 0);
3914 zero_loop_start = code;
3915 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3916 zero_loop_jump = code;
3917 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3918 ppc_patch (zero_loop_jump, zero_loop_start);
3920 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3925 ppc_mr (code, ppc_r3, ins->sreg1);
3926 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3927 (gpointer)"mono_arch_throw_exception");
3928 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3929 ppc_load_func (code, ppc_r0, 0);
3930 ppc_mtlr (code, ppc_r0);
3939 ppc_mr (code, ppc_r3, ins->sreg1);
3940 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3941 (gpointer)"mono_arch_rethrow_exception");
3942 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3943 ppc_load_func (code, ppc_r0, 0);
3944 ppc_mtlr (code, ppc_r0);
3951 case OP_START_HANDLER: {
3952 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3953 g_assert (spvar->inst_basereg != ppc_sp);
3954 code = emit_reserve_param_area (cfg, code);
3955 ppc_mflr (code, ppc_r0);
3956 if (ppc_is_imm16 (spvar->inst_offset)) {
3957 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3959 ppc_load (code, ppc_r11, spvar->inst_offset);
3960 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3964 case OP_ENDFILTER: {
3965 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3966 g_assert (spvar->inst_basereg != ppc_sp);
3967 code = emit_unreserve_param_area (cfg, code);
3968 if (ins->sreg1 != ppc_r3)
3969 ppc_mr (code, ppc_r3, ins->sreg1);
3970 if (ppc_is_imm16 (spvar->inst_offset)) {
3971 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3973 ppc_load (code, ppc_r11, spvar->inst_offset);
3974 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3976 ppc_mtlr (code, ppc_r0);
3980 case OP_ENDFINALLY: {
3981 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3982 g_assert (spvar->inst_basereg != ppc_sp);
3983 code = emit_unreserve_param_area (cfg, code);
3984 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3985 ppc_mtlr (code, ppc_r0);
3989 case OP_CALL_HANDLER:
3990 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3992 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3995 ins->inst_c0 = code - cfg->native_code;
3998 /*if (ins->inst_target_bb->native_offset) {
4000 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4002 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4007 ppc_mtctr (code, ins->sreg1);
4008 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4012 CASE_PPC64 (OP_LCEQ)
4013 ppc_li (code, ins->dreg, 0);
4014 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4015 ppc_li (code, ins->dreg, 1);
4021 CASE_PPC64 (OP_LCLT)
4022 CASE_PPC64 (OP_LCLT_UN)
4023 ppc_li (code, ins->dreg, 1);
4024 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4025 ppc_li (code, ins->dreg, 0);
4031 CASE_PPC64 (OP_LCGT)
4032 CASE_PPC64 (OP_LCGT_UN)
4033 ppc_li (code, ins->dreg, 1);
4034 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4035 ppc_li (code, ins->dreg, 0);
4037 case OP_COND_EXC_EQ:
4038 case OP_COND_EXC_NE_UN:
4039 case OP_COND_EXC_LT:
4040 case OP_COND_EXC_LT_UN:
4041 case OP_COND_EXC_GT:
4042 case OP_COND_EXC_GT_UN:
4043 case OP_COND_EXC_GE:
4044 case OP_COND_EXC_GE_UN:
4045 case OP_COND_EXC_LE:
4046 case OP_COND_EXC_LE_UN:
4047 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4049 case OP_COND_EXC_IEQ:
4050 case OP_COND_EXC_INE_UN:
4051 case OP_COND_EXC_ILT:
4052 case OP_COND_EXC_ILT_UN:
4053 case OP_COND_EXC_IGT:
4054 case OP_COND_EXC_IGT_UN:
4055 case OP_COND_EXC_IGE:
4056 case OP_COND_EXC_IGE_UN:
4057 case OP_COND_EXC_ILE:
4058 case OP_COND_EXC_ILE_UN:
4059 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4071 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4074 /* floating point opcodes */
4076 g_assert (cfg->compile_aot);
4078 /* FIXME: Optimize this */
4080 ppc_mflr (code, ppc_r11);
4082 *(double*)code = *(double*)ins->inst_p0;
4084 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4087 g_assert_not_reached ();
4089 case OP_STORER8_MEMBASE_REG:
4090 if (ppc_is_imm16 (ins->inst_offset)) {
4091 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4093 if (ppc_is_imm32 (ins->inst_offset)) {
4094 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4095 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4097 ppc_load (code, ppc_r0, ins->inst_offset);
4098 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4102 case OP_LOADR8_MEMBASE:
4103 if (ppc_is_imm16 (ins->inst_offset)) {
4104 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4106 if (ppc_is_imm32 (ins->inst_offset)) {
4107 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4108 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4110 ppc_load (code, ppc_r0, ins->inst_offset);
4111 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4115 case OP_STORER4_MEMBASE_REG:
4116 ppc_frsp (code, ins->sreg1, ins->sreg1);
4117 if (ppc_is_imm16 (ins->inst_offset)) {
4118 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4120 if (ppc_is_imm32 (ins->inst_offset)) {
4121 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4122 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4124 ppc_load (code, ppc_r0, ins->inst_offset);
4125 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4129 case OP_LOADR4_MEMBASE:
4130 if (ppc_is_imm16 (ins->inst_offset)) {
4131 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4133 if (ppc_is_imm32 (ins->inst_offset)) {
4134 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4135 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4137 ppc_load (code, ppc_r0, ins->inst_offset);
4138 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4142 case OP_LOADR4_MEMINDEX:
4143 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4145 case OP_LOADR8_MEMINDEX:
4146 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4148 case OP_STORER4_MEMINDEX:
4149 ppc_frsp (code, ins->sreg1, ins->sreg1);
4150 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4152 case OP_STORER8_MEMINDEX:
4153 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4156 case CEE_CONV_R4: /* FIXME: change precision */
4158 g_assert_not_reached ();
4159 case OP_FCONV_TO_I1:
4160 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4162 case OP_FCONV_TO_U1:
4163 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4165 case OP_FCONV_TO_I2:
4166 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4168 case OP_FCONV_TO_U2:
4169 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4171 case OP_FCONV_TO_I4:
4173 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4175 case OP_FCONV_TO_U4:
4177 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4179 case OP_LCONV_TO_R_UN:
4180 g_assert_not_reached ();
4181 /* Implemented as helper calls */
4183 case OP_LCONV_TO_OVF_I4_2:
4184 case OP_LCONV_TO_OVF_I: {
4185 #ifdef __mono_ppc64__
4188 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4189 // Check if its negative
4190 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4191 negative_branch = code;
4192 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4193 // Its positive msword == 0
4194 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4195 msword_positive_branch = code;
4196 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4198 ovf_ex_target = code;
4199 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4201 ppc_patch (negative_branch, code);
4202 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4203 msword_negative_branch = code;
4204 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4205 ppc_patch (msword_negative_branch, ovf_ex_target);
4207 ppc_patch (msword_positive_branch, code);
4208 if (ins->dreg != ins->sreg1)
4209 ppc_mr (code, ins->dreg, ins->sreg1);
4214 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4217 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4220 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4223 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4226 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4229 ppc_fneg (code, ins->dreg, ins->sreg1);
4233 g_assert_not_reached ();
4236 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4239 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4240 ppc_li (code, ins->dreg, 0);
4241 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4242 ppc_li (code, ins->dreg, 1);
4245 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4246 ppc_li (code, ins->dreg, 1);
4247 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4248 ppc_li (code, ins->dreg, 0);
4251 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4252 ppc_li (code, ins->dreg, 1);
4253 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4254 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4255 ppc_li (code, ins->dreg, 0);
4258 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4259 ppc_li (code, ins->dreg, 1);
4260 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4261 ppc_li (code, ins->dreg, 0);
4264 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4265 ppc_li (code, ins->dreg, 1);
4266 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4267 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4268 ppc_li (code, ins->dreg, 0);
4271 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4274 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4277 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4278 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4281 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4282 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4285 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4286 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4289 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4290 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4293 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4294 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4297 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4300 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4301 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4304 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4307 g_assert_not_reached ();
4308 case OP_CHECK_FINITE: {
4309 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4310 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4311 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4312 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4315 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4316 #ifdef __mono_ppc64__
4317 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4319 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4324 #ifdef __mono_ppc64__
4325 case OP_ICONV_TO_I4:
4327 ppc_extsw (code, ins->dreg, ins->sreg1);
4329 case OP_ICONV_TO_U4:
4331 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4333 case OP_ICONV_TO_R4:
4334 case OP_ICONV_TO_R8:
4335 case OP_LCONV_TO_R4:
4336 case OP_LCONV_TO_R8: {
4338 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4339 ppc_extsw (code, ppc_r0, ins->sreg1);
4344 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4345 ppc_mffgpr (code, ins->dreg, tmp);
4347 ppc_str (code, tmp, -8, ppc_r1);
4348 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4350 ppc_fcfid (code, ins->dreg, ins->dreg);
4351 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4352 ppc_frsp (code, ins->dreg, ins->dreg);
4356 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4359 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4362 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4364 ppc_mfspr (code, ppc_r0, ppc_xer);
4365 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4366 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4368 case OP_COND_EXC_OV:
4369 ppc_mfspr (code, ppc_r0, ppc_xer);
4370 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4371 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4383 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4385 case OP_FCONV_TO_I8:
4386 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4388 case OP_FCONV_TO_U8:
4389 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4391 case OP_STOREI4_MEMBASE_REG:
4392 if (ppc_is_imm16 (ins->inst_offset)) {
4393 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4395 ppc_load (code, ppc_r0, ins->inst_offset);
4396 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4399 case OP_STOREI4_MEMINDEX:
4400 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4403 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4405 case OP_ISHR_UN_IMM:
4406 if (ins->inst_imm & 0x1f)
4407 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4409 ppc_mr (code, ins->dreg, ins->sreg1);
4411 case OP_ATOMIC_ADD_NEW_I4:
4412 case OP_ATOMIC_ADD_NEW_I8: {
4413 guint8 *loop = code, *branch;
4414 g_assert (ins->inst_offset == 0);
4415 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4416 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4418 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4419 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4420 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4421 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4423 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4425 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4426 ppc_patch (branch, loop);
4427 ppc_mr (code, ins->dreg, ppc_r0);
4431 case OP_ICONV_TO_R4:
4432 case OP_ICONV_TO_R8: {
4433 if (cpu_hw_caps & PPC_ISA_64) {
4434 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4435 ppc_stw (code, ppc_r0, -8, ppc_r1);
4436 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4437 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4438 ppc_fcfid (code, ins->dreg, ins->dreg);
4439 if (ins->opcode == OP_ICONV_TO_R4)
4440 ppc_frsp (code, ins->dreg, ins->dreg);
4445 case OP_ATOMIC_CAS_I4:
4446 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4447 int location = ins->sreg1;
4448 int value = ins->sreg2;
4449 int comparand = ins->sreg3;
4450 guint8 *start, *not_equal, *lost_reservation;
4453 if (ins->opcode == OP_ATOMIC_CAS_I4)
4454 ppc_lwarx (code, ppc_r0, 0, location);
4455 #ifdef __mono_ppc64__
4457 ppc_ldarx (code, ppc_r0, 0, location);
4459 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4462 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4463 if (ins->opcode == OP_ATOMIC_CAS_I4)
4464 ppc_stwcxd (code, value, 0, location);
4465 #ifdef __mono_ppc64__
4467 ppc_stdcxd (code, value, 0, location);
4470 lost_reservation = code;
4471 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4472 ppc_patch (lost_reservation, start);
4474 ppc_patch (not_equal, code);
4475 ppc_mr (code, ins->dreg, ppc_r0);
4480 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4481 g_assert_not_reached ();
4484 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4485 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4486 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4487 g_assert_not_reached ();
4493 last_offset = offset;
4496 cfg->code_len = code - cfg->native_code;
4498 #endif /* !DISABLE_JIT */
4501 mono_arch_register_lowlevel_calls (void)
4503 /* The signature doesn't matter */
4504 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4507 #ifdef __mono_ppc64__
4508 #define patch_load_sequence(ip,val) do {\
4509 guint16 *__load = (guint16*)(ip); \
4510 g_assert (sizeof (val) == sizeof (gsize)); \
4511 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4512 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4513 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4514 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4517 #define patch_load_sequence(ip,val) do {\
4518 guint16 *__lis_ori = (guint16*)(ip); \
4519 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4520 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4526 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4528 MonoJumpInfo *patch_info;
4529 gboolean compile_aot = !run_cctors;
4531 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4532 unsigned char *ip = patch_info->ip.i + code;
4533 unsigned char *target;
4534 gboolean is_fd = FALSE;
4536 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4539 switch (patch_info->type) {
4540 case MONO_PATCH_INFO_BB:
4541 case MONO_PATCH_INFO_LABEL:
4544 /* No need to patch these */
4549 switch (patch_info->type) {
4550 case MONO_PATCH_INFO_IP:
4551 patch_load_sequence (ip, ip);
4553 case MONO_PATCH_INFO_METHOD_REL:
4554 g_assert_not_reached ();
4555 *((gpointer *)(ip)) = code + patch_info->data.offset;
4557 case MONO_PATCH_INFO_SWITCH: {
4558 gpointer *table = (gpointer *)patch_info->data.table->table;
4561 patch_load_sequence (ip, table);
4563 for (i = 0; i < patch_info->data.table->table_size; i++) {
4564 table [i] = (glong)patch_info->data.table->table [i] + code;
4566 /* we put into the table the absolute address, no need for ppc_patch in this case */
4569 case MONO_PATCH_INFO_METHODCONST:
4570 case MONO_PATCH_INFO_CLASS:
4571 case MONO_PATCH_INFO_IMAGE:
4572 case MONO_PATCH_INFO_FIELD:
4573 case MONO_PATCH_INFO_VTABLE:
4574 case MONO_PATCH_INFO_IID:
4575 case MONO_PATCH_INFO_SFLDA:
4576 case MONO_PATCH_INFO_LDSTR:
4577 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4578 case MONO_PATCH_INFO_LDTOKEN:
4579 /* from OP_AOTCONST : lis + ori */
4580 patch_load_sequence (ip, target);
4582 case MONO_PATCH_INFO_R4:
4583 case MONO_PATCH_INFO_R8:
4584 g_assert_not_reached ();
4585 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4587 case MONO_PATCH_INFO_EXC_NAME:
4588 g_assert_not_reached ();
4589 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4591 case MONO_PATCH_INFO_NONE:
4592 case MONO_PATCH_INFO_BB_OVF:
4593 case MONO_PATCH_INFO_EXC_OVF:
4594 /* everything is dealt with at epilog output time */
4596 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4597 case MONO_PATCH_INFO_INTERNAL_METHOD:
4598 case MONO_PATCH_INFO_ABS:
4599 case MONO_PATCH_INFO_CLASS_INIT:
4600 case MONO_PATCH_INFO_RGCTX_FETCH:
4607 ppc_patch_full (ip, target, is_fd);
4612 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4613 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4614 * the instruction offset immediate for all the registers.
4617 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4621 for (i = 13; i <= 31; i++) {
4622 if (used_int_regs & (1 << i)) {
4623 ppc_str (code, i, pos, base_reg);
4624 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4625 pos += sizeof (mgreg_t);
4629 /* pos is the start of the MonoLMF structure */
4630 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4631 for (i = 13; i <= 31; i++) {
4632 ppc_str (code, i, offset, base_reg);
4633 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4634 offset += sizeof (mgreg_t);
4636 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4637 for (i = 14; i < 32; i++) {
4638 ppc_stfd (code, i, offset, base_reg);
4639 offset += sizeof (gdouble);
4646 * Stack frame layout:
4648 * ------------------- sp
4649 * MonoLMF structure or saved registers
4650 * -------------------
4652 * -------------------
4654 * -------------------
4655 * optional 8 bytes for tracing
4656 * -------------------
4657 * param area size is cfg->param_area
4658 * -------------------
4659 * linkage area size is PPC_STACK_PARAM_OFFSET
4660 * ------------------- sp
4664 mono_arch_emit_prolog (MonoCompile *cfg)
4666 MonoMethod *method = cfg->method;
4668 MonoMethodSignature *sig;
4670 long alloc_size, pos, max_offset, cfa_offset;
4676 int tailcall_struct_index;
4678 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4681 sig = mono_method_signature (method);
4682 cfg->code_size = 512 + sig->param_count * 32;
4683 code = cfg->native_code = g_malloc (cfg->code_size);
4687 /* We currently emit unwind info for aot, but don't use it */
4688 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4690 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4691 ppc_mflr (code, ppc_r0);
4692 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4693 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4696 alloc_size = cfg->stack_offset;
4699 if (!method->save_lmf) {
4700 for (i = 31; i >= 13; --i) {
4701 if (cfg->used_int_regs & (1 << i)) {
4702 pos += sizeof (mgreg_t);
4706 pos += sizeof (MonoLMF);
4710 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4711 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4712 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4713 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4716 cfg->stack_usage = alloc_size;
4717 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4719 if (ppc_is_imm16 (-alloc_size)) {
4720 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4721 cfa_offset = alloc_size;
4722 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4723 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4726 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4727 ppc_load (code, ppc_r0, -alloc_size);
4728 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4729 cfa_offset = alloc_size;
4730 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4731 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4734 if (cfg->frame_reg != ppc_sp) {
4735 ppc_mr (code, cfg->frame_reg, ppc_sp);
4736 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4739 /* store runtime generic context */
4740 if (cfg->rgctx_var) {
4741 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4742 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4744 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4747 /* compute max_offset in order to use short forward jumps
4748 * we always do it on ppc because the immediate displacement
4749 * for jumps is too small
4752 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4754 bb->max_offset = max_offset;
4756 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4759 MONO_BB_FOR_EACH_INS (bb, ins)
4760 max_offset += ins_native_length (cfg, ins);
4763 /* load arguments allocated to register from the stack */
4766 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4768 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4769 ArgInfo *ainfo = &cinfo->ret;
4771 inst = cfg->vret_addr;
4774 if (ppc_is_imm16 (inst->inst_offset)) {
4775 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4777 ppc_load (code, ppc_r11, inst->inst_offset);
4778 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4782 tailcall_struct_index = 0;
4783 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4784 ArgInfo *ainfo = cinfo->args + i;
4785 inst = cfg->args [pos];
4787 if (cfg->verbose_level > 2)
4788 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4789 if (inst->opcode == OP_REGVAR) {
4790 if (ainfo->regtype == RegTypeGeneral)
4791 ppc_mr (code, inst->dreg, ainfo->reg);
4792 else if (ainfo->regtype == RegTypeFP)
4793 ppc_fmr (code, inst->dreg, ainfo->reg);
4794 else if (ainfo->regtype == RegTypeBase) {
4795 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4796 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4798 g_assert_not_reached ();
4800 if (cfg->verbose_level > 2)
4801 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4803 /* the argument should be put on the stack: FIXME handle size != word */
4804 if (ainfo->regtype == RegTypeGeneral) {
4805 switch (ainfo->size) {
4807 if (ppc_is_imm16 (inst->inst_offset)) {
4808 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4810 if (ppc_is_imm32 (inst->inst_offset)) {
4811 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4812 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4814 ppc_load (code, ppc_r11, inst->inst_offset);
4815 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4820 if (ppc_is_imm16 (inst->inst_offset)) {
4821 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4823 if (ppc_is_imm32 (inst->inst_offset)) {
4824 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4825 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4827 ppc_load (code, ppc_r11, inst->inst_offset);
4828 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4832 #ifdef __mono_ppc64__
4834 if (ppc_is_imm16 (inst->inst_offset)) {
4835 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4837 if (ppc_is_imm32 (inst->inst_offset)) {
4838 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4839 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4841 ppc_load (code, ppc_r11, inst->inst_offset);
4842 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4847 if (ppc_is_imm16 (inst->inst_offset)) {
4848 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4850 ppc_load (code, ppc_r11, inst->inst_offset);
4851 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4856 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4857 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4858 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4860 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4861 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4862 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4863 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4868 if (ppc_is_imm16 (inst->inst_offset)) {
4869 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4871 if (ppc_is_imm32 (inst->inst_offset)) {
4872 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4873 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4875 ppc_load (code, ppc_r11, inst->inst_offset);
4876 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4881 } else if (ainfo->regtype == RegTypeBase) {
4882 g_assert (ppc_is_imm16 (ainfo->offset));
4883 /* load the previous stack pointer in r11 */
4884 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4885 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4886 switch (ainfo->size) {
4888 if (ppc_is_imm16 (inst->inst_offset)) {
4889 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4891 if (ppc_is_imm32 (inst->inst_offset)) {
4892 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4893 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4895 ppc_load (code, ppc_r11, inst->inst_offset);
4896 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4901 if (ppc_is_imm16 (inst->inst_offset)) {
4902 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4904 if (ppc_is_imm32 (inst->inst_offset)) {
4905 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4906 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4908 ppc_load (code, ppc_r11, inst->inst_offset);
4909 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4913 #ifdef __mono_ppc64__
4915 if (ppc_is_imm16 (inst->inst_offset)) {
4916 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4918 if (ppc_is_imm32 (inst->inst_offset)) {
4919 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4920 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4922 ppc_load (code, ppc_r11, inst->inst_offset);
4923 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4928 if (ppc_is_imm16 (inst->inst_offset)) {
4929 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4931 ppc_load (code, ppc_r11, inst->inst_offset);
4932 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4937 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4938 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4939 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4940 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4941 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4943 /* use r12 to load the 2nd half of the long before we clobber r11. */
4944 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4945 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4946 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4947 ppc_stw (code, ppc_r0, 0, ppc_r11);
4948 ppc_stw (code, ppc_r12, 4, ppc_r11);
4953 if (ppc_is_imm16 (inst->inst_offset)) {
4954 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4956 if (ppc_is_imm32 (inst->inst_offset)) {
4957 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4958 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4960 ppc_load (code, ppc_r11, inst->inst_offset);
4961 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4966 } else if (ainfo->regtype == RegTypeFP) {
4967 g_assert (ppc_is_imm16 (inst->inst_offset));
4968 if (ainfo->size == 8)
4969 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4970 else if (ainfo->size == 4)
4971 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4973 g_assert_not_reached ();
4974 } else if (ainfo->regtype == RegTypeStructByVal) {
4975 int doffset = inst->inst_offset;
4979 g_assert (ppc_is_imm16 (inst->inst_offset));
4980 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4981 /* FIXME: what if there is no class? */
4982 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4983 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4984 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4987 * Darwin handles 1 and 2 byte
4988 * structs specially by
4989 * loading h/b into the arg
4990 * register. Only done for
4994 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4996 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5000 #ifdef __mono_ppc64__
5002 g_assert (cur_reg == 0);
5003 ppc_sldi (code, ppc_r0, ainfo->reg,
5004 (sizeof (gpointer) - ainfo->bytes) * 8);
5005 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5009 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5010 inst->inst_basereg);
5013 soffset += sizeof (gpointer);
5014 doffset += sizeof (gpointer);
5016 if (ainfo->vtsize) {
5017 /* FIXME: we need to do the shifting here, too */
5020 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5021 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5022 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5023 code = emit_memcpy (code, size - soffset,
5024 inst->inst_basereg, doffset,
5025 ppc_r11, ainfo->offset + soffset);
5027 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5028 inst->inst_basereg, doffset,
5029 ppc_r11, ainfo->offset + soffset);
5032 } else if (ainfo->regtype == RegTypeStructByAddr) {
5033 /* if it was originally a RegTypeBase */
5034 if (ainfo->offset) {
5035 /* load the previous stack pointer in r11 */
5036 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5037 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5039 ppc_mr (code, ppc_r11, ainfo->reg);
5042 if (cfg->tailcall_valuetype_addrs) {
5043 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5045 g_assert (ppc_is_imm16 (addr->inst_offset));
5046 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5048 tailcall_struct_index++;
5051 g_assert (ppc_is_imm16 (inst->inst_offset));
5052 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5053 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5055 g_assert_not_reached ();
5060 if (method->save_lmf) {
5061 if (lmf_pthread_key != -1) {
5062 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5063 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5064 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5066 if (cfg->compile_aot) {
5067 /* Compute the got address which is needed by the PLT entry */
5068 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5070 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5071 (gpointer)"mono_get_lmf_addr");
5072 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5073 ppc_load_func (code, ppc_r0, 0);
5074 ppc_mtlr (code, ppc_r0);
5080 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5081 /* lmf_offset is the offset from the previous stack pointer,
5082 * alloc_size is the total stack space allocated, so the offset
5083 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5084 * The pointer to the struct is put in ppc_r11 (new_lmf).
5085 * The callee-saved registers are already in the MonoLMF structure
5087 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5088 /* ppc_r3 is the result from mono_get_lmf_addr () */
5089 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5090 /* new_lmf->previous_lmf = *lmf_addr */
5091 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5092 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5093 /* *(lmf_addr) = r11 */
5094 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5095 /* save method info */
5096 if (cfg->compile_aot)
5098 ppc_load (code, ppc_r0, 0);
5100 ppc_load_ptr (code, ppc_r0, method);
5101 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5102 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5103 /* save the current IP */
5104 if (cfg->compile_aot) {
5106 ppc_mflr (code, ppc_r0);
5108 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5109 #ifdef __mono_ppc64__
5110 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5112 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5115 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5119 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5121 cfg->code_len = code - cfg->native_code;
5122 g_assert (cfg->code_len <= cfg->code_size);
5129 mono_arch_emit_epilog (MonoCompile *cfg)
5131 MonoMethod *method = cfg->method;
5133 int max_epilog_size = 16 + 20*4;
5136 if (cfg->method->save_lmf)
5137 max_epilog_size += 128;
5139 if (mono_jit_trace_calls != NULL)
5140 max_epilog_size += 50;
5142 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5143 max_epilog_size += 50;
5145 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5146 cfg->code_size *= 2;
5147 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5148 cfg->stat_code_reallocs++;
5152 * Keep in sync with OP_JMP
5154 code = cfg->native_code + cfg->code_len;
5156 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5157 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5161 if (method->save_lmf) {
5163 pos += sizeof (MonoLMF);
5165 /* save the frame reg in r8 */
5166 ppc_mr (code, ppc_r8, cfg->frame_reg);
5167 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5168 /* r5 = previous_lmf */
5169 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5171 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5172 /* *(lmf_addr) = previous_lmf */
5173 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5174 /* FIXME: speedup: there is no actual need to restore the registers if
5175 * we didn't actually change them (idea from Zoltan).
5178 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5180 /*for (i = 14; i < 32; i++) {
5181 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5183 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5184 /* use the saved copy of the frame reg in r8 */
5185 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5186 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5187 ppc_mtlr (code, ppc_r0);
5189 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5191 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5192 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5193 if (ppc_is_imm16 (return_offset)) {
5194 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5196 ppc_load (code, ppc_r11, return_offset);
5197 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5199 ppc_mtlr (code, ppc_r0);
5201 if (ppc_is_imm16 (cfg->stack_usage)) {
5202 int offset = cfg->stack_usage;
5203 for (i = 13; i <= 31; i++) {
5204 if (cfg->used_int_regs & (1 << i))
5205 offset -= sizeof (mgreg_t);
5207 if (cfg->frame_reg != ppc_sp)
5208 ppc_mr (code, ppc_r11, cfg->frame_reg);
5209 /* note r31 (possibly the frame register) is restored last */
5210 for (i = 13; i <= 31; i++) {
5211 if (cfg->used_int_regs & (1 << i)) {
5212 ppc_ldr (code, i, offset, cfg->frame_reg);
5213 offset += sizeof (mgreg_t);
5216 if (cfg->frame_reg != ppc_sp)
5217 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5219 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5221 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5222 if (cfg->used_int_regs) {
5223 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5224 for (i = 31; i >= 13; --i) {
5225 if (cfg->used_int_regs & (1 << i)) {
5226 pos += sizeof (mgreg_t);
5227 ppc_ldr (code, i, -pos, ppc_r11);
5230 ppc_mr (code, ppc_sp, ppc_r11);
5232 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5239 cfg->code_len = code - cfg->native_code;
5241 g_assert (cfg->code_len < cfg->code_size);
5244 #endif /* ifndef DISABLE_JIT */
5246 /* remove once throw_exception_by_name is eliminated */
5248 exception_id_by_name (const char *name)
5250 if (strcmp (name, "IndexOutOfRangeException") == 0)
5251 return MONO_EXC_INDEX_OUT_OF_RANGE;
5252 if (strcmp (name, "OverflowException") == 0)
5253 return MONO_EXC_OVERFLOW;
5254 if (strcmp (name, "ArithmeticException") == 0)
5255 return MONO_EXC_ARITHMETIC;
5256 if (strcmp (name, "DivideByZeroException") == 0)
5257 return MONO_EXC_DIVIDE_BY_ZERO;
5258 if (strcmp (name, "InvalidCastException") == 0)
5259 return MONO_EXC_INVALID_CAST;
5260 if (strcmp (name, "NullReferenceException") == 0)
5261 return MONO_EXC_NULL_REF;
5262 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5263 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5264 if (strcmp (name, "ArgumentException") == 0)
5265 return MONO_EXC_ARGUMENT;
5266 g_error ("Unknown intrinsic exception %s\n", name);
5272 mono_arch_emit_exceptions (MonoCompile *cfg)
5274 MonoJumpInfo *patch_info;
5277 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5278 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5279 int max_epilog_size = 50;
5281 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5282 exc_throw_pos [i] = NULL;
5283 exc_throw_found [i] = 0;
5286 /* count the number of exception infos */
5289 * make sure we have enough space for exceptions
5291 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5292 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5293 i = exception_id_by_name (patch_info->data.target);
5294 if (!exc_throw_found [i]) {
5295 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5296 exc_throw_found [i] = TRUE;
5298 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5299 max_epilog_size += 12;
5300 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5301 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5302 i = exception_id_by_name (ovfj->data.exception);
5303 if (!exc_throw_found [i]) {
5304 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5305 exc_throw_found [i] = TRUE;
5307 max_epilog_size += 8;
5311 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5312 cfg->code_size *= 2;
5313 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5314 cfg->stat_code_reallocs++;
5317 code = cfg->native_code + cfg->code_len;
5319 /* add code to raise exceptions */
5320 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5321 switch (patch_info->type) {
5322 case MONO_PATCH_INFO_BB_OVF: {
5323 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5324 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5325 /* patch the initial jump */
5326 ppc_patch (ip, code);
5327 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5329 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5330 /* jump back to the true target */
5332 ip = ovfj->data.bb->native_offset + cfg->native_code;
5333 ppc_patch (code - 4, ip);
5334 patch_info->type = MONO_PATCH_INFO_NONE;
5337 case MONO_PATCH_INFO_EXC_OVF: {
5338 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5339 MonoJumpInfo *newji;
5340 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5341 unsigned char *bcl = code;
5342 /* patch the initial jump: we arrived here with a call */
5343 ppc_patch (ip, code);
5344 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5346 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5347 /* patch the conditional jump to the right handler */
5348 /* make it processed next */
5349 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5350 newji->type = MONO_PATCH_INFO_EXC;
5351 newji->ip.i = bcl - cfg->native_code;
5352 newji->data.target = ovfj->data.exception;
5353 newji->next = patch_info->next;
5354 patch_info->next = newji;
5355 patch_info->type = MONO_PATCH_INFO_NONE;
5358 case MONO_PATCH_INFO_EXC: {
5359 MonoClass *exc_class;
5361 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5362 i = exception_id_by_name (patch_info->data.target);
5363 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5364 ppc_patch (ip, exc_throw_pos [i]);
5365 patch_info->type = MONO_PATCH_INFO_NONE;
5368 exc_throw_pos [i] = code;
5371 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5372 g_assert (exc_class);
5374 ppc_patch (ip, code);
5375 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5376 ppc_load (code, ppc_r3, exc_class->type_token);
5377 /* we got here from a conditional call, so the calling ip is set in lr */
5378 ppc_mflr (code, ppc_r4);
5379 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5380 patch_info->data.name = "mono_arch_throw_corlib_exception";
5381 patch_info->ip.i = code - cfg->native_code;
5382 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5383 ppc_load_func (code, ppc_r0, 0);
5384 ppc_mtctr (code, ppc_r0);
5385 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5397 cfg->code_len = code - cfg->native_code;
5399 g_assert (cfg->code_len <= cfg->code_size);
5405 try_offset_access (void *value, guint32 idx)
5407 register void* me __asm__ ("r2");
5408 void ***p = (void***)((char*)me + 284);
5409 int idx1 = idx / 32;
5410 int idx2 = idx % 32;
5413 if (value != p[idx1][idx2])
5420 setup_tls_access (void)
5424 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5425 size_t conf_size = 0;
5428 /* FIXME for darwin */
5429 guint32 *ins, *code;
5430 guint32 cmplwi_1023, li_0x48, blr_ins;
5434 tls_mode = TLS_MODE_FAILED;
5437 if (tls_mode == TLS_MODE_FAILED)
5439 if (g_getenv ("MONO_NO_TLS")) {
5440 tls_mode = TLS_MODE_FAILED;
5444 if (tls_mode == TLS_MODE_DETECT) {
5445 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5446 tls_mode = TLS_MODE_DARWIN_G4;
5447 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5448 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5449 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5450 tls_mode = TLS_MODE_NPTL;
5451 #elif !defined(TARGET_PS3)
5452 ins = (guint32*)pthread_getspecific;
5453 /* uncond branch to the real method */
5454 if ((*ins >> 26) == 18) {
5456 val = (*ins & ~3) << 6;
5460 ins = (guint32*)(long)val;
5462 ins = (guint32*) ((char*)ins + val);
5465 code = &cmplwi_1023;
5466 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5468 ppc_li (code, ppc_r4, 0x48);
5471 if (*ins == cmplwi_1023) {
5472 int found_lwz_284 = 0;
5473 for (ptk = 0; ptk < 20; ++ptk) {
5475 if (!*ins || *ins == blr_ins)
5477 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5482 if (!found_lwz_284) {
5483 tls_mode = TLS_MODE_FAILED;
5486 tls_mode = TLS_MODE_LTHREADS;
5487 } else if (*ins == li_0x48) {
5489 /* uncond branch to the real method */
5490 if ((*ins >> 26) == 18) {
5492 val = (*ins & ~3) << 6;
5496 ins = (guint32*)(long)val;
5498 ins = (guint32*) ((char*)ins + val);
5500 code = (guint32*)&val;
5501 ppc_li (code, ppc_r0, 0x7FF2);
5502 if (ins [1] == val) {
5503 /* Darwin on G4, implement */
5504 tls_mode = TLS_MODE_FAILED;
5507 code = (guint32*)&val;
5508 ppc_mfspr (code, ppc_r3, 104);
5509 if (ins [1] != val) {
5510 tls_mode = TLS_MODE_FAILED;
5513 tls_mode = TLS_MODE_DARWIN_G5;
5516 tls_mode = TLS_MODE_FAILED;
5520 tls_mode = TLS_MODE_FAILED;
5526 if (tls_mode == TLS_MODE_DETECT)
5527 tls_mode = TLS_MODE_FAILED;
5528 if (tls_mode == TLS_MODE_FAILED)
5530 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5531 monodomain_key = mono_domain_get_tls_offset();
5533 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5534 mono_domain_get_tls_offset returning -1) then use keyed access. */
5535 if (monodomain_key == -1) {
5536 ptk = mono_domain_get_tls_key ();
5538 monodomain_key = ptk;
5541 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5542 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5546 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5547 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5548 if (lmf_pthread_key == -1) {
5549 ptk = mono_jit_tls_id;
5551 /*g_print ("MonoLMF at: %d\n", ptk);*/
5552 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5553 init_tls_failed = 1;
5556 lmf_pthread_key = ptk;
5565 mono_arch_finish_init (void)
5567 setup_tls_access ();
5571 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5575 #ifdef MONO_ARCH_HAVE_IMT
5577 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5579 #define LOADSTORE_SIZE 4
5580 #define JUMP_IMM_SIZE 12
5581 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5582 #define ENABLE_WRONG_METHOD_CHECK 0
5585 * LOCKING: called with the domain lock held
5588 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5589 gpointer fail_tramp)
5593 guint8 *code, *start;
5595 for (i = 0; i < count; ++i) {
5596 MonoIMTCheckItem *item = imt_entries [i];
5597 if (item->is_equals) {
5598 if (item->check_target_idx) {
5599 if (!item->compare_done)
5600 item->chunk_size += CMP_SIZE;
5601 if (item->has_target_code)
5602 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5604 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5607 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5608 if (!item->has_target_code)
5609 item->chunk_size += LOADSTORE_SIZE;
5611 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5612 #if ENABLE_WRONG_METHOD_CHECK
5613 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5618 item->chunk_size += CMP_SIZE + BR_SIZE;
5619 imt_entries [item->check_target_idx]->compare_done = TRUE;
5621 size += item->chunk_size;
5623 /* the initial load of the vtable address */
5624 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5626 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5628 code = mono_domain_code_reserve (domain, size);
5633 * We need to save and restore r11 because it might be
5634 * used by the caller as the vtable register, so
5635 * clobbering it will trip up the magic trampoline.
5637 * FIXME: Get rid of this by making sure that r11 is
5638 * not used as the vtable register in interface calls.
5640 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5641 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5643 for (i = 0; i < count; ++i) {
5644 MonoIMTCheckItem *item = imt_entries [i];
5645 item->code_target = code;
5646 if (item->is_equals) {
5647 if (item->check_target_idx) {
5648 if (!item->compare_done) {
5649 ppc_load (code, ppc_r0, (gsize)item->key);
5650 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5652 item->jmp_code = code;
5653 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5654 if (item->has_target_code) {
5655 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5657 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5658 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5660 ppc_mtctr (code, ppc_r0);
5661 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5664 ppc_load (code, ppc_r0, (gulong)item->key);
5665 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5666 item->jmp_code = code;
5667 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5668 if (item->has_target_code) {
5669 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5672 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5673 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5675 ppc_mtctr (code, ppc_r0);
5676 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5677 ppc_patch (item->jmp_code, code);
5678 ppc_load_ptr (code, ppc_r0, fail_tramp);
5679 ppc_mtctr (code, ppc_r0);
5680 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5681 item->jmp_code = NULL;
5683 /* enable the commented code to assert on wrong method */
5684 #if ENABLE_WRONG_METHOD_CHECK
5685 ppc_load (code, ppc_r0, (guint32)item->key);
5686 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5687 item->jmp_code = code;
5688 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5690 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5691 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5692 ppc_mtctr (code, ppc_r0);
5693 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5694 #if ENABLE_WRONG_METHOD_CHECK
5695 ppc_patch (item->jmp_code, code);
5697 item->jmp_code = NULL;
5702 ppc_load (code, ppc_r0, (gulong)item->key);
5703 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5704 item->jmp_code = code;
5705 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5708 /* patch the branches to get to the target items */
5709 for (i = 0; i < count; ++i) {
5710 MonoIMTCheckItem *item = imt_entries [i];
5711 if (item->jmp_code) {
5712 if (item->check_target_idx) {
5713 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5719 mono_stats.imt_thunks_size += code - start;
5720 g_assert (code - start <= size);
5721 mono_arch_flush_icache (start, size);
5726 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5728 mgreg_t *r = (mgreg_t*)regs;
5730 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5735 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5737 mgreg_t *r = (mgreg_t*)regs;
5739 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5743 mono_arch_get_cie_program (void)
5747 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5753 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5760 mono_arch_print_tree (MonoInst *tree, int arity)
5765 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5769 setup_tls_access ();
5770 if (monodomain_key == -1)
5773 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5774 ins->inst_offset = monodomain_key;
5779 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5782 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5784 g_assert (reg >= ppc_r13);
5786 return ctx->regs [reg - ppc_r13];
5790 mono_arch_get_patch_offset (guint8 *code)
5796 * mono_aot_emit_load_got_addr:
5798 * Emit code to load the got address.
5799 * On PPC, the result is placed into r30.
5802 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5805 ppc_mflr (code, ppc_r30);
5807 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5809 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5810 /* arch_emit_got_address () patches this */
5811 #if defined(TARGET_POWERPC64)
5817 ppc_load32 (code, ppc_r0, 0);
5818 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5825 * mono_ppc_emit_load_aotconst:
5827 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5828 * TARGET from the mscorlib GOT in full-aot code.
5829 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5833 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5835 /* Load the mscorlib got address */
5836 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5837 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5838 /* arch_emit_got_access () patches this */
5839 ppc_load32 (code, ppc_r0, 0);
5840 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5845 /* Soft Debug support */
5846 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5853 * mono_arch_set_breakpoint:
5855 * See mini-amd64.c for docs.
5858 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5861 guint8 *orig_code = code;
5863 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5864 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5866 g_assert (code - orig_code == BREAKPOINT_SIZE);
5868 mono_arch_flush_icache (orig_code, code - orig_code);
5872 * mono_arch_clear_breakpoint:
5874 * See mini-amd64.c for docs.
5877 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5882 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5885 mono_arch_flush_icache (ip, code - ip);
5889 * mono_arch_is_breakpoint_event:
5891 * See mini-amd64.c for docs.
5894 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5896 siginfo_t* sinfo = (siginfo_t*) info;
5897 /* Sometimes the address is off by 4 */
5898 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5905 * mono_arch_skip_breakpoint:
5907 * See mini-amd64.c for docs.
5910 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5912 /* skip the ldptr */
5913 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5921 * mono_arch_start_single_stepping:
5923 * See mini-amd64.c for docs.
5926 mono_arch_start_single_stepping (void)
5928 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5932 * mono_arch_stop_single_stepping:
5934 * See mini-amd64.c for docs.
5937 mono_arch_stop_single_stepping (void)
5939 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5943 * mono_arch_is_single_step_event:
5945 * See mini-amd64.c for docs.
5948 mono_arch_is_single_step_event (void *info, void *sigctx)
5950 siginfo_t* sinfo = (siginfo_t*) info;
5951 /* Sometimes the address is off by 4 */
5952 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5959 * mono_arch_skip_single_step:
5961 * See mini-amd64.c for docs.
5964 mono_arch_skip_single_step (MonoContext *ctx)
5966 /* skip the ldptr */
5967 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5971 * mono_arch_create_seq_point_info:
5973 * See mini-amd64.c for docs.
5976 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)