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/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-proclib.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-ppc.h>
23 #ifdef TARGET_POWERPC64
24 #include "cpu-ppc64.h"
31 #include <sys/sysctl.h>
37 #define FORCE_INDIR_CALL 1
48 /* cpu_hw_caps contains the flags defined below */
49 static int cpu_hw_caps = 0;
50 static int cachelinesize = 0;
51 static int cachelineinc = 0;
53 PPC_ICACHE_SNOOP = 1 << 0,
54 PPC_MULTIPLE_LS_UNITS = 1 << 1,
55 PPC_SMP_CAPABLE = 1 << 2,
58 PPC_MOVE_FPR_GPR = 1 << 5,
62 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
64 /* This mutex protects architecture specific caches */
65 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
67 static mono_mutex_t mini_arch_mutex;
69 int mono_exc_esp_offset = 0;
70 static int tls_mode = TLS_MODE_DETECT;
71 static int lmf_pthread_key = -1;
74 * The code generated for sequence points reads from this location, which is
75 * made read-only when single stepping is enabled.
77 static gpointer ss_trigger_page;
79 /* Enabled breakpoints read from this trigger page */
80 static gpointer bp_trigger_page;
83 offsets_from_pthread_key (guint32 key, int *offset2)
87 *offset2 = idx2 * sizeof (gpointer);
88 return 284 + idx1 * sizeof (gpointer);
91 #define emit_linuxthreads_tls(code,dreg,key) do {\
93 off1 = offsets_from_pthread_key ((key), &off2); \
94 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
95 ppc_ldptr ((code), (dreg), off2, (dreg)); \
98 #define emit_darwing5_tls(code,dreg,key) do {\
99 int off1 = 0x48 + key * sizeof (gpointer); \
100 ppc_mfspr ((code), (dreg), 104); \
101 ppc_ldptr ((code), (dreg), off1, (dreg)); \
104 /* FIXME: ensure the sc call preserves all but r3 */
105 #define emit_darwing4_tls(code,dreg,key) do {\
106 int off1 = 0x48 + key * sizeof (gpointer); \
107 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r12, ppc_r3); \
108 ppc_li ((code), ppc_r0, 0x7FF2); \
110 ppc_lwz ((code), (dreg), off1, ppc_r3); \
111 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r12); \
114 #ifdef PPC_THREAD_PTR_REG
115 #define emit_nptl_tls(code,dreg,key) do { \
117 int off2 = key >> 15; \
118 if ((off2 == 0) || (off2 == -1)) { \
119 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
121 int off3 = (off2 + 1) > 1; \
122 ppc_addis ((code), ppc_r12, PPC_THREAD_PTR_REG, off3); \
123 ppc_ldptr ((code), (dreg), off1, ppc_r12); \
127 #define emit_nptl_tls(code,dreg,key) do { \
128 g_assert_not_reached (); \
132 #define emit_tls_access(code,dreg,key) do { \
133 switch (tls_mode) { \
134 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
135 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
137 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
138 default: g_assert_not_reached (); \
142 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
144 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
145 inst->type = STACK_R8; \
147 inst->inst_p0 = (void*)(addr); \
148 mono_bblock_add_inst (cfg->cbb, inst); \
152 mono_arch_regname (int reg) {
153 static const char rnames[][4] = {
154 "r0", "sp", "r2", "r3", "r4",
155 "r5", "r6", "r7", "r8", "r9",
156 "r10", "r11", "r12", "r13", "r14",
157 "r15", "r16", "r17", "r18", "r19",
158 "r20", "r21", "r22", "r23", "r24",
159 "r25", "r26", "r27", "r28", "r29",
162 if (reg >= 0 && reg < 32)
168 mono_arch_fregname (int reg) {
169 static const char rnames[][4] = {
170 "f0", "f1", "f2", "f3", "f4",
171 "f5", "f6", "f7", "f8", "f9",
172 "f10", "f11", "f12", "f13", "f14",
173 "f15", "f16", "f17", "f18", "f19",
174 "f20", "f21", "f22", "f23", "f24",
175 "f25", "f26", "f27", "f28", "f29",
178 if (reg >= 0 && reg < 32)
183 /* this function overwrites r0, r11, r12 */
185 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
187 /* unrolled, use the counter in big */
188 if (size > sizeof (gpointer) * 5) {
189 long shifted = size / SIZEOF_VOID_P;
190 guint8 *copy_loop_start, *copy_loop_jump;
192 ppc_load (code, ppc_r0, shifted);
193 ppc_mtctr (code, ppc_r0);
194 //g_assert (sreg == ppc_r12);
195 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (gpointer)));
196 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (gpointer)));
197 copy_loop_start = code;
198 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
200 copy_loop_jump = code;
201 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
202 ppc_patch (copy_loop_jump, copy_loop_start);
203 size -= shifted * sizeof (gpointer);
204 doffset = soffset = 0;
207 #ifdef __mono_ppc64__
208 /* the hardware has multiple load/store units and the move is long
209 enough to use more then one register, then use load/load/store/store
210 to execute 2 instructions per cycle. */
211 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
213 ppc_ldptr (code, ppc_r0, soffset, sreg);
214 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
215 ppc_stptr (code, ppc_r0, doffset, dreg);
216 ppc_stptr (code, ppc_r11, doffset+8, dreg);
223 ppc_ldr (code, ppc_r0, soffset, sreg);
224 ppc_str (code, ppc_r0, doffset, dreg);
230 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
232 ppc_lwz (code, ppc_r0, soffset, sreg);
233 ppc_lwz (code, ppc_r11, soffset+4, sreg);
234 ppc_stw (code, ppc_r0, doffset, dreg);
235 ppc_stw (code, ppc_r11, doffset+4, dreg);
243 ppc_lwz (code, ppc_r0, soffset, sreg);
244 ppc_stw (code, ppc_r0, doffset, dreg);
250 ppc_lhz (code, ppc_r0, soffset, sreg);
251 ppc_sth (code, ppc_r0, doffset, dreg);
257 ppc_lbz (code, ppc_r0, soffset, sreg);
258 ppc_stb (code, ppc_r0, doffset, dreg);
267 * mono_arch_get_argument_info:
268 * @csig: a method signature
269 * @param_count: the number of parameters to consider
270 * @arg_info: an array to store the result infos
272 * Gathers information on parameters such as size, alignment and
273 * padding. arg_info should be large enought to hold param_count + 1 entries.
275 * Returns the size of the activation frame.
278 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
284 int k, frame_size = 0;
285 int size, align, pad;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
293 arg_info [0].offset = offset;
296 frame_size += sizeof (gpointer);
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
307 size = mini_type_stack_size (csig->params [k], &align);
309 /* ignore alignment for now */
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
318 arg_info [k + 1].offset = offset;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
330 #ifdef __mono_ppc64__
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
367 return is_load_sequence (&code [-6]);
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
380 #define MAX_ARCH_DELEGATE_PARAMS 7
383 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
385 guint8 *code, *start;
388 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
390 start = code = mono_global_codeman_reserve (size);
392 code = mono_ppc_create_pre_code_ftnptr (code);
394 /* Replace the this argument with the target */
395 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
396 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
397 /* it's a function descriptor */
398 /* Can't use ldptr as it doesn't work with r0 */
399 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
401 ppc_mtctr (code, ppc_r0);
402 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
403 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
405 g_assert ((code - start) <= size);
407 mono_arch_flush_icache (start, size);
411 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
412 start = code = mono_global_codeman_reserve (size);
414 code = mono_ppc_create_pre_code_ftnptr (code);
416 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
417 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
418 /* it's a function descriptor */
419 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
421 ppc_mtctr (code, ppc_r0);
422 /* slide down the arguments */
423 for (i = 0; i < param_count; ++i) {
424 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
428 g_assert ((code - start) <= size);
430 mono_arch_flush_icache (start, size);
434 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
436 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
437 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
445 mono_arch_get_delegate_invoke_impls (void)
451 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
452 res = g_slist_prepend (res, info);
454 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
455 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
456 res = g_slist_prepend (res, info);
463 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
465 guint8 *code, *start;
467 /* FIXME: Support more cases */
468 if (MONO_TYPE_ISSTRUCT (sig->ret))
472 static guint8* cached = NULL;
478 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
481 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
482 mono_tramp_info_register (info, NULL);
484 mono_memory_barrier ();
488 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
491 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
493 for (i = 0; i < sig->param_count; ++i)
494 if (!mono_is_regsize_var (sig->params [i]))
498 code = cache [sig->param_count];
503 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
504 start = mono_aot_get_trampoline (name);
508 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
509 mono_tramp_info_register (info, NULL);
512 mono_memory_barrier ();
514 cache [sig->param_count] = start;
520 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
526 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
528 mgreg_t *r = (mgreg_t*)regs;
530 return (gpointer)(gsize)r [ppc_r3];
538 #define MAX_AUX_ENTRIES 128
540 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
541 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
543 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
545 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
546 #define ISA_64 0x40000000
548 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
549 #define ISA_MOVE_FPR_GPR 0x00000200
551 * Initialize the cpu to execute managed code.
554 mono_arch_cpu_init (void)
559 * Initialize architecture specific code.
562 mono_arch_init (void)
564 #if defined(MONO_CROSS_COMPILE)
565 #elif defined(__APPLE__)
567 size_t len = sizeof (cachelinesize);
570 mib [1] = HW_CACHELINE;
572 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
576 cachelineinc = cachelinesize;
578 #elif defined(__linux__)
579 AuxVec vec [MAX_AUX_ENTRIES];
580 int i, vec_entries = 0;
581 /* sadly this will work only with 2.6 kernels... */
582 FILE* f = fopen ("/proc/self/auxv", "rb");
585 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
589 for (i = 0; i < vec_entries; i++) {
590 int type = vec [i].type;
592 if (type == 19) { /* AT_DCACHEBSIZE */
593 cachelinesize = vec [i].value;
597 #elif defined(G_COMPILER_CODEWARRIOR)
601 //#error Need a way to get cache line size
604 if (mono_hwcap_ppc_has_icache_snoop)
605 cpu_hw_caps |= PPC_ICACHE_SNOOP;
607 if (mono_hwcap_ppc_is_isa_2x)
608 cpu_hw_caps |= PPC_ISA_2X;
610 if (mono_hwcap_ppc_is_isa_64)
611 cpu_hw_caps |= PPC_ISA_64;
613 if (mono_hwcap_ppc_has_move_fpr_gpr)
614 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
616 if (mono_hwcap_ppc_has_multiple_ls_units)
617 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
623 cachelineinc = cachelinesize;
625 if (mono_cpu_count () > 1)
626 cpu_hw_caps |= PPC_SMP_CAPABLE;
628 mono_os_mutex_init_recursive (&mini_arch_mutex);
630 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
631 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
632 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
634 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
636 // FIXME: Fix partial sharing for power and remove this
637 mono_set_partial_sharing_supported (FALSE);
641 * Cleanup architecture specific code.
644 mono_arch_cleanup (void)
646 mono_os_mutex_destroy (&mini_arch_mutex);
650 * This function returns the optimizations supported on this cpu.
653 mono_arch_cpu_optimizations (guint32 *exclude_mask)
657 /* no ppc-specific optimizations yet */
663 * This function test for all SIMD functions supported.
665 * Returns a bitmask corresponding to all supported versions.
669 mono_arch_cpu_enumerate_simd_versions (void)
671 /* SIMD is currently unimplemented */
675 #ifdef __mono_ppc64__
676 #define CASE_PPC32(c)
677 #define CASE_PPC64(c) case c:
679 #define CASE_PPC32(c) case c:
680 #define CASE_PPC64(c)
684 is_regsize_var (MonoType *t) {
687 t = mini_get_underlying_type (t);
691 CASE_PPC64 (MONO_TYPE_I8)
692 CASE_PPC64 (MONO_TYPE_U8)
696 case MONO_TYPE_FNPTR:
698 case MONO_TYPE_OBJECT:
699 case MONO_TYPE_STRING:
700 case MONO_TYPE_CLASS:
701 case MONO_TYPE_SZARRAY:
702 case MONO_TYPE_ARRAY:
704 case MONO_TYPE_GENERICINST:
705 if (!mono_type_generic_inst_is_valuetype (t))
708 case MONO_TYPE_VALUETYPE:
716 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
721 for (i = 0; i < cfg->num_varinfo; i++) {
722 MonoInst *ins = cfg->varinfo [i];
723 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
726 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
729 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
732 /* we can only allocate 32 bit values */
733 if (is_regsize_var (ins->inst_vtype)) {
734 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
735 g_assert (i == vmv->idx);
736 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
742 #endif /* ifndef DISABLE_JIT */
745 mono_arch_get_global_int_regs (MonoCompile *cfg)
749 if (cfg->frame_reg != ppc_sp)
751 /* ppc_r13 is used by the system on PPC EABI */
752 for (i = 14; i < top; ++i) {
754 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
755 * since the trampolines can clobber r12.
757 if (!(cfg->compile_aot && i == 29))
758 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
765 * mono_arch_regalloc_cost:
767 * Return the cost, in number of memory references, of the action of
768 * allocating the variable VMV into a register during global register
772 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
779 mono_arch_flush_icache (guint8 *code, gint size)
781 #ifdef MONO_CROSS_COMPILE
784 guint8 *endp, *start;
788 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
789 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
790 #if defined(G_COMPILER_CODEWARRIOR)
791 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
792 for (p = start; p < endp; p += cachelineinc) {
796 for (p = start; p < endp; p += cachelineinc) {
802 for (p = start; p < endp; p += cachelineinc) {
813 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
814 * The sync is required to insure that the store queue is completely empty.
815 * While the icbi performs no cache operations, icbi/isync is required to
816 * kill local prefetch.
818 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
820 asm ("icbi 0,%0;" : : "r"(code) : "memory");
824 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
825 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
826 for (p = start; p < endp; p += cachelineinc) {
827 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
830 for (p = start; p < endp; p += cachelineinc) {
831 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
836 for (p = start; p < endp; p += cachelineinc) {
837 /* for ISA2.0+ implementations we should not need any extra sync between the
838 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
839 * So I am not sure which chip had this problem but its not an issue on
840 * of the ISA V2 chips.
842 if (cpu_hw_caps & PPC_ISA_2X)
843 asm ("icbi 0,%0;" : : "r"(p) : "memory");
845 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
847 if (!(cpu_hw_caps & PPC_ISA_2X))
855 mono_arch_flush_register_windows (void)
860 #define ALWAYS_ON_STACK(s) s
861 #define FP_ALSO_IN_REG(s) s
863 #ifdef __mono_ppc64__
864 #define ALWAYS_ON_STACK(s) s
865 #define FP_ALSO_IN_REG(s) s
867 #define ALWAYS_ON_STACK(s)
868 #define FP_ALSO_IN_REG(s)
870 #define ALIGN_DOUBLES
879 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
884 guint32 vtsize; /* in param area */
886 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
887 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
888 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
889 guint8 bytes : 4; /* size in bytes - only valid for
890 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
891 in one word, otherwise it's 0*/
900 gboolean vtype_retaddr;
908 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
910 #ifdef __mono_ppc64__
915 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
916 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
917 ainfo->reg = ppc_sp; /* in the caller */
918 ainfo->regtype = RegTypeBase;
919 *stack_size += sizeof (gpointer);
921 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
925 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
927 //*stack_size += (*stack_size % 8);
929 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
930 ainfo->reg = ppc_sp; /* in the caller */
931 ainfo->regtype = RegTypeBase;
938 ALWAYS_ON_STACK (*stack_size += 8);
946 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
948 has_only_a_r48_field (MonoClass *klass)
952 gboolean have_field = FALSE;
954 while ((f = mono_class_get_fields (klass, &iter))) {
955 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
958 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
969 get_call_info (MonoMethodSignature *sig)
971 guint i, fr, gr, pstart;
972 int n = sig->hasthis + sig->param_count;
973 MonoType *simpletype;
974 guint32 stack_size = 0;
975 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
976 gboolean is_pinvoke = sig->pinvoke;
978 fr = PPC_FIRST_FPARG_REG;
979 gr = PPC_FIRST_ARG_REG;
981 /* FIXME: handle returning a struct */
982 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
983 cinfo->vtype_retaddr = TRUE;
989 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
990 * the first argument, allowing 'this' to be always passed in the first arg reg.
991 * Also do this if the first argument is a reference type, since virtual calls
992 * are sometimes made using calli without sig->hasthis set, like in the delegate
995 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
997 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1000 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1004 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1005 cinfo->struct_ret = cinfo->ret.reg;
1006 cinfo->vret_arg_index = 1;
1010 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1014 if (cinfo->vtype_retaddr) {
1015 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1016 cinfo->struct_ret = cinfo->ret.reg;
1020 DEBUG(printf("params: %d\n", sig->param_count));
1021 for (i = pstart; i < sig->param_count; ++i) {
1022 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1023 /* Prevent implicit arguments and sig_cookie from
1024 being passed in registers */
1025 gr = PPC_LAST_ARG_REG + 1;
1026 /* FIXME: don't we have to set fr, too? */
1027 /* Emit the signature cookie just before the implicit arguments */
1028 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1030 DEBUG(printf("param %d: ", i));
1031 if (sig->params [i]->byref) {
1032 DEBUG(printf("byref\n"));
1033 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1037 simpletype = mini_get_underlying_type (sig->params [i]);
1038 switch (simpletype->type) {
1039 case MONO_TYPE_BOOLEAN:
1042 cinfo->args [n].size = 1;
1043 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1046 case MONO_TYPE_CHAR:
1049 cinfo->args [n].size = 2;
1050 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1055 cinfo->args [n].size = 4;
1056 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1062 case MONO_TYPE_FNPTR:
1063 case MONO_TYPE_CLASS:
1064 case MONO_TYPE_OBJECT:
1065 case MONO_TYPE_STRING:
1066 case MONO_TYPE_SZARRAY:
1067 case MONO_TYPE_ARRAY:
1068 cinfo->args [n].size = sizeof (gpointer);
1069 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1072 case MONO_TYPE_GENERICINST:
1073 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1074 cinfo->args [n].size = sizeof (gpointer);
1075 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1080 case MONO_TYPE_VALUETYPE:
1081 case MONO_TYPE_TYPEDBYREF: {
1083 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1084 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1085 size = sizeof (MonoTypedRef);
1086 else if (is_pinvoke)
1087 size = mono_class_native_size (klass, NULL);
1089 size = mono_class_value_size (klass, NULL);
1091 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1092 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1093 cinfo->args [n].size = size;
1095 /* It was 7, now it is 8 in LinuxPPC */
1096 if (fr <= PPC_LAST_FPARG_REG) {
1097 cinfo->args [n].regtype = RegTypeFP;
1098 cinfo->args [n].reg = fr;
1100 FP_ALSO_IN_REG (gr ++);
1101 #if !defined(__mono_ppc64__)
1103 FP_ALSO_IN_REG (gr ++);
1105 ALWAYS_ON_STACK (stack_size += size);
1107 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1108 cinfo->args [n].regtype = RegTypeBase;
1109 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1116 DEBUG(printf ("load %d bytes struct\n",
1117 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1119 #if PPC_PASS_STRUCTS_BY_VALUE
1121 int align_size = size;
1123 int rest = PPC_LAST_ARG_REG - gr + 1;
1126 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1129 gboolean is_all_floats = mini_type_is_hfa (sig->params [i], &mbr_cnt, &mbr_size);
1131 if (is_all_floats && (mbr_cnt <= 8)) {
1132 rest = PPC_LAST_FPARG_REG - fr + 1;
1134 // Pass small (<= 8 member) structures entirely made up of either float or double members
1135 // in FR registers. There have to be at least mbr_cnt registers left.
1136 if (is_all_floats &&
1137 (rest >= mbr_cnt) &&
1140 n_in_regs = MIN (rest, nregs);
1141 cinfo->args [n].regtype = RegTypeFPStructByVal;
1142 cinfo->args [n].vtregs = n_in_regs;
1143 cinfo->args [n].size = mbr_size;
1144 cinfo->args [n].vtsize = nregs - n_in_regs;
1145 cinfo->args [n].reg = fr;
1147 if (mbr_size == 4) {
1149 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1152 FP_ALSO_IN_REG (gr += (n_in_regs));
1157 align_size += (sizeof (gpointer) - 1);
1158 align_size &= ~(sizeof (gpointer) - 1);
1159 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1160 n_in_regs = MIN (rest, nregs);
1164 /* FIXME: check this */
1165 if (size >= 3 && size % 4 != 0)
1168 cinfo->args [n].regtype = RegTypeStructByVal;
1169 cinfo->args [n].vtregs = n_in_regs;
1170 cinfo->args [n].size = n_in_regs;
1171 cinfo->args [n].vtsize = nregs - n_in_regs;
1172 cinfo->args [n].reg = gr;
1176 #ifdef __mono_ppc64__
1177 if (nregs == 1 && is_pinvoke)
1178 cinfo->args [n].bytes = size;
1181 cinfo->args [n].bytes = 0;
1182 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1183 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1184 stack_size += nregs * sizeof (gpointer);
1187 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1188 cinfo->args [n].regtype = RegTypeStructByAddr;
1189 cinfo->args [n].vtsize = size;
1196 cinfo->args [n].size = 8;
1197 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1201 cinfo->args [n].size = 4;
1203 /* It was 7, now it is 8 in LinuxPPC */
1204 if (fr <= PPC_LAST_FPARG_REG
1205 // For non-native vararg calls the parms must go in storage
1206 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1208 cinfo->args [n].regtype = RegTypeFP;
1209 cinfo->args [n].reg = fr;
1211 FP_ALSO_IN_REG (gr ++);
1212 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1214 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1215 cinfo->args [n].regtype = RegTypeBase;
1216 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1217 stack_size += SIZEOF_REGISTER;
1222 cinfo->args [n].size = 8;
1223 /* It was 7, now it is 8 in LinuxPPC */
1224 if (fr <= PPC_LAST_FPARG_REG
1225 // For non-native vararg calls the parms must go in storage
1226 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1228 cinfo->args [n].regtype = RegTypeFP;
1229 cinfo->args [n].reg = fr;
1231 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1232 ALWAYS_ON_STACK (stack_size += 8);
1234 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1235 cinfo->args [n].regtype = RegTypeBase;
1236 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1242 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1247 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1248 /* Prevent implicit arguments and sig_cookie from
1249 being passed in registers */
1250 gr = PPC_LAST_ARG_REG + 1;
1251 /* Emit the signature cookie just before the implicit arguments */
1252 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1256 simpletype = mini_get_underlying_type (sig->ret);
1257 switch (simpletype->type) {
1258 case MONO_TYPE_BOOLEAN:
1263 case MONO_TYPE_CHAR:
1269 case MONO_TYPE_FNPTR:
1270 case MONO_TYPE_CLASS:
1271 case MONO_TYPE_OBJECT:
1272 case MONO_TYPE_SZARRAY:
1273 case MONO_TYPE_ARRAY:
1274 case MONO_TYPE_STRING:
1275 cinfo->ret.reg = ppc_r3;
1279 cinfo->ret.reg = ppc_r3;
1283 cinfo->ret.reg = ppc_f1;
1284 cinfo->ret.regtype = RegTypeFP;
1286 case MONO_TYPE_GENERICINST:
1287 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1288 cinfo->ret.reg = ppc_r3;
1292 case MONO_TYPE_VALUETYPE:
1294 case MONO_TYPE_TYPEDBYREF:
1295 case MONO_TYPE_VOID:
1298 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1302 /* align stack size to 16 */
1303 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1304 stack_size = (stack_size + 15) & ~15;
1306 cinfo->stack_usage = stack_size;
1311 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1317 c1 = get_call_info (caller_sig);
1318 c2 = get_call_info (callee_sig);
1319 res = c1->stack_usage >= c2->stack_usage;
1320 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1321 /* An address on the callee's stack is passed as the first argument */
1323 for (i = 0; i < c2->nargs; ++i) {
1324 if (c2->args [i].regtype == RegTypeStructByAddr)
1325 /* An address on the callee's stack is passed as the argument */
1330 if (!mono_debug_count ())
1341 * Set var information according to the calling convention. ppc version.
1342 * The locals var stuff should most likely be split in another method.
1345 mono_arch_allocate_vars (MonoCompile *m)
1347 MonoMethodSignature *sig;
1348 MonoMethodHeader *header;
1350 int i, offset, size, align, curinst;
1351 int frame_reg = ppc_sp;
1353 guint32 locals_stack_size, locals_stack_align;
1355 m->flags |= MONO_CFG_HAS_SPILLUP;
1357 /* allow room for the vararg method args: void* and long/double */
1358 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1359 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1360 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1361 * call convs needs to be handled this way.
1363 if (m->flags & MONO_CFG_HAS_VARARGS)
1364 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1365 /* gtk-sharp and other broken code will dllimport vararg functions even with
1366 * non-varargs signatures. Since there is little hope people will get this right
1367 * we assume they won't.
1369 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1370 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1375 * We use the frame register also for any method that has
1376 * exception clauses. This way, when the handlers are called,
1377 * the code will reference local variables using the frame reg instead of
1378 * the stack pointer: if we had to restore the stack pointer, we'd
1379 * corrupt the method frames that are already on the stack (since
1380 * filters get called before stack unwinding happens) when the filter
1381 * code would call any method (this also applies to finally etc.).
1383 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1384 frame_reg = ppc_r31;
1385 m->frame_reg = frame_reg;
1386 if (frame_reg != ppc_sp) {
1387 m->used_int_regs |= 1 << frame_reg;
1390 sig = mono_method_signature (m->method);
1394 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1395 m->ret->opcode = OP_REGVAR;
1396 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1398 /* FIXME: handle long values? */
1399 switch (mini_get_underlying_type (sig->ret)->type) {
1400 case MONO_TYPE_VOID:
1404 m->ret->opcode = OP_REGVAR;
1405 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1408 m->ret->opcode = OP_REGVAR;
1409 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1413 /* local vars are at a positive offset from the stack pointer */
1415 * also note that if the function uses alloca, we use ppc_r31
1416 * to point at the local variables.
1418 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1419 /* align the offset to 16 bytes: not sure this is needed here */
1421 //offset &= ~(16 - 1);
1423 /* add parameter area size for called functions */
1424 offset += m->param_area;
1426 offset &= ~(16 - 1);
1428 /* allow room to save the return value */
1429 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1432 /* the MonoLMF structure is stored just below the stack pointer */
1435 /* this stuff should not be needed on ppc and the new jit,
1436 * because a call on ppc to the handlers doesn't change the
1437 * stack pointer and the jist doesn't manipulate the stack pointer
1438 * for operations involving valuetypes.
1440 /* reserve space to store the esp */
1441 offset += sizeof (gpointer);
1443 /* this is a global constant */
1444 mono_exc_esp_offset = offset;
1447 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1448 offset += sizeof(gpointer) - 1;
1449 offset &= ~(sizeof(gpointer) - 1);
1451 m->vret_addr->opcode = OP_REGOFFSET;
1452 m->vret_addr->inst_basereg = frame_reg;
1453 m->vret_addr->inst_offset = offset;
1455 if (G_UNLIKELY (m->verbose_level > 1)) {
1456 printf ("vret_addr =");
1457 mono_print_ins (m->vret_addr);
1460 offset += sizeof(gpointer);
1463 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1464 if (locals_stack_align) {
1465 offset += (locals_stack_align - 1);
1466 offset &= ~(locals_stack_align - 1);
1468 for (i = m->locals_start; i < m->num_varinfo; i++) {
1469 if (offsets [i] != -1) {
1470 MonoInst *inst = m->varinfo [i];
1471 inst->opcode = OP_REGOFFSET;
1472 inst->inst_basereg = frame_reg;
1473 inst->inst_offset = offset + offsets [i];
1475 g_print ("allocating local %d (%s) to %d\n",
1476 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1480 offset += locals_stack_size;
1484 inst = m->args [curinst];
1485 if (inst->opcode != OP_REGVAR) {
1486 inst->opcode = OP_REGOFFSET;
1487 inst->inst_basereg = frame_reg;
1488 offset += sizeof (gpointer) - 1;
1489 offset &= ~(sizeof (gpointer) - 1);
1490 inst->inst_offset = offset;
1491 offset += sizeof (gpointer);
1496 for (i = 0; i < sig->param_count; ++i) {
1497 inst = m->args [curinst];
1498 if (inst->opcode != OP_REGVAR) {
1499 inst->opcode = OP_REGOFFSET;
1500 inst->inst_basereg = frame_reg;
1502 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1503 inst->backend.is_pinvoke = 1;
1505 size = mono_type_size (sig->params [i], &align);
1507 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1508 size = align = sizeof (gpointer);
1510 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1511 * they are saved using std in the prolog.
1513 align = sizeof (gpointer);
1514 offset += align - 1;
1515 offset &= ~(align - 1);
1516 inst->inst_offset = offset;
1522 /* some storage for fp conversions */
1525 m->arch.fp_conv_var_offset = offset;
1528 /* align the offset to 16 bytes */
1530 offset &= ~(16 - 1);
1533 m->stack_offset = offset;
1535 if (sig->call_convention == MONO_CALL_VARARG) {
1536 CallInfo *cinfo = get_call_info (m->method->signature);
1538 m->sig_cookie = cinfo->sig_cookie.offset;
1545 mono_arch_create_vars (MonoCompile *cfg)
1547 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1549 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1550 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1554 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1555 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1559 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1561 int sig_reg = mono_alloc_ireg (cfg);
1563 /* FIXME: Add support for signature tokens to AOT */
1564 cfg->disable_aot = TRUE;
1566 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1567 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1568 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1572 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1575 MonoMethodSignature *sig;
1579 sig = call->signature;
1580 n = sig->param_count + sig->hasthis;
1582 cinfo = get_call_info (sig);
1584 for (i = 0; i < n; ++i) {
1585 ArgInfo *ainfo = cinfo->args + i;
1588 if (i >= sig->hasthis)
1589 t = sig->params [i - sig->hasthis];
1591 t = &mono_defaults.int_class->byval_arg;
1592 t = mini_get_underlying_type (t);
1594 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1595 emit_sig_cookie (cfg, call, cinfo);
1597 in = call->args [i];
1599 if (ainfo->regtype == RegTypeGeneral) {
1600 #ifndef __mono_ppc64__
1601 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1602 MONO_INST_NEW (cfg, ins, OP_MOVE);
1603 ins->dreg = mono_alloc_ireg (cfg);
1604 ins->sreg1 = in->dreg + 1;
1605 MONO_ADD_INS (cfg->cbb, ins);
1606 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1608 MONO_INST_NEW (cfg, ins, OP_MOVE);
1609 ins->dreg = mono_alloc_ireg (cfg);
1610 ins->sreg1 = in->dreg + 2;
1611 MONO_ADD_INS (cfg->cbb, ins);
1612 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1616 MONO_INST_NEW (cfg, ins, OP_MOVE);
1617 ins->dreg = mono_alloc_ireg (cfg);
1618 ins->sreg1 = in->dreg;
1619 MONO_ADD_INS (cfg->cbb, ins);
1621 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1623 } else if (ainfo->regtype == RegTypeStructByAddr) {
1624 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1625 ins->opcode = OP_OUTARG_VT;
1626 ins->sreg1 = in->dreg;
1627 ins->klass = in->klass;
1628 ins->inst_p0 = call;
1629 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1630 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1631 MONO_ADD_INS (cfg->cbb, ins);
1632 } else if (ainfo->regtype == RegTypeStructByVal) {
1633 /* this is further handled in mono_arch_emit_outarg_vt () */
1634 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1635 ins->opcode = OP_OUTARG_VT;
1636 ins->sreg1 = in->dreg;
1637 ins->klass = in->klass;
1638 ins->inst_p0 = call;
1639 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1640 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1641 MONO_ADD_INS (cfg->cbb, ins);
1642 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1643 /* this is further handled in mono_arch_emit_outarg_vt () */
1644 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1645 ins->opcode = OP_OUTARG_VT;
1646 ins->sreg1 = in->dreg;
1647 ins->klass = in->klass;
1648 ins->inst_p0 = call;
1649 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1650 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1651 MONO_ADD_INS (cfg->cbb, ins);
1652 cfg->flags |= MONO_CFG_HAS_FPOUT;
1653 } else if (ainfo->regtype == RegTypeBase) {
1654 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1655 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1656 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1657 if (t->type == MONO_TYPE_R8)
1658 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1660 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1662 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1664 } else if (ainfo->regtype == RegTypeFP) {
1665 if (t->type == MONO_TYPE_VALUETYPE) {
1666 /* this is further handled in mono_arch_emit_outarg_vt () */
1667 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1668 ins->opcode = OP_OUTARG_VT;
1669 ins->sreg1 = in->dreg;
1670 ins->klass = in->klass;
1671 ins->inst_p0 = call;
1672 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1673 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1674 MONO_ADD_INS (cfg->cbb, ins);
1676 cfg->flags |= MONO_CFG_HAS_FPOUT;
1678 int dreg = mono_alloc_freg (cfg);
1680 if (ainfo->size == 4) {
1681 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1683 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1685 ins->sreg1 = in->dreg;
1686 MONO_ADD_INS (cfg->cbb, ins);
1689 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1690 cfg->flags |= MONO_CFG_HAS_FPOUT;
1693 g_assert_not_reached ();
1697 /* Emit the signature cookie in the case that there is no
1698 additional argument */
1699 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1700 emit_sig_cookie (cfg, call, cinfo);
1702 if (cinfo->struct_ret) {
1705 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1706 vtarg->sreg1 = call->vret_var->dreg;
1707 vtarg->dreg = mono_alloc_preg (cfg);
1708 MONO_ADD_INS (cfg->cbb, vtarg);
1710 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1713 call->stack_usage = cinfo->stack_usage;
1714 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1715 cfg->flags |= MONO_CFG_HAS_CALLS;
1723 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1725 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1726 ArgInfo *ainfo = ins->inst_p1;
1727 int ovf_size = ainfo->vtsize;
1728 int doffset = ainfo->offset;
1729 int i, soffset, dreg;
1731 if (ainfo->regtype == RegTypeStructByVal) {
1738 * Darwin pinvokes needs some special handling for 1
1739 * and 2 byte arguments
1741 g_assert (ins->klass);
1742 if (call->signature->pinvoke)
1743 size = mono_class_native_size (ins->klass, NULL);
1744 if (size == 2 || size == 1) {
1745 int tmpr = mono_alloc_ireg (cfg);
1747 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1749 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1750 dreg = mono_alloc_ireg (cfg);
1751 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1752 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1755 for (i = 0; i < ainfo->vtregs; ++i) {
1756 dreg = mono_alloc_ireg (cfg);
1757 #if G_BYTE_ORDER == G_BIG_ENDIAN
1758 int antipadding = 0;
1761 antipadding = sizeof (gpointer) - ainfo->bytes;
1763 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1765 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1767 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1769 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1770 soffset += sizeof (gpointer);
1773 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1774 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1776 for (i = 0; i < ainfo->vtregs; ++i) {
1777 int tmpr = mono_alloc_freg (cfg);
1778 if (ainfo->size == 4)
1779 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1781 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1782 dreg = mono_alloc_freg (cfg);
1783 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1784 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1785 soffset += ainfo->size;
1788 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1789 } else if (ainfo->regtype == RegTypeFP) {
1790 int tmpr = mono_alloc_freg (cfg);
1791 if (ainfo->size == 4)
1792 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1794 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1795 dreg = mono_alloc_freg (cfg);
1796 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1797 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1799 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1803 /* FIXME: alignment? */
1804 if (call->signature->pinvoke) {
1805 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1806 vtcopy->backend.is_pinvoke = 1;
1808 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1811 g_assert (ovf_size > 0);
1813 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1814 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1817 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1819 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1824 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1826 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1829 #ifndef __mono_ppc64__
1830 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1833 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1834 ins->sreg1 = val->dreg + 1;
1835 ins->sreg2 = val->dreg + 2;
1836 MONO_ADD_INS (cfg->cbb, ins);
1840 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1841 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1845 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1848 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1850 mono_arch_is_inst_imm (gint64 imm)
1855 #endif /* DISABLE_JIT */
1858 * Allow tracing to work with this interface (with an optional argument)
1862 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1866 ppc_load_ptr (code, ppc_r3, cfg->method);
1867 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1868 ppc_load_func (code, PPC_CALL_REG, func);
1869 ppc_mtlr (code, PPC_CALL_REG);
1883 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1886 int save_mode = SAVE_NONE;
1888 MonoMethod *method = cfg->method;
1889 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
1890 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1894 offset = code - cfg->native_code;
1895 /* we need about 16 instructions */
1896 if (offset > (cfg->code_size - 16 * 4)) {
1897 cfg->code_size *= 2;
1898 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1899 code = cfg->native_code + offset;
1903 case MONO_TYPE_VOID:
1904 /* special case string .ctor icall */
1905 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1906 save_mode = SAVE_ONE;
1908 save_mode = SAVE_NONE;
1910 #ifndef __mono_ppc64__
1913 save_mode = SAVE_TWO;
1918 save_mode = SAVE_FP;
1920 case MONO_TYPE_VALUETYPE:
1921 save_mode = SAVE_STRUCT;
1924 save_mode = SAVE_ONE;
1928 switch (save_mode) {
1930 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1931 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1932 if (enable_arguments) {
1933 ppc_mr (code, ppc_r5, ppc_r4);
1934 ppc_mr (code, ppc_r4, ppc_r3);
1938 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1939 if (enable_arguments) {
1940 ppc_mr (code, ppc_r4, ppc_r3);
1944 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1945 if (enable_arguments) {
1946 /* FIXME: what reg? */
1947 ppc_fmr (code, ppc_f3, ppc_f1);
1948 /* FIXME: use 8 byte load on PPC64 */
1949 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1950 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1954 if (enable_arguments) {
1955 /* FIXME: get the actual address */
1956 ppc_mr (code, ppc_r4, ppc_r3);
1957 // FIXME: Support the new v2 ABI!
1965 ppc_load_ptr (code, ppc_r3, cfg->method);
1966 ppc_load_func (code, PPC_CALL_REG, func);
1967 ppc_mtlr (code, PPC_CALL_REG);
1970 switch (save_mode) {
1972 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1973 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1976 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1979 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1989 * Conditional branches have a small offset, so if it is likely overflowed,
1990 * we do a branch to the end of the method (uncond branches have much larger
1991 * offsets) where we perform the conditional and jump back unconditionally.
1992 * It's slightly slower, since we add two uncond branches, but it's very simple
1993 * with the current patch implementation and such large methods are likely not
1994 * going to be perf critical anyway.
1999 const char *exception;
2006 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
2007 if (0 && ins->inst_true_bb->native_offset) { \
2008 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
2010 int br_disp = ins->inst_true_bb->max_offset - offset; \
2011 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2012 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2013 ovfj->data.bb = ins->inst_true_bb; \
2014 ovfj->ip_offset = 0; \
2015 ovfj->b0_cond = (b0); \
2016 ovfj->b1_cond = (b1); \
2017 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
2020 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2021 ppc_bc (code, (b0), (b1), 0); \
2025 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
2027 /* emit an exception if condition is fail
2029 * We assign the extra code used to throw the implicit exceptions
2030 * to cfg->bb_exit as far as the big branch handling is concerned
2032 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2034 int br_disp = cfg->bb_exit->max_offset - offset; \
2035 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2036 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2037 ovfj->data.exception = (exc_name); \
2038 ovfj->ip_offset = code - cfg->native_code; \
2039 ovfj->b0_cond = (b0); \
2040 ovfj->b1_cond = (b1); \
2041 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2043 cfg->bb_exit->max_offset += 24; \
2045 mono_add_patch_info (cfg, code - cfg->native_code, \
2046 MONO_PATCH_INFO_EXC, exc_name); \
2047 ppc_bcl (code, (b0), (b1), 0); \
2051 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2054 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2059 normalize_opcode (int opcode)
2062 #ifndef __mono_ilp32__
2063 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2064 return OP_LOAD_MEMBASE;
2065 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2066 return OP_LOAD_MEMINDEX;
2067 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2068 return OP_STORE_MEMBASE_REG;
2069 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2070 return OP_STORE_MEMBASE_IMM;
2071 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2072 return OP_STORE_MEMINDEX;
2074 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2076 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2077 return OP_SHR_UN_IMM;
2084 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2086 MonoInst *ins, *n, *last_ins = NULL;
2088 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2089 switch (normalize_opcode (ins->opcode)) {
2091 /* remove unnecessary multiplication with 1 */
2092 if (ins->inst_imm == 1) {
2093 if (ins->dreg != ins->sreg1) {
2094 ins->opcode = OP_MOVE;
2096 MONO_DELETE_INS (bb, ins);
2100 int power2 = mono_is_power_of_two (ins->inst_imm);
2102 ins->opcode = OP_SHL_IMM;
2103 ins->inst_imm = power2;
2107 case OP_LOAD_MEMBASE:
2109 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2110 * OP_LOAD_MEMBASE offset(basereg), reg
2112 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2113 ins->inst_basereg == last_ins->inst_destbasereg &&
2114 ins->inst_offset == last_ins->inst_offset) {
2115 if (ins->dreg == last_ins->sreg1) {
2116 MONO_DELETE_INS (bb, ins);
2119 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2120 ins->opcode = OP_MOVE;
2121 ins->sreg1 = last_ins->sreg1;
2125 * Note: reg1 must be different from the basereg in the second load
2126 * OP_LOAD_MEMBASE offset(basereg), reg1
2127 * OP_LOAD_MEMBASE offset(basereg), reg2
2129 * OP_LOAD_MEMBASE offset(basereg), reg1
2130 * OP_MOVE reg1, reg2
2132 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2133 ins->inst_basereg != last_ins->dreg &&
2134 ins->inst_basereg == last_ins->inst_basereg &&
2135 ins->inst_offset == last_ins->inst_offset) {
2137 if (ins->dreg == last_ins->dreg) {
2138 MONO_DELETE_INS (bb, ins);
2141 ins->opcode = OP_MOVE;
2142 ins->sreg1 = last_ins->dreg;
2145 //g_assert_not_reached ();
2149 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2150 * OP_LOAD_MEMBASE offset(basereg), reg
2152 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2153 * OP_ICONST reg, imm
2155 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2156 ins->inst_basereg == last_ins->inst_destbasereg &&
2157 ins->inst_offset == last_ins->inst_offset) {
2158 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2159 ins->opcode = OP_ICONST;
2160 ins->inst_c0 = last_ins->inst_imm;
2161 g_assert_not_reached (); // check this rule
2165 case OP_LOADU1_MEMBASE:
2166 case OP_LOADI1_MEMBASE:
2167 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2168 ins->inst_basereg == last_ins->inst_destbasereg &&
2169 ins->inst_offset == last_ins->inst_offset) {
2170 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2171 ins->sreg1 = last_ins->sreg1;
2174 case OP_LOADU2_MEMBASE:
2175 case OP_LOADI2_MEMBASE:
2176 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2177 ins->inst_basereg == last_ins->inst_destbasereg &&
2178 ins->inst_offset == last_ins->inst_offset) {
2179 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2180 ins->sreg1 = last_ins->sreg1;
2183 #ifdef __mono_ppc64__
2184 case OP_LOADU4_MEMBASE:
2185 case OP_LOADI4_MEMBASE:
2186 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2187 ins->inst_basereg == last_ins->inst_destbasereg &&
2188 ins->inst_offset == last_ins->inst_offset) {
2189 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2190 ins->sreg1 = last_ins->sreg1;
2195 ins->opcode = OP_MOVE;
2199 if (ins->dreg == ins->sreg1) {
2200 MONO_DELETE_INS (bb, ins);
2204 * OP_MOVE sreg, dreg
2205 * OP_MOVE dreg, sreg
2207 if (last_ins && last_ins->opcode == OP_MOVE &&
2208 ins->sreg1 == last_ins->dreg &&
2209 ins->dreg == last_ins->sreg1) {
2210 MONO_DELETE_INS (bb, ins);
2218 bb->last_ins = last_ins;
2222 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2224 switch (ins->opcode) {
2225 case OP_ICONV_TO_R_UN: {
2226 // This value is OK as-is for both big and little endian because of how it is stored
2227 static const guint64 adjust_val = 0x4330000000000000ULL;
2228 int msw_reg = mono_alloc_ireg (cfg);
2229 int adj_reg = mono_alloc_freg (cfg);
2230 int tmp_reg = mono_alloc_freg (cfg);
2231 int basereg = ppc_sp;
2233 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2234 if (!ppc_is_imm16 (offset + 4)) {
2235 basereg = mono_alloc_ireg (cfg);
2236 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2238 #if G_BYTE_ORDER == G_BIG_ENDIAN
2239 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2240 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2242 // For little endian the words are reversed
2243 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2244 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2246 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2247 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2248 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2249 ins->opcode = OP_NOP;
2252 #ifndef __mono_ppc64__
2253 case OP_ICONV_TO_R4:
2254 case OP_ICONV_TO_R8: {
2255 /* If we have a PPC_FEATURE_64 machine we can avoid
2256 this and use the fcfid instruction. Otherwise
2257 on an old 32-bit chip and we have to do this the
2259 if (!(cpu_hw_caps & PPC_ISA_64)) {
2260 /* FIXME: change precision for CEE_CONV_R4 */
2261 static const guint64 adjust_val = 0x4330000080000000ULL;
2262 int msw_reg = mono_alloc_ireg (cfg);
2263 int xored = mono_alloc_ireg (cfg);
2264 int adj_reg = mono_alloc_freg (cfg);
2265 int tmp_reg = mono_alloc_freg (cfg);
2266 int basereg = ppc_sp;
2268 if (!ppc_is_imm16 (offset + 4)) {
2269 basereg = mono_alloc_ireg (cfg);
2270 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2272 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2273 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2274 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2275 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2276 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2277 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2278 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2279 if (ins->opcode == OP_ICONV_TO_R4)
2280 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2281 ins->opcode = OP_NOP;
2287 int msw_reg = mono_alloc_ireg (cfg);
2288 int basereg = ppc_sp;
2290 if (!ppc_is_imm16 (offset + 4)) {
2291 basereg = mono_alloc_ireg (cfg);
2292 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2294 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2295 #if G_BYTE_ORDER == G_BIG_ENDIAN
2296 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2298 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2300 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2301 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2302 ins->opcode = OP_NOP;
2305 #ifdef __mono_ppc64__
2307 case OP_IADD_OVF_UN:
2309 int shifted1_reg = mono_alloc_ireg (cfg);
2310 int shifted2_reg = mono_alloc_ireg (cfg);
2311 int result_shifted_reg = mono_alloc_ireg (cfg);
2313 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2314 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2315 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2316 if (ins->opcode == OP_IADD_OVF_UN)
2317 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2319 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2320 ins->opcode = OP_NOP;
2327 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2329 switch (ins->opcode) {
2331 /* ADC sets the condition code */
2332 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2333 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2336 case OP_LADD_OVF_UN:
2337 /* ADC sets the condition code */
2338 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2339 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2343 /* SBB sets the condition code */
2344 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2345 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2348 case OP_LSUB_OVF_UN:
2349 /* SBB sets the condition code */
2350 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2355 /* From gcc generated code */
2356 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2357 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2366 * the branch_b0_table should maintain the order of these
2380 branch_b0_table [] = {
2395 branch_b1_table [] = {
2409 #define NEW_INS(cfg,dest,op) do { \
2410 MONO_INST_NEW((cfg), (dest), (op)); \
2411 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2415 map_to_reg_reg_op (int op)
2424 case OP_COMPARE_IMM:
2426 case OP_ICOMPARE_IMM:
2428 case OP_LCOMPARE_IMM:
2444 case OP_LOAD_MEMBASE:
2445 return OP_LOAD_MEMINDEX;
2446 case OP_LOADI4_MEMBASE:
2447 return OP_LOADI4_MEMINDEX;
2448 case OP_LOADU4_MEMBASE:
2449 return OP_LOADU4_MEMINDEX;
2450 case OP_LOADI8_MEMBASE:
2451 return OP_LOADI8_MEMINDEX;
2452 case OP_LOADU1_MEMBASE:
2453 return OP_LOADU1_MEMINDEX;
2454 case OP_LOADI2_MEMBASE:
2455 return OP_LOADI2_MEMINDEX;
2456 case OP_LOADU2_MEMBASE:
2457 return OP_LOADU2_MEMINDEX;
2458 case OP_LOADI1_MEMBASE:
2459 return OP_LOADI1_MEMINDEX;
2460 case OP_LOADR4_MEMBASE:
2461 return OP_LOADR4_MEMINDEX;
2462 case OP_LOADR8_MEMBASE:
2463 return OP_LOADR8_MEMINDEX;
2464 case OP_STOREI1_MEMBASE_REG:
2465 return OP_STOREI1_MEMINDEX;
2466 case OP_STOREI2_MEMBASE_REG:
2467 return OP_STOREI2_MEMINDEX;
2468 case OP_STOREI4_MEMBASE_REG:
2469 return OP_STOREI4_MEMINDEX;
2470 case OP_STOREI8_MEMBASE_REG:
2471 return OP_STOREI8_MEMINDEX;
2472 case OP_STORE_MEMBASE_REG:
2473 return OP_STORE_MEMINDEX;
2474 case OP_STORER4_MEMBASE_REG:
2475 return OP_STORER4_MEMINDEX;
2476 case OP_STORER8_MEMBASE_REG:
2477 return OP_STORER8_MEMINDEX;
2478 case OP_STORE_MEMBASE_IMM:
2479 return OP_STORE_MEMBASE_REG;
2480 case OP_STOREI1_MEMBASE_IMM:
2481 return OP_STOREI1_MEMBASE_REG;
2482 case OP_STOREI2_MEMBASE_IMM:
2483 return OP_STOREI2_MEMBASE_REG;
2484 case OP_STOREI4_MEMBASE_IMM:
2485 return OP_STOREI4_MEMBASE_REG;
2486 case OP_STOREI8_MEMBASE_IMM:
2487 return OP_STOREI8_MEMBASE_REG;
2489 return mono_op_imm_to_op (op);
2492 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2494 #define compare_opcode_is_unsigned(opcode) \
2495 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2496 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2497 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2498 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2499 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2500 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2501 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2502 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2505 * Remove from the instruction list the instructions that can't be
2506 * represented with very simple instructions with no register
2510 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2512 MonoInst *ins, *next, *temp, *last_ins = NULL;
2515 MONO_BB_FOR_EACH_INS (bb, ins) {
2517 switch (ins->opcode) {
2518 case OP_IDIV_UN_IMM:
2521 case OP_IREM_UN_IMM:
2522 CASE_PPC64 (OP_LREM_IMM) {
2523 NEW_INS (cfg, temp, OP_ICONST);
2524 temp->inst_c0 = ins->inst_imm;
2525 temp->dreg = mono_alloc_ireg (cfg);
2526 ins->sreg2 = temp->dreg;
2527 if (ins->opcode == OP_IDIV_IMM)
2528 ins->opcode = OP_IDIV;
2529 else if (ins->opcode == OP_IREM_IMM)
2530 ins->opcode = OP_IREM;
2531 else if (ins->opcode == OP_IDIV_UN_IMM)
2532 ins->opcode = OP_IDIV_UN;
2533 else if (ins->opcode == OP_IREM_UN_IMM)
2534 ins->opcode = OP_IREM_UN;
2535 else if (ins->opcode == OP_LREM_IMM)
2536 ins->opcode = OP_LREM;
2538 /* handle rem separately */
2543 CASE_PPC64 (OP_LREM)
2544 CASE_PPC64 (OP_LREM_UN) {
2546 /* we change a rem dest, src1, src2 to
2547 * div temp1, src1, src2
2548 * mul temp2, temp1, src2
2549 * sub dest, src1, temp2
2551 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2552 NEW_INS (cfg, mul, OP_IMUL);
2553 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2554 ins->opcode = OP_ISUB;
2556 NEW_INS (cfg, mul, OP_LMUL);
2557 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2558 ins->opcode = OP_LSUB;
2560 temp->sreg1 = ins->sreg1;
2561 temp->sreg2 = ins->sreg2;
2562 temp->dreg = mono_alloc_ireg (cfg);
2563 mul->sreg1 = temp->dreg;
2564 mul->sreg2 = ins->sreg2;
2565 mul->dreg = mono_alloc_ireg (cfg);
2566 ins->sreg2 = mul->dreg;
2570 CASE_PPC64 (OP_LADD_IMM)
2573 if (!ppc_is_imm16 (ins->inst_imm)) {
2574 NEW_INS (cfg, temp, OP_ICONST);
2575 temp->inst_c0 = ins->inst_imm;
2576 temp->dreg = mono_alloc_ireg (cfg);
2577 ins->sreg2 = temp->dreg;
2578 ins->opcode = map_to_reg_reg_op (ins->opcode);
2582 CASE_PPC64 (OP_LSUB_IMM)
2584 if (!ppc_is_imm16 (-ins->inst_imm)) {
2585 NEW_INS (cfg, temp, OP_ICONST);
2586 temp->inst_c0 = ins->inst_imm;
2587 temp->dreg = mono_alloc_ireg (cfg);
2588 ins->sreg2 = temp->dreg;
2589 ins->opcode = map_to_reg_reg_op (ins->opcode);
2601 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2602 #ifdef __mono_ppc64__
2603 if (ins->inst_imm & 0xffffffff00000000ULL)
2607 NEW_INS (cfg, temp, OP_ICONST);
2608 temp->inst_c0 = ins->inst_imm;
2609 temp->dreg = mono_alloc_ireg (cfg);
2610 ins->sreg2 = temp->dreg;
2611 ins->opcode = map_to_reg_reg_op (ins->opcode);
2620 NEW_INS (cfg, temp, OP_ICONST);
2621 temp->inst_c0 = ins->inst_imm;
2622 temp->dreg = mono_alloc_ireg (cfg);
2623 ins->sreg2 = temp->dreg;
2624 ins->opcode = map_to_reg_reg_op (ins->opcode);
2626 case OP_COMPARE_IMM:
2627 case OP_ICOMPARE_IMM:
2628 CASE_PPC64 (OP_LCOMPARE_IMM)
2630 /* Branch opts can eliminate the branch */
2631 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2632 ins->opcode = OP_NOP;
2636 if (compare_opcode_is_unsigned (next->opcode)) {
2637 if (!ppc_is_uimm16 (ins->inst_imm)) {
2638 NEW_INS (cfg, temp, OP_ICONST);
2639 temp->inst_c0 = ins->inst_imm;
2640 temp->dreg = mono_alloc_ireg (cfg);
2641 ins->sreg2 = temp->dreg;
2642 ins->opcode = map_to_reg_reg_op (ins->opcode);
2645 if (!ppc_is_imm16 (ins->inst_imm)) {
2646 NEW_INS (cfg, temp, OP_ICONST);
2647 temp->inst_c0 = ins->inst_imm;
2648 temp->dreg = mono_alloc_ireg (cfg);
2649 ins->sreg2 = temp->dreg;
2650 ins->opcode = map_to_reg_reg_op (ins->opcode);
2656 if (ins->inst_imm == 1) {
2657 ins->opcode = OP_MOVE;
2660 if (ins->inst_imm == 0) {
2661 ins->opcode = OP_ICONST;
2665 imm = mono_is_power_of_two (ins->inst_imm);
2667 ins->opcode = OP_SHL_IMM;
2668 ins->inst_imm = imm;
2671 if (!ppc_is_imm16 (ins->inst_imm)) {
2672 NEW_INS (cfg, temp, OP_ICONST);
2673 temp->inst_c0 = ins->inst_imm;
2674 temp->dreg = mono_alloc_ireg (cfg);
2675 ins->sreg2 = temp->dreg;
2676 ins->opcode = map_to_reg_reg_op (ins->opcode);
2679 case OP_LOCALLOC_IMM:
2680 NEW_INS (cfg, temp, OP_ICONST);
2681 temp->inst_c0 = ins->inst_imm;
2682 temp->dreg = mono_alloc_ireg (cfg);
2683 ins->sreg1 = temp->dreg;
2684 ins->opcode = OP_LOCALLOC;
2686 case OP_LOAD_MEMBASE:
2687 case OP_LOADI4_MEMBASE:
2688 CASE_PPC64 (OP_LOADI8_MEMBASE)
2689 case OP_LOADU4_MEMBASE:
2690 case OP_LOADI2_MEMBASE:
2691 case OP_LOADU2_MEMBASE:
2692 case OP_LOADI1_MEMBASE:
2693 case OP_LOADU1_MEMBASE:
2694 case OP_LOADR4_MEMBASE:
2695 case OP_LOADR8_MEMBASE:
2696 case OP_STORE_MEMBASE_REG:
2697 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2698 case OP_STOREI4_MEMBASE_REG:
2699 case OP_STOREI2_MEMBASE_REG:
2700 case OP_STOREI1_MEMBASE_REG:
2701 case OP_STORER4_MEMBASE_REG:
2702 case OP_STORER8_MEMBASE_REG:
2703 /* we can do two things: load the immed in a register
2704 * and use an indexed load, or see if the immed can be
2705 * represented as an ad_imm + a load with a smaller offset
2706 * that fits. We just do the first for now, optimize later.
2708 if (ppc_is_imm16 (ins->inst_offset))
2710 NEW_INS (cfg, temp, OP_ICONST);
2711 temp->inst_c0 = ins->inst_offset;
2712 temp->dreg = mono_alloc_ireg (cfg);
2713 ins->sreg2 = temp->dreg;
2714 ins->opcode = map_to_reg_reg_op (ins->opcode);
2716 case OP_STORE_MEMBASE_IMM:
2717 case OP_STOREI1_MEMBASE_IMM:
2718 case OP_STOREI2_MEMBASE_IMM:
2719 case OP_STOREI4_MEMBASE_IMM:
2720 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2721 NEW_INS (cfg, temp, OP_ICONST);
2722 temp->inst_c0 = ins->inst_imm;
2723 temp->dreg = mono_alloc_ireg (cfg);
2724 ins->sreg1 = temp->dreg;
2725 ins->opcode = map_to_reg_reg_op (ins->opcode);
2727 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2730 if (cfg->compile_aot) {
2731 /* Keep these in the aot case */
2734 NEW_INS (cfg, temp, OP_ICONST);
2735 temp->inst_c0 = (gulong)ins->inst_p0;
2736 temp->dreg = mono_alloc_ireg (cfg);
2737 ins->inst_basereg = temp->dreg;
2738 ins->inst_offset = 0;
2739 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2741 /* make it handle the possibly big ins->inst_offset
2742 * later optimize to use lis + load_membase
2748 bb->last_ins = last_ins;
2749 bb->max_vreg = cfg->next_vreg;
2753 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2755 long offset = cfg->arch.fp_conv_var_offset;
2757 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2758 #ifdef __mono_ppc64__
2760 ppc_fctidz (code, ppc_f0, sreg);
2765 ppc_fctiwz (code, ppc_f0, sreg);
2768 if (ppc_is_imm16 (offset + sub_offset)) {
2769 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2771 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2773 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2775 ppc_load (code, dreg, offset);
2776 ppc_add (code, dreg, dreg, cfg->frame_reg);
2777 ppc_stfd (code, ppc_f0, 0, dreg);
2779 ppc_ldr (code, dreg, sub_offset, dreg);
2781 ppc_lwz (code, dreg, sub_offset, dreg);
2785 ppc_andid (code, dreg, dreg, 0xff);
2787 ppc_andid (code, dreg, dreg, 0xffff);
2788 #ifdef __mono_ppc64__
2790 ppc_clrldi (code, dreg, dreg, 32);
2794 ppc_extsb (code, dreg, dreg);
2796 ppc_extsh (code, dreg, dreg);
2797 #ifdef __mono_ppc64__
2799 ppc_extsw (code, dreg, dreg);
2807 const guchar *target;
2812 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2815 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2816 #ifdef __mono_ppc64__
2817 g_assert_not_reached ();
2819 PatchData *pdata = (PatchData*)user_data;
2820 guchar *code = data;
2821 guint32 *thunks = data;
2822 guint32 *endthunks = (guint32*)(code + bsize);
2826 int difflow, diffhigh;
2828 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2829 difflow = (char*)pdata->code - (char*)thunks;
2830 diffhigh = (char*)pdata->code - (char*)endthunks;
2831 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2834 templ = (guchar*)load;
2835 ppc_load_sequence (templ, ppc_r0, pdata->target);
2837 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2838 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2839 while (thunks < endthunks) {
2840 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2841 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2842 ppc_patch (pdata->code, (guchar*)thunks);
2845 static int num_thunks = 0;
2847 if ((num_thunks % 20) == 0)
2848 g_print ("num_thunks lookup: %d\n", num_thunks);
2851 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2852 /* found a free slot instead: emit thunk */
2853 code = (guchar*)thunks;
2854 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2855 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2856 ppc_mtctr (code, ppc_r0);
2857 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2858 mono_arch_flush_icache ((guchar*)thunks, 16);
2860 ppc_patch (pdata->code, (guchar*)thunks);
2863 static int num_thunks = 0;
2865 if ((num_thunks % 20) == 0)
2866 g_print ("num_thunks: %d\n", num_thunks);
2870 /* skip 16 bytes, the size of the thunk */
2874 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2881 handle_thunk (int absolute, guchar *code, const guchar *target) {
2882 MonoDomain *domain = mono_domain_get ();
2886 pdata.target = target;
2887 pdata.absolute = absolute;
2890 mono_domain_lock (domain);
2891 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2894 /* this uses the first available slot */
2896 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2898 mono_domain_unlock (domain);
2900 if (pdata.found != 1)
2901 g_print ("thunk failed for %p from %p\n", target, code);
2902 g_assert (pdata.found == 1);
2906 patch_ins (guint8 *code, guint32 ins)
2908 *(guint32*)code = ins;
2909 mono_arch_flush_icache (code, 4);
2913 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2915 guint32 ins = *(guint32*)code;
2916 guint32 prim = ins >> 26;
2919 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2921 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2922 gint diff = target - code;
2925 if (diff <= 33554431){
2926 ins = (18 << 26) | (diff) | (ins & 1);
2927 patch_ins (code, ins);
2931 /* diff between 0 and -33554432 */
2932 if (diff >= -33554432){
2933 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2934 patch_ins (code, ins);
2939 if ((glong)target >= 0){
2940 if ((glong)target <= 33554431){
2941 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2942 patch_ins (code, ins);
2946 if ((glong)target >= -33554432){
2947 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2948 patch_ins (code, ins);
2953 handle_thunk (TRUE, code, target);
2956 g_assert_not_reached ();
2964 guint32 li = (gulong)target;
2965 ins = (ins & 0xffff0000) | (ins & 3);
2966 ovf = li & 0xffff0000;
2967 if (ovf != 0 && ovf != 0xffff0000)
2968 g_assert_not_reached ();
2971 // FIXME: assert the top bits of li are 0
2973 gint diff = target - code;
2974 ins = (ins & 0xffff0000) | (ins & 3);
2975 ovf = diff & 0xffff0000;
2976 if (ovf != 0 && ovf != 0xffff0000)
2977 g_assert_not_reached ();
2981 patch_ins (code, ins);
2985 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2986 #ifdef __mono_ppc64__
2987 guint32 *seq = (guint32*)code;
2988 guint32 *branch_ins;
2990 /* the trampoline code will try to patch the blrl, blr, bcctr */
2991 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2993 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2998 if (ppc_is_load_op (seq [5])
2999 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3000 /* With function descs we need to do more careful
3002 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3005 branch_ins = seq + 8;
3007 branch_ins = seq + 6;
3010 seq = (guint32*)code;
3011 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3012 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3014 if (ppc_is_load_op (seq [5])) {
3015 g_assert (ppc_is_load_op (seq [6]));
3018 guint8 *buf = (guint8*)&seq [5];
3019 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3024 target = mono_get_addr_from_ftnptr ((gpointer)target);
3027 /* FIXME: make this thread safe */
3028 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3029 /* FIXME: we're assuming we're using r12 here */
3030 ppc_load_ptr_sequence (code, ppc_r12, target);
3032 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3034 mono_arch_flush_icache ((guint8*)seq, 28);
3037 /* the trampoline code will try to patch the blrl, blr, bcctr */
3038 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3041 /* this is the lis/ori/mtlr/blrl sequence */
3042 seq = (guint32*)code;
3043 g_assert ((seq [0] >> 26) == 15);
3044 g_assert ((seq [1] >> 26) == 24);
3045 g_assert ((seq [2] >> 26) == 31);
3046 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3047 /* FIXME: make this thread safe */
3048 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3049 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3050 mono_arch_flush_icache (code - 8, 8);
3053 g_assert_not_reached ();
3055 // g_print ("patched with 0x%08x\n", ins);
3059 ppc_patch (guchar *code, const guchar *target)
3061 ppc_patch_full (code, target, FALSE);
3065 mono_ppc_patch (guchar *code, const guchar *target)
3067 ppc_patch (code, target);
3071 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3073 switch (ins->opcode) {
3076 case OP_FCALL_MEMBASE:
3077 if (ins->dreg != ppc_f1)
3078 ppc_fmr (code, ins->dreg, ppc_f1);
3086 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3088 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3092 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3094 long size = cfg->param_area;
3096 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3097 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3102 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3103 if (ppc_is_imm16 (-size)) {
3104 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3106 ppc_load (code, ppc_r12, -size);
3107 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3114 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3116 long size = cfg->param_area;
3118 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3119 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3124 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3125 if (ppc_is_imm16 (size)) {
3126 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3128 ppc_load (code, ppc_r12, size);
3129 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3135 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3139 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3141 MonoInst *ins, *next;
3144 guint8 *code = cfg->native_code + cfg->code_len;
3145 MonoInst *last_ins = NULL;
3146 guint last_offset = 0;
3150 /* we don't align basic blocks of loops on ppc */
3152 if (cfg->verbose_level > 2)
3153 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3155 cpos = bb->max_offset;
3157 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3158 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3159 //g_assert (!mono_compile_aot);
3162 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3163 /* this is not thread save, but good enough */
3164 /* fixme: howto handle overflows? */
3165 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3168 MONO_BB_FOR_EACH_INS (bb, ins) {
3169 offset = code - cfg->native_code;
3171 max_len = ins_native_length (cfg, ins);
3173 if (offset > (cfg->code_size - max_len - 16)) {
3174 cfg->code_size *= 2;
3175 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3176 code = cfg->native_code + offset;
3178 // if (ins->cil_code)
3179 // g_print ("cil code\n");
3180 mono_debug_record_line_number (cfg, ins, offset);
3182 switch (normalize_opcode (ins->opcode)) {
3183 case OP_RELAXED_NOP:
3186 case OP_DUMMY_STORE:
3187 case OP_NOT_REACHED:
3190 case OP_IL_SEQ_POINT:
3191 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3193 case OP_SEQ_POINT: {
3196 if (cfg->compile_aot)
3200 * Read from the single stepping trigger page. This will cause a
3201 * SIGSEGV when single stepping is enabled.
3202 * We do this _before_ the breakpoint, so single stepping after
3203 * a breakpoint is hit will step to the next IL offset.
3205 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3206 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3207 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3210 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3213 * A placeholder for a possible breakpoint inserted by
3214 * mono_arch_set_breakpoint ().
3216 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3221 emit_tls_access (code, ins->dreg, ins->inst_offset);
3224 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3225 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3226 ppc_mr (code, ppc_r4, ppc_r0);
3229 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3230 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3231 ppc_mr (code, ppc_r4, ppc_r0);
3233 case OP_MEMORY_BARRIER:
3236 case OP_STOREI1_MEMBASE_REG:
3237 if (ppc_is_imm16 (ins->inst_offset)) {
3238 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3240 if (ppc_is_imm32 (ins->inst_offset)) {
3241 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3242 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3244 ppc_load (code, ppc_r0, ins->inst_offset);
3245 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3249 case OP_STOREI2_MEMBASE_REG:
3250 if (ppc_is_imm16 (ins->inst_offset)) {
3251 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3253 if (ppc_is_imm32 (ins->inst_offset)) {
3254 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3255 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3257 ppc_load (code, ppc_r0, ins->inst_offset);
3258 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3262 case OP_STORE_MEMBASE_REG:
3263 if (ppc_is_imm16 (ins->inst_offset)) {
3264 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3266 if (ppc_is_imm32 (ins->inst_offset)) {
3267 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3268 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3270 ppc_load (code, ppc_r0, ins->inst_offset);
3271 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3275 #ifdef __mono_ilp32__
3276 case OP_STOREI8_MEMBASE_REG:
3277 if (ppc_is_imm16 (ins->inst_offset)) {
3278 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3280 ppc_load (code, ppc_r0, ins->inst_offset);
3281 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3285 case OP_STOREI1_MEMINDEX:
3286 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3288 case OP_STOREI2_MEMINDEX:
3289 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3291 case OP_STORE_MEMINDEX:
3292 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3295 g_assert_not_reached ();
3297 case OP_LOAD_MEMBASE:
3298 if (ppc_is_imm16 (ins->inst_offset)) {
3299 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3301 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3302 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3303 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3305 ppc_load (code, ppc_r0, ins->inst_offset);
3306 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3310 case OP_LOADI4_MEMBASE:
3311 #ifdef __mono_ppc64__
3312 if (ppc_is_imm16 (ins->inst_offset)) {
3313 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3315 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3316 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3317 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3319 ppc_load (code, ppc_r0, ins->inst_offset);
3320 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3325 case OP_LOADU4_MEMBASE:
3326 if (ppc_is_imm16 (ins->inst_offset)) {
3327 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3329 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3330 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3331 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3333 ppc_load (code, ppc_r0, ins->inst_offset);
3334 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3338 case OP_LOADI1_MEMBASE:
3339 case OP_LOADU1_MEMBASE:
3340 if (ppc_is_imm16 (ins->inst_offset)) {
3341 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3343 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3344 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3345 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3347 ppc_load (code, ppc_r0, ins->inst_offset);
3348 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3351 if (ins->opcode == OP_LOADI1_MEMBASE)
3352 ppc_extsb (code, ins->dreg, ins->dreg);
3354 case OP_LOADU2_MEMBASE:
3355 if (ppc_is_imm16 (ins->inst_offset)) {
3356 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3358 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3359 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3360 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3362 ppc_load (code, ppc_r0, ins->inst_offset);
3363 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3367 case OP_LOADI2_MEMBASE:
3368 if (ppc_is_imm16 (ins->inst_offset)) {
3369 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3371 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3372 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3373 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3375 ppc_load (code, ppc_r0, ins->inst_offset);
3376 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3380 #ifdef __mono_ilp32__
3381 case OP_LOADI8_MEMBASE:
3382 if (ppc_is_imm16 (ins->inst_offset)) {
3383 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3385 ppc_load (code, ppc_r0, ins->inst_offset);
3386 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3390 case OP_LOAD_MEMINDEX:
3391 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3393 case OP_LOADI4_MEMINDEX:
3394 #ifdef __mono_ppc64__
3395 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3398 case OP_LOADU4_MEMINDEX:
3399 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3401 case OP_LOADU2_MEMINDEX:
3402 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3404 case OP_LOADI2_MEMINDEX:
3405 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3407 case OP_LOADU1_MEMINDEX:
3408 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3410 case OP_LOADI1_MEMINDEX:
3411 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3412 ppc_extsb (code, ins->dreg, ins->dreg);
3414 case OP_ICONV_TO_I1:
3415 CASE_PPC64 (OP_LCONV_TO_I1)
3416 ppc_extsb (code, ins->dreg, ins->sreg1);
3418 case OP_ICONV_TO_I2:
3419 CASE_PPC64 (OP_LCONV_TO_I2)
3420 ppc_extsh (code, ins->dreg, ins->sreg1);
3422 case OP_ICONV_TO_U1:
3423 CASE_PPC64 (OP_LCONV_TO_U1)
3424 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3426 case OP_ICONV_TO_U2:
3427 CASE_PPC64 (OP_LCONV_TO_U2)
3428 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3432 CASE_PPC64 (OP_LCOMPARE)
3433 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3435 if (next && compare_opcode_is_unsigned (next->opcode))
3436 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3438 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3440 case OP_COMPARE_IMM:
3441 case OP_ICOMPARE_IMM:
3442 CASE_PPC64 (OP_LCOMPARE_IMM)
3443 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3445 if (next && compare_opcode_is_unsigned (next->opcode)) {
3446 if (ppc_is_uimm16 (ins->inst_imm)) {
3447 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3449 g_assert_not_reached ();
3452 if (ppc_is_imm16 (ins->inst_imm)) {
3453 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3455 g_assert_not_reached ();
3461 * gdb does not like encountering a trap in the debugged code. So
3462 * instead of emitting a trap, we emit a call a C function and place a
3466 ppc_mr (code, ppc_r3, ins->sreg1);
3467 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3468 (gpointer)"mono_break");
3469 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3470 ppc_load_func (code, PPC_CALL_REG, 0);
3471 ppc_mtlr (code, PPC_CALL_REG);
3479 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3482 CASE_PPC64 (OP_LADD)
3483 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3487 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3490 if (ppc_is_imm16 (ins->inst_imm)) {
3491 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3493 g_assert_not_reached ();
3498 CASE_PPC64 (OP_LADD_IMM)
3499 if (ppc_is_imm16 (ins->inst_imm)) {
3500 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3502 g_assert_not_reached ();
3506 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3508 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3509 ppc_mfspr (code, ppc_r0, ppc_xer);
3510 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3511 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3513 case OP_IADD_OVF_UN:
3514 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3516 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3517 ppc_mfspr (code, ppc_r0, ppc_xer);
3518 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3519 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3522 CASE_PPC64 (OP_LSUB_OVF)
3523 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3525 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3526 ppc_mfspr (code, ppc_r0, ppc_xer);
3527 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3528 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3530 case OP_ISUB_OVF_UN:
3531 CASE_PPC64 (OP_LSUB_OVF_UN)
3532 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3534 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3535 ppc_mfspr (code, ppc_r0, ppc_xer);
3536 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3537 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3539 case OP_ADD_OVF_CARRY:
3540 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3542 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3543 ppc_mfspr (code, ppc_r0, ppc_xer);
3544 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3545 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3547 case OP_ADD_OVF_UN_CARRY:
3548 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3550 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3551 ppc_mfspr (code, ppc_r0, ppc_xer);
3552 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3553 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3555 case OP_SUB_OVF_CARRY:
3556 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3558 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3559 ppc_mfspr (code, ppc_r0, ppc_xer);
3560 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3561 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3563 case OP_SUB_OVF_UN_CARRY:
3564 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3566 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3567 ppc_mfspr (code, ppc_r0, ppc_xer);
3568 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3569 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3573 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3576 CASE_PPC64 (OP_LSUB)
3577 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3581 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3585 CASE_PPC64 (OP_LSUB_IMM)
3586 // we add the negated value
3587 if (ppc_is_imm16 (-ins->inst_imm))
3588 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3590 g_assert_not_reached ();
3594 g_assert (ppc_is_imm16 (ins->inst_imm));
3595 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3598 ppc_subfze (code, ins->dreg, ins->sreg1);
3601 CASE_PPC64 (OP_LAND)
3602 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3603 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3607 CASE_PPC64 (OP_LAND_IMM)
3608 if (!(ins->inst_imm & 0xffff0000)) {
3609 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3610 } else if (!(ins->inst_imm & 0xffff)) {
3611 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3613 g_assert_not_reached ();
3617 CASE_PPC64 (OP_LDIV) {
3618 guint8 *divisor_is_m1;
3619 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3621 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3622 divisor_is_m1 = code;
3623 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3624 ppc_lis (code, ppc_r0, 0x8000);
3625 #ifdef __mono_ppc64__
3626 if (ins->opcode == OP_LDIV)
3627 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3629 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3630 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3631 ppc_patch (divisor_is_m1, code);
3632 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3634 if (ins->opcode == OP_IDIV)
3635 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3636 #ifdef __mono_ppc64__
3638 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3640 ppc_mfspr (code, ppc_r0, ppc_xer);
3641 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3642 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3646 CASE_PPC64 (OP_LDIV_UN)
3647 if (ins->opcode == OP_IDIV_UN)
3648 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3649 #ifdef __mono_ppc64__
3651 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3653 ppc_mfspr (code, ppc_r0, ppc_xer);
3654 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3655 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3661 g_assert_not_reached ();
3664 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3668 CASE_PPC64 (OP_LOR_IMM)
3669 if (!(ins->inst_imm & 0xffff0000)) {
3670 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3671 } else if (!(ins->inst_imm & 0xffff)) {
3672 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3674 g_assert_not_reached ();
3678 CASE_PPC64 (OP_LXOR)
3679 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3683 CASE_PPC64 (OP_LXOR_IMM)
3684 if (!(ins->inst_imm & 0xffff0000)) {
3685 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3686 } else if (!(ins->inst_imm & 0xffff)) {
3687 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3689 g_assert_not_reached ();
3693 CASE_PPC64 (OP_LSHL)
3694 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3698 CASE_PPC64 (OP_LSHL_IMM)
3699 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3702 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3705 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3708 if (MASK_SHIFT_IMM (ins->inst_imm))
3709 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3711 ppc_mr (code, ins->dreg, ins->sreg1);
3714 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3717 CASE_PPC64 (OP_LNOT)
3718 ppc_not (code, ins->dreg, ins->sreg1);
3721 CASE_PPC64 (OP_LNEG)
3722 ppc_neg (code, ins->dreg, ins->sreg1);
3725 CASE_PPC64 (OP_LMUL)
3726 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3730 CASE_PPC64 (OP_LMUL_IMM)
3731 if (ppc_is_imm16 (ins->inst_imm)) {
3732 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3734 g_assert_not_reached ();
3738 CASE_PPC64 (OP_LMUL_OVF)
3739 /* we annot use mcrxr, since it's not implemented on some processors
3740 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3742 if (ins->opcode == OP_IMUL_OVF)
3743 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3744 #ifdef __mono_ppc64__
3746 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3748 ppc_mfspr (code, ppc_r0, ppc_xer);
3749 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3750 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3752 case OP_IMUL_OVF_UN:
3753 CASE_PPC64 (OP_LMUL_OVF_UN)
3754 /* we first multiply to get the high word and compare to 0
3755 * to set the flags, then the result is discarded and then
3756 * we multiply to get the lower * bits result
3758 if (ins->opcode == OP_IMUL_OVF_UN)
3759 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3760 #ifdef __mono_ppc64__
3762 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3764 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3765 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3766 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3769 ppc_load (code, ins->dreg, ins->inst_c0);
3772 ppc_load (code, ins->dreg, ins->inst_l);
3775 case OP_LOAD_GOTADDR:
3776 /* The PLT implementation depends on this */
3777 g_assert (ins->dreg == ppc_r30);
3779 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3782 // FIXME: Fix max instruction length
3783 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3784 /* arch_emit_got_access () patches this */
3785 ppc_load32 (code, ppc_r0, 0);
3786 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3789 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3790 ppc_load_sequence (code, ins->dreg, 0);
3792 CASE_PPC32 (OP_ICONV_TO_I4)
3793 CASE_PPC32 (OP_ICONV_TO_U4)
3795 if (ins->dreg != ins->sreg1)
3796 ppc_mr (code, ins->dreg, ins->sreg1);
3799 int saved = ins->sreg1;
3800 if (ins->sreg1 == ppc_r3) {
3801 ppc_mr (code, ppc_r0, ins->sreg1);
3804 if (ins->sreg2 != ppc_r3)
3805 ppc_mr (code, ppc_r3, ins->sreg2);
3806 if (saved != ppc_r4)
3807 ppc_mr (code, ppc_r4, saved);
3811 if (ins->dreg != ins->sreg1)
3812 ppc_fmr (code, ins->dreg, ins->sreg1);
3814 case OP_MOVE_F_TO_I4:
3815 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3816 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3818 case OP_MOVE_I4_TO_F:
3819 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3820 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3822 case OP_FCONV_TO_R4:
3823 ppc_frsp (code, ins->dreg, ins->sreg1);
3827 MonoCallInst *call = (MonoCallInst*)ins;
3830 * Keep in sync with mono_arch_emit_epilog
3832 g_assert (!cfg->method->save_lmf);
3834 * Note: we can use ppc_r12 here because it is dead anyway:
3835 * we're leaving the method.
3837 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3838 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3839 if (ppc_is_imm16 (ret_offset)) {
3840 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3842 ppc_load (code, ppc_r12, ret_offset);
3843 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3845 ppc_mtlr (code, ppc_r0);
3848 if (ppc_is_imm16 (cfg->stack_usage)) {
3849 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3851 /* cfg->stack_usage is an int, so we can use
3852 * an addis/addi sequence here even in 64-bit. */
3853 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3854 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3856 if (!cfg->method->save_lmf) {
3858 for (i = 31; i >= 13; --i) {
3859 if (cfg->used_int_regs & (1 << i)) {
3860 pos += sizeof (gpointer);
3861 ppc_ldptr (code, i, -pos, ppc_r12);
3865 /* FIXME restore from MonoLMF: though this can't happen yet */
3868 /* Copy arguments on the stack to our argument area */
3869 if (call->stack_usage) {
3870 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3871 /* r12 was clobbered */
3872 g_assert (cfg->frame_reg == ppc_sp);
3873 if (ppc_is_imm16 (cfg->stack_usage)) {
3874 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3876 /* cfg->stack_usage is an int, so we can use
3877 * an addis/addi sequence here even in 64-bit. */
3878 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3879 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3883 ppc_mr (code, ppc_sp, ppc_r12);
3884 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3885 if (cfg->compile_aot) {
3886 /* arch_emit_got_access () patches this */
3887 ppc_load32 (code, ppc_r0, 0);
3888 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3889 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3890 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3892 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3894 ppc_mtctr (code, ppc_r0);
3895 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3902 /* ensure ins->sreg1 is not NULL */
3903 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3906 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3907 if (ppc_is_imm16 (cookie_offset)) {
3908 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3910 ppc_load (code, ppc_r0, cookie_offset);
3911 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3913 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3922 call = (MonoCallInst*)ins;
3923 if (ins->flags & MONO_INST_HAS_METHOD)
3924 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3926 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3927 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3928 ppc_load_func (code, PPC_CALL_REG, 0);
3929 ppc_mtlr (code, PPC_CALL_REG);
3934 /* FIXME: this should be handled somewhere else in the new jit */
3935 code = emit_move_return_value (cfg, ins, code);
3941 case OP_VOIDCALL_REG:
3943 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3944 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3945 /* FIXME: if we know that this is a method, we
3946 can omit this load */
3947 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3948 ppc_mtlr (code, ppc_r0);
3950 #if (_CALL_ELF == 2)
3951 if (ins->flags & MONO_INST_HAS_METHOD) {
3952 // Not a global entry point
3954 // Need to set up r12 with function entry address for global entry point
3955 if (ppc_r12 != ins->sreg1) {
3956 ppc_mr(code,ppc_r12,ins->sreg1);
3960 ppc_mtlr (code, ins->sreg1);
3963 /* FIXME: this should be handled somewhere else in the new jit */
3964 code = emit_move_return_value (cfg, ins, code);
3966 case OP_FCALL_MEMBASE:
3967 case OP_LCALL_MEMBASE:
3968 case OP_VCALL_MEMBASE:
3969 case OP_VCALL2_MEMBASE:
3970 case OP_VOIDCALL_MEMBASE:
3971 case OP_CALL_MEMBASE:
3972 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3973 /* The trampolines clobber this */
3974 ppc_mr (code, ppc_r29, ins->sreg1);
3975 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3977 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3979 ppc_mtlr (code, ppc_r0);
3981 /* FIXME: this should be handled somewhere else in the new jit */
3982 code = emit_move_return_value (cfg, ins, code);
3985 guint8 * zero_loop_jump, * zero_loop_start;
3986 /* keep alignment */
3987 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3988 int area_offset = alloca_waste;
3990 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3991 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3992 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3993 /* use ctr to store the number of words to 0 if needed */
3994 if (ins->flags & MONO_INST_INIT) {
3995 /* we zero 4 bytes at a time:
3996 * we add 7 instead of 3 so that we set the counter to
3997 * at least 1, otherwise the bdnz instruction will make
3998 * it negative and iterate billions of times.
4000 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4001 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4002 ppc_mtctr (code, ppc_r0);
4004 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4005 ppc_neg (code, ppc_r12, ppc_r12);
4006 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4008 /* FIXME: make this loop work in 8 byte
4009 increments on PPC64 */
4010 if (ins->flags & MONO_INST_INIT) {
4011 /* adjust the dest reg by -4 so we can use stwu */
4012 /* we actually adjust -8 because we let the loop
4015 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4016 ppc_li (code, ppc_r12, 0);
4017 zero_loop_start = code;
4018 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4019 zero_loop_jump = code;
4020 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4021 ppc_patch (zero_loop_jump, zero_loop_start);
4023 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4028 ppc_mr (code, ppc_r3, ins->sreg1);
4029 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4030 (gpointer)"mono_arch_throw_exception");
4031 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4032 ppc_load_func (code, PPC_CALL_REG, 0);
4033 ppc_mtlr (code, PPC_CALL_REG);
4042 ppc_mr (code, ppc_r3, ins->sreg1);
4043 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4044 (gpointer)"mono_arch_rethrow_exception");
4045 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4046 ppc_load_func (code, PPC_CALL_REG, 0);
4047 ppc_mtlr (code, PPC_CALL_REG);
4054 case OP_START_HANDLER: {
4055 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4056 g_assert (spvar->inst_basereg != ppc_sp);
4057 code = emit_reserve_param_area (cfg, code);
4058 ppc_mflr (code, ppc_r0);
4059 if (ppc_is_imm16 (spvar->inst_offset)) {
4060 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4062 ppc_load (code, ppc_r12, spvar->inst_offset);
4063 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4067 case OP_ENDFILTER: {
4068 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4069 g_assert (spvar->inst_basereg != ppc_sp);
4070 code = emit_unreserve_param_area (cfg, code);
4071 if (ins->sreg1 != ppc_r3)
4072 ppc_mr (code, ppc_r3, ins->sreg1);
4073 if (ppc_is_imm16 (spvar->inst_offset)) {
4074 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4076 ppc_load (code, ppc_r12, spvar->inst_offset);
4077 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4079 ppc_mtlr (code, ppc_r0);
4083 case OP_ENDFINALLY: {
4084 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4085 g_assert (spvar->inst_basereg != ppc_sp);
4086 code = emit_unreserve_param_area (cfg, code);
4087 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4088 ppc_mtlr (code, ppc_r0);
4092 case OP_CALL_HANDLER:
4093 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4095 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4098 ins->inst_c0 = code - cfg->native_code;
4101 /*if (ins->inst_target_bb->native_offset) {
4103 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4105 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4110 ppc_mtctr (code, ins->sreg1);
4111 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4115 CASE_PPC64 (OP_LCEQ)
4116 ppc_li (code, ins->dreg, 0);
4117 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4118 ppc_li (code, ins->dreg, 1);
4124 CASE_PPC64 (OP_LCLT)
4125 CASE_PPC64 (OP_LCLT_UN)
4126 ppc_li (code, ins->dreg, 1);
4127 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4128 ppc_li (code, ins->dreg, 0);
4134 CASE_PPC64 (OP_LCGT)
4135 CASE_PPC64 (OP_LCGT_UN)
4136 ppc_li (code, ins->dreg, 1);
4137 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4138 ppc_li (code, ins->dreg, 0);
4140 case OP_COND_EXC_EQ:
4141 case OP_COND_EXC_NE_UN:
4142 case OP_COND_EXC_LT:
4143 case OP_COND_EXC_LT_UN:
4144 case OP_COND_EXC_GT:
4145 case OP_COND_EXC_GT_UN:
4146 case OP_COND_EXC_GE:
4147 case OP_COND_EXC_GE_UN:
4148 case OP_COND_EXC_LE:
4149 case OP_COND_EXC_LE_UN:
4150 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4152 case OP_COND_EXC_IEQ:
4153 case OP_COND_EXC_INE_UN:
4154 case OP_COND_EXC_ILT:
4155 case OP_COND_EXC_ILT_UN:
4156 case OP_COND_EXC_IGT:
4157 case OP_COND_EXC_IGT_UN:
4158 case OP_COND_EXC_IGE:
4159 case OP_COND_EXC_IGE_UN:
4160 case OP_COND_EXC_ILE:
4161 case OP_COND_EXC_ILE_UN:
4162 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4174 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4177 /* floating point opcodes */
4179 g_assert (cfg->compile_aot);
4181 /* FIXME: Optimize this */
4183 ppc_mflr (code, ppc_r12);
4185 *(double*)code = *(double*)ins->inst_p0;
4187 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4190 g_assert_not_reached ();
4192 case OP_STORER8_MEMBASE_REG:
4193 if (ppc_is_imm16 (ins->inst_offset)) {
4194 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4196 if (ppc_is_imm32 (ins->inst_offset)) {
4197 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4198 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4200 ppc_load (code, ppc_r0, ins->inst_offset);
4201 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4205 case OP_LOADR8_MEMBASE:
4206 if (ppc_is_imm16 (ins->inst_offset)) {
4207 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4209 if (ppc_is_imm32 (ins->inst_offset)) {
4210 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4211 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4213 ppc_load (code, ppc_r0, ins->inst_offset);
4214 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4218 case OP_STORER4_MEMBASE_REG:
4219 ppc_frsp (code, ins->sreg1, ins->sreg1);
4220 if (ppc_is_imm16 (ins->inst_offset)) {
4221 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4223 if (ppc_is_imm32 (ins->inst_offset)) {
4224 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4225 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4227 ppc_load (code, ppc_r0, ins->inst_offset);
4228 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4232 case OP_LOADR4_MEMBASE:
4233 if (ppc_is_imm16 (ins->inst_offset)) {
4234 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4236 if (ppc_is_imm32 (ins->inst_offset)) {
4237 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4238 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4240 ppc_load (code, ppc_r0, ins->inst_offset);
4241 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4245 case OP_LOADR4_MEMINDEX:
4246 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4248 case OP_LOADR8_MEMINDEX:
4249 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4251 case OP_STORER4_MEMINDEX:
4252 ppc_frsp (code, ins->sreg1, ins->sreg1);
4253 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4255 case OP_STORER8_MEMINDEX:
4256 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4259 case CEE_CONV_R4: /* FIXME: change precision */
4261 g_assert_not_reached ();
4262 case OP_FCONV_TO_I1:
4263 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4265 case OP_FCONV_TO_U1:
4266 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4268 case OP_FCONV_TO_I2:
4269 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4271 case OP_FCONV_TO_U2:
4272 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4274 case OP_FCONV_TO_I4:
4276 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4278 case OP_FCONV_TO_U4:
4280 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4282 case OP_LCONV_TO_R_UN:
4283 g_assert_not_reached ();
4284 /* Implemented as helper calls */
4286 case OP_LCONV_TO_OVF_I4_2:
4287 case OP_LCONV_TO_OVF_I: {
4288 #ifdef __mono_ppc64__
4291 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4292 // Check if its negative
4293 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4294 negative_branch = code;
4295 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4296 // Its positive msword == 0
4297 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4298 msword_positive_branch = code;
4299 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4301 ovf_ex_target = code;
4302 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4304 ppc_patch (negative_branch, code);
4305 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4306 msword_negative_branch = code;
4307 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4308 ppc_patch (msword_negative_branch, ovf_ex_target);
4310 ppc_patch (msword_positive_branch, code);
4311 if (ins->dreg != ins->sreg1)
4312 ppc_mr (code, ins->dreg, ins->sreg1);
4317 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4320 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4323 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4326 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4329 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4332 ppc_fneg (code, ins->dreg, ins->sreg1);
4336 g_assert_not_reached ();
4339 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4342 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4343 ppc_li (code, ins->dreg, 0);
4344 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4345 ppc_li (code, ins->dreg, 1);
4348 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4349 ppc_li (code, ins->dreg, 1);
4350 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4351 ppc_li (code, ins->dreg, 0);
4354 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4355 ppc_li (code, ins->dreg, 1);
4356 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4357 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4358 ppc_li (code, ins->dreg, 0);
4361 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4362 ppc_li (code, ins->dreg, 1);
4363 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4364 ppc_li (code, ins->dreg, 0);
4367 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4368 ppc_li (code, ins->dreg, 1);
4369 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4370 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4371 ppc_li (code, ins->dreg, 0);
4374 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4377 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4380 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4381 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4384 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4385 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4388 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4389 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4392 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4393 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4396 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4397 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4400 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4403 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4404 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4407 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4410 g_assert_not_reached ();
4411 case OP_CHECK_FINITE: {
4412 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4413 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4414 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4415 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4418 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4419 #ifdef __mono_ppc64__
4420 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4422 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4427 #ifdef __mono_ppc64__
4428 case OP_ICONV_TO_I4:
4430 ppc_extsw (code, ins->dreg, ins->sreg1);
4432 case OP_ICONV_TO_U4:
4434 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4436 case OP_ICONV_TO_R4:
4437 case OP_ICONV_TO_R8:
4438 case OP_LCONV_TO_R4:
4439 case OP_LCONV_TO_R8: {
4441 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4442 ppc_extsw (code, ppc_r0, ins->sreg1);
4447 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4448 ppc_mffgpr (code, ins->dreg, tmp);
4450 ppc_str (code, tmp, -8, ppc_r1);
4451 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4453 ppc_fcfid (code, ins->dreg, ins->dreg);
4454 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4455 ppc_frsp (code, ins->dreg, ins->dreg);
4459 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4462 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4465 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4467 ppc_mfspr (code, ppc_r0, ppc_xer);
4468 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4469 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4471 case OP_COND_EXC_OV:
4472 ppc_mfspr (code, ppc_r0, ppc_xer);
4473 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4474 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4486 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4488 case OP_FCONV_TO_I8:
4489 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4491 case OP_FCONV_TO_U8:
4492 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4494 case OP_STOREI4_MEMBASE_REG:
4495 if (ppc_is_imm16 (ins->inst_offset)) {
4496 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4498 ppc_load (code, ppc_r0, ins->inst_offset);
4499 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4502 case OP_STOREI4_MEMINDEX:
4503 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4506 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4508 case OP_ISHR_UN_IMM:
4509 if (ins->inst_imm & 0x1f)
4510 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4512 ppc_mr (code, ins->dreg, ins->sreg1);
4515 case OP_ICONV_TO_R4:
4516 case OP_ICONV_TO_R8: {
4517 if (cpu_hw_caps & PPC_ISA_64) {
4518 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4519 ppc_stw (code, ppc_r0, -8, ppc_r1);
4520 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4521 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4522 ppc_fcfid (code, ins->dreg, ins->dreg);
4523 if (ins->opcode == OP_ICONV_TO_R4)
4524 ppc_frsp (code, ins->dreg, ins->dreg);
4530 case OP_ATOMIC_ADD_I4:
4531 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4532 int location = ins->inst_basereg;
4533 int addend = ins->sreg2;
4534 guint8 *loop, *branch;
4535 g_assert (ins->inst_offset == 0);
4539 if (ins->opcode == OP_ATOMIC_ADD_I4)
4540 ppc_lwarx (code, ppc_r0, 0, location);
4541 #ifdef __mono_ppc64__
4543 ppc_ldarx (code, ppc_r0, 0, location);
4546 ppc_add (code, ppc_r0, ppc_r0, addend);
4548 if (ins->opcode == OP_ATOMIC_ADD_I4)
4549 ppc_stwcxd (code, ppc_r0, 0, location);
4550 #ifdef __mono_ppc64__
4552 ppc_stdcxd (code, ppc_r0, 0, location);
4556 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4557 ppc_patch (branch, loop);
4560 ppc_mr (code, ins->dreg, ppc_r0);
4563 case OP_ATOMIC_CAS_I4:
4564 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4565 int location = ins->sreg1;
4566 int value = ins->sreg2;
4567 int comparand = ins->sreg3;
4568 guint8 *start, *not_equal, *lost_reservation;
4572 if (ins->opcode == OP_ATOMIC_CAS_I4)
4573 ppc_lwarx (code, ppc_r0, 0, location);
4574 #ifdef __mono_ppc64__
4576 ppc_ldarx (code, ppc_r0, 0, location);
4579 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4581 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4583 if (ins->opcode == OP_ATOMIC_CAS_I4)
4584 ppc_stwcxd (code, value, 0, location);
4585 #ifdef __mono_ppc64__
4587 ppc_stdcxd (code, value, 0, location);
4590 lost_reservation = code;
4591 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4592 ppc_patch (lost_reservation, start);
4593 ppc_patch (not_equal, code);
4596 ppc_mr (code, ins->dreg, ppc_r0);
4599 case OP_GC_SAFE_POINT:
4603 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4604 g_assert_not_reached ();
4607 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4608 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4609 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4610 g_assert_not_reached ();
4616 last_offset = offset;
4619 cfg->code_len = code - cfg->native_code;
4621 #endif /* !DISABLE_JIT */
4624 mono_arch_register_lowlevel_calls (void)
4626 /* The signature doesn't matter */
4627 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4630 #ifdef __mono_ppc64__
4631 #ifdef _LITTLE_ENDIAN
4632 #define patch_load_sequence(ip,val) do {\
4633 guint16 *__load = (guint16*)(ip); \
4634 g_assert (sizeof (val) == sizeof (gsize)); \
4635 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4636 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4637 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4638 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4640 #elif defined _BIG_ENDIAN
4641 #define patch_load_sequence(ip,val) do {\
4642 guint16 *__load = (guint16*)(ip); \
4643 g_assert (sizeof (val) == sizeof (gsize)); \
4644 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4645 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4646 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4647 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4650 #error huh? No endianess defined by compiler
4653 #define patch_load_sequence(ip,val) do {\
4654 guint16 *__lis_ori = (guint16*)(ip); \
4655 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4656 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4662 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4664 MonoJumpInfo *patch_info;
4665 gboolean compile_aot = !run_cctors;
4667 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4668 unsigned char *ip = patch_info->ip.i + code;
4669 unsigned char *target;
4670 gboolean is_fd = FALSE;
4672 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4675 switch (patch_info->type) {
4676 case MONO_PATCH_INFO_BB:
4677 case MONO_PATCH_INFO_LABEL:
4680 /* No need to patch these */
4685 switch (patch_info->type) {
4686 case MONO_PATCH_INFO_IP:
4687 patch_load_sequence (ip, ip);
4689 case MONO_PATCH_INFO_METHOD_REL:
4690 g_assert_not_reached ();
4691 *((gpointer *)(ip)) = code + patch_info->data.offset;
4693 case MONO_PATCH_INFO_SWITCH: {
4694 gpointer *table = (gpointer *)patch_info->data.table->table;
4697 patch_load_sequence (ip, table);
4699 for (i = 0; i < patch_info->data.table->table_size; i++) {
4700 table [i] = (glong)patch_info->data.table->table [i] + code;
4702 /* we put into the table the absolute address, no need for ppc_patch in this case */
4705 case MONO_PATCH_INFO_METHODCONST:
4706 case MONO_PATCH_INFO_CLASS:
4707 case MONO_PATCH_INFO_IMAGE:
4708 case MONO_PATCH_INFO_FIELD:
4709 case MONO_PATCH_INFO_VTABLE:
4710 case MONO_PATCH_INFO_IID:
4711 case MONO_PATCH_INFO_SFLDA:
4712 case MONO_PATCH_INFO_LDSTR:
4713 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4714 case MONO_PATCH_INFO_LDTOKEN:
4715 /* from OP_AOTCONST : lis + ori */
4716 patch_load_sequence (ip, target);
4718 case MONO_PATCH_INFO_R4:
4719 case MONO_PATCH_INFO_R8:
4720 g_assert_not_reached ();
4721 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4723 case MONO_PATCH_INFO_EXC_NAME:
4724 g_assert_not_reached ();
4725 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4727 case MONO_PATCH_INFO_NONE:
4728 case MONO_PATCH_INFO_BB_OVF:
4729 case MONO_PATCH_INFO_EXC_OVF:
4730 /* everything is dealt with at epilog output time */
4732 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4733 case MONO_PATCH_INFO_INTERNAL_METHOD:
4734 case MONO_PATCH_INFO_ABS:
4735 case MONO_PATCH_INFO_RGCTX_FETCH:
4736 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4743 ppc_patch_full (ip, target, is_fd);
4748 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4749 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4750 * the instruction offset immediate for all the registers.
4753 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4757 for (i = 13; i <= 31; i++) {
4758 if (used_int_regs & (1 << i)) {
4759 ppc_str (code, i, pos, base_reg);
4760 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4761 pos += sizeof (mgreg_t);
4765 /* pos is the start of the MonoLMF structure */
4766 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4767 for (i = 13; i <= 31; i++) {
4768 ppc_str (code, i, offset, base_reg);
4769 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4770 offset += sizeof (mgreg_t);
4772 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4773 for (i = 14; i < 32; i++) {
4774 ppc_stfd (code, i, offset, base_reg);
4775 offset += sizeof (gdouble);
4782 * Stack frame layout:
4784 * ------------------- sp
4785 * MonoLMF structure or saved registers
4786 * -------------------
4788 * -------------------
4790 * -------------------
4791 * optional 8 bytes for tracing
4792 * -------------------
4793 * param area size is cfg->param_area
4794 * -------------------
4795 * linkage area size is PPC_STACK_PARAM_OFFSET
4796 * ------------------- sp
4800 mono_arch_emit_prolog (MonoCompile *cfg)
4802 MonoMethod *method = cfg->method;
4804 MonoMethodSignature *sig;
4806 long alloc_size, pos, max_offset, cfa_offset;
4812 int tailcall_struct_index;
4814 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4817 sig = mono_method_signature (method);
4818 cfg->code_size = 512 + sig->param_count * 32;
4819 code = cfg->native_code = g_malloc (cfg->code_size);
4823 /* We currently emit unwind info for aot, but don't use it */
4824 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4826 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4827 ppc_mflr (code, ppc_r0);
4828 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4829 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4832 alloc_size = cfg->stack_offset;
4835 if (!method->save_lmf) {
4836 for (i = 31; i >= 13; --i) {
4837 if (cfg->used_int_regs & (1 << i)) {
4838 pos += sizeof (mgreg_t);
4842 pos += sizeof (MonoLMF);
4846 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4847 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4848 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4849 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4852 cfg->stack_usage = alloc_size;
4853 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4855 if (ppc_is_imm16 (-alloc_size)) {
4856 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4857 cfa_offset = alloc_size;
4858 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4859 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4862 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4863 ppc_load (code, ppc_r0, -alloc_size);
4864 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4865 cfa_offset = alloc_size;
4866 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4867 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4870 if (cfg->frame_reg != ppc_sp) {
4871 ppc_mr (code, cfg->frame_reg, ppc_sp);
4872 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4875 /* store runtime generic context */
4876 if (cfg->rgctx_var) {
4877 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4878 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4880 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4883 /* compute max_offset in order to use short forward jumps
4884 * we always do it on ppc because the immediate displacement
4885 * for jumps is too small
4888 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4890 bb->max_offset = max_offset;
4892 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4895 MONO_BB_FOR_EACH_INS (bb, ins)
4896 max_offset += ins_native_length (cfg, ins);
4899 /* load arguments allocated to register from the stack */
4902 cinfo = get_call_info (sig);
4904 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4905 ArgInfo *ainfo = &cinfo->ret;
4907 inst = cfg->vret_addr;
4910 if (ppc_is_imm16 (inst->inst_offset)) {
4911 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4913 ppc_load (code, ppc_r12, inst->inst_offset);
4914 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4918 tailcall_struct_index = 0;
4919 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4920 ArgInfo *ainfo = cinfo->args + i;
4921 inst = cfg->args [pos];
4923 if (cfg->verbose_level > 2)
4924 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4925 if (inst->opcode == OP_REGVAR) {
4926 if (ainfo->regtype == RegTypeGeneral)
4927 ppc_mr (code, inst->dreg, ainfo->reg);
4928 else if (ainfo->regtype == RegTypeFP)
4929 ppc_fmr (code, inst->dreg, ainfo->reg);
4930 else if (ainfo->regtype == RegTypeBase) {
4931 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4932 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4934 g_assert_not_reached ();
4936 if (cfg->verbose_level > 2)
4937 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4939 /* the argument should be put on the stack: FIXME handle size != word */
4940 if (ainfo->regtype == RegTypeGeneral) {
4941 switch (ainfo->size) {
4943 if (ppc_is_imm16 (inst->inst_offset)) {
4944 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4946 if (ppc_is_imm32 (inst->inst_offset)) {
4947 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4948 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4950 ppc_load (code, ppc_r12, inst->inst_offset);
4951 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4956 if (ppc_is_imm16 (inst->inst_offset)) {
4957 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4959 if (ppc_is_imm32 (inst->inst_offset)) {
4960 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4961 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4963 ppc_load (code, ppc_r12, inst->inst_offset);
4964 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4968 #ifdef __mono_ppc64__
4970 if (ppc_is_imm16 (inst->inst_offset)) {
4971 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4973 if (ppc_is_imm32 (inst->inst_offset)) {
4974 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4975 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4977 ppc_load (code, ppc_r12, inst->inst_offset);
4978 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4983 if (ppc_is_imm16 (inst->inst_offset)) {
4984 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4986 ppc_load (code, ppc_r12, inst->inst_offset);
4987 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4992 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4993 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4994 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4996 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4997 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4998 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4999 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5004 if (ppc_is_imm16 (inst->inst_offset)) {
5005 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5007 if (ppc_is_imm32 (inst->inst_offset)) {
5008 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5009 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5011 ppc_load (code, ppc_r12, inst->inst_offset);
5012 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5017 } else if (ainfo->regtype == RegTypeBase) {
5018 g_assert (ppc_is_imm16 (ainfo->offset));
5019 /* load the previous stack pointer in r12 */
5020 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5021 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5022 switch (ainfo->size) {
5024 if (ppc_is_imm16 (inst->inst_offset)) {
5025 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5027 if (ppc_is_imm32 (inst->inst_offset)) {
5028 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5029 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5031 ppc_load (code, ppc_r12, inst->inst_offset);
5032 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5037 if (ppc_is_imm16 (inst->inst_offset)) {
5038 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5040 if (ppc_is_imm32 (inst->inst_offset)) {
5041 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5042 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5044 ppc_load (code, ppc_r12, inst->inst_offset);
5045 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5049 #ifdef __mono_ppc64__
5051 if (ppc_is_imm16 (inst->inst_offset)) {
5052 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5054 if (ppc_is_imm32 (inst->inst_offset)) {
5055 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5056 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5058 ppc_load (code, ppc_r12, inst->inst_offset);
5059 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5064 if (ppc_is_imm16 (inst->inst_offset)) {
5065 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5067 ppc_load (code, ppc_r12, inst->inst_offset);
5068 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5073 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5074 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5075 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5076 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5077 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5079 /* use r11 to load the 2nd half of the long before we clobber r12. */
5080 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5081 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5082 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5083 ppc_stw (code, ppc_r0, 0, ppc_r12);
5084 ppc_stw (code, ppc_r11, 4, ppc_r12);
5089 if (ppc_is_imm16 (inst->inst_offset)) {
5090 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5092 if (ppc_is_imm32 (inst->inst_offset)) {
5093 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5094 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5096 ppc_load (code, ppc_r12, inst->inst_offset);
5097 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5102 } else if (ainfo->regtype == RegTypeFP) {
5103 g_assert (ppc_is_imm16 (inst->inst_offset));
5104 if (ainfo->size == 8)
5105 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5106 else if (ainfo->size == 4)
5107 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5109 g_assert_not_reached ();
5110 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5111 int doffset = inst->inst_offset;
5115 g_assert (ppc_is_imm16 (inst->inst_offset));
5116 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5117 /* FIXME: what if there is no class? */
5118 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5119 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5120 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5121 if (ainfo->size == 4) {
5122 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5124 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5126 soffset += ainfo->size;
5127 doffset += ainfo->size;
5129 } else if (ainfo->regtype == RegTypeStructByVal) {
5130 int doffset = inst->inst_offset;
5134 g_assert (ppc_is_imm16 (inst->inst_offset));
5135 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5136 /* FIXME: what if there is no class? */
5137 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5138 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5139 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5142 * Darwin handles 1 and 2 byte
5143 * structs specially by
5144 * loading h/b into the arg
5145 * register. Only done for
5149 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5151 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5155 #ifdef __mono_ppc64__
5157 g_assert (cur_reg == 0);
5158 #if G_BYTE_ORDER == G_BIG_ENDIAN
5159 ppc_sldi (code, ppc_r0, ainfo->reg,
5160 (sizeof (gpointer) - ainfo->bytes) * 8);
5161 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5163 if (mono_class_native_size (inst->klass, NULL) == 1) {
5164 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5165 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5166 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5167 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5168 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5170 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5176 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5177 inst->inst_basereg);
5180 soffset += sizeof (gpointer);
5181 doffset += sizeof (gpointer);
5183 if (ainfo->vtsize) {
5184 /* FIXME: we need to do the shifting here, too */
5187 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5188 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5189 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5190 code = emit_memcpy (code, size - soffset,
5191 inst->inst_basereg, doffset,
5192 ppc_r12, ainfo->offset + soffset);
5194 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5195 inst->inst_basereg, doffset,
5196 ppc_r12, ainfo->offset + soffset);
5199 } else if (ainfo->regtype == RegTypeStructByAddr) {
5200 /* if it was originally a RegTypeBase */
5201 if (ainfo->offset) {
5202 /* load the previous stack pointer in r12 */
5203 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5204 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5206 ppc_mr (code, ppc_r12, ainfo->reg);
5209 if (cfg->tailcall_valuetype_addrs) {
5210 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5212 g_assert (ppc_is_imm16 (addr->inst_offset));
5213 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5215 tailcall_struct_index++;
5218 g_assert (ppc_is_imm16 (inst->inst_offset));
5219 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5220 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5222 g_assert_not_reached ();
5227 if (method->save_lmf) {
5228 if (lmf_pthread_key != -1) {
5229 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5230 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5231 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5233 if (cfg->compile_aot) {
5234 /* Compute the got address which is needed by the PLT entry */
5235 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5237 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5238 (gpointer)"mono_get_lmf_addr");
5239 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5240 ppc_load_func (code, PPC_CALL_REG, 0);
5241 ppc_mtlr (code, PPC_CALL_REG);
5247 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5248 /* lmf_offset is the offset from the previous stack pointer,
5249 * alloc_size is the total stack space allocated, so the offset
5250 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5251 * The pointer to the struct is put in ppc_r12 (new_lmf).
5252 * The callee-saved registers are already in the MonoLMF structure
5254 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5255 /* ppc_r3 is the result from mono_get_lmf_addr () */
5256 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5257 /* new_lmf->previous_lmf = *lmf_addr */
5258 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5259 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5260 /* *(lmf_addr) = r12 */
5261 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5262 /* save method info */
5263 if (cfg->compile_aot)
5265 ppc_load (code, ppc_r0, 0);
5267 ppc_load_ptr (code, ppc_r0, method);
5268 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5269 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5270 /* save the current IP */
5271 if (cfg->compile_aot) {
5273 ppc_mflr (code, ppc_r0);
5275 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5276 #ifdef __mono_ppc64__
5277 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5279 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5282 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5286 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5288 cfg->code_len = code - cfg->native_code;
5289 g_assert (cfg->code_len <= cfg->code_size);
5296 mono_arch_emit_epilog (MonoCompile *cfg)
5298 MonoMethod *method = cfg->method;
5300 int max_epilog_size = 16 + 20*4;
5303 if (cfg->method->save_lmf)
5304 max_epilog_size += 128;
5306 if (mono_jit_trace_calls != NULL)
5307 max_epilog_size += 50;
5309 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5310 max_epilog_size += 50;
5312 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5313 cfg->code_size *= 2;
5314 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5315 cfg->stat_code_reallocs++;
5319 * Keep in sync with OP_JMP
5321 code = cfg->native_code + cfg->code_len;
5323 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5324 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5328 if (method->save_lmf) {
5330 pos += sizeof (MonoLMF);
5332 /* save the frame reg in r8 */
5333 ppc_mr (code, ppc_r8, cfg->frame_reg);
5334 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5335 /* r5 = previous_lmf */
5336 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5338 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5339 /* *(lmf_addr) = previous_lmf */
5340 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5341 /* FIXME: speedup: there is no actual need to restore the registers if
5342 * we didn't actually change them (idea from Zoltan).
5345 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5347 /*for (i = 14; i < 32; i++) {
5348 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5350 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5351 /* use the saved copy of the frame reg in r8 */
5352 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5353 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5354 ppc_mtlr (code, ppc_r0);
5356 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5358 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5359 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5360 if (ppc_is_imm16 (return_offset)) {
5361 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5363 ppc_load (code, ppc_r12, return_offset);
5364 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5366 ppc_mtlr (code, ppc_r0);
5368 if (ppc_is_imm16 (cfg->stack_usage)) {
5369 int offset = cfg->stack_usage;
5370 for (i = 13; i <= 31; i++) {
5371 if (cfg->used_int_regs & (1 << i))
5372 offset -= sizeof (mgreg_t);
5374 if (cfg->frame_reg != ppc_sp)
5375 ppc_mr (code, ppc_r12, cfg->frame_reg);
5376 /* note r31 (possibly the frame register) is restored last */
5377 for (i = 13; i <= 31; i++) {
5378 if (cfg->used_int_regs & (1 << i)) {
5379 ppc_ldr (code, i, offset, cfg->frame_reg);
5380 offset += sizeof (mgreg_t);
5383 if (cfg->frame_reg != ppc_sp)
5384 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5386 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5388 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5389 if (cfg->used_int_regs) {
5390 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5391 for (i = 31; i >= 13; --i) {
5392 if (cfg->used_int_regs & (1 << i)) {
5393 pos += sizeof (mgreg_t);
5394 ppc_ldr (code, i, -pos, ppc_r12);
5397 ppc_mr (code, ppc_sp, ppc_r12);
5399 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5406 cfg->code_len = code - cfg->native_code;
5408 g_assert (cfg->code_len < cfg->code_size);
5411 #endif /* ifndef DISABLE_JIT */
5413 /* remove once throw_exception_by_name is eliminated */
5415 exception_id_by_name (const char *name)
5417 if (strcmp (name, "IndexOutOfRangeException") == 0)
5418 return MONO_EXC_INDEX_OUT_OF_RANGE;
5419 if (strcmp (name, "OverflowException") == 0)
5420 return MONO_EXC_OVERFLOW;
5421 if (strcmp (name, "ArithmeticException") == 0)
5422 return MONO_EXC_ARITHMETIC;
5423 if (strcmp (name, "DivideByZeroException") == 0)
5424 return MONO_EXC_DIVIDE_BY_ZERO;
5425 if (strcmp (name, "InvalidCastException") == 0)
5426 return MONO_EXC_INVALID_CAST;
5427 if (strcmp (name, "NullReferenceException") == 0)
5428 return MONO_EXC_NULL_REF;
5429 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5430 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5431 if (strcmp (name, "ArgumentException") == 0)
5432 return MONO_EXC_ARGUMENT;
5433 g_error ("Unknown intrinsic exception %s\n", name);
5439 mono_arch_emit_exceptions (MonoCompile *cfg)
5441 MonoJumpInfo *patch_info;
5444 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5445 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5446 int max_epilog_size = 50;
5448 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5449 exc_throw_pos [i] = NULL;
5450 exc_throw_found [i] = 0;
5453 /* count the number of exception infos */
5456 * make sure we have enough space for exceptions
5458 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5459 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5460 i = exception_id_by_name (patch_info->data.target);
5461 if (!exc_throw_found [i]) {
5462 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5463 exc_throw_found [i] = TRUE;
5465 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5466 max_epilog_size += 12;
5467 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5468 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5469 i = exception_id_by_name (ovfj->data.exception);
5470 if (!exc_throw_found [i]) {
5471 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5472 exc_throw_found [i] = TRUE;
5474 max_epilog_size += 8;
5478 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5479 cfg->code_size *= 2;
5480 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5481 cfg->stat_code_reallocs++;
5484 code = cfg->native_code + cfg->code_len;
5486 /* add code to raise exceptions */
5487 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5488 switch (patch_info->type) {
5489 case MONO_PATCH_INFO_BB_OVF: {
5490 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5491 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5492 /* patch the initial jump */
5493 ppc_patch (ip, code);
5494 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5496 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5497 /* jump back to the true target */
5499 ip = ovfj->data.bb->native_offset + cfg->native_code;
5500 ppc_patch (code - 4, ip);
5501 patch_info->type = MONO_PATCH_INFO_NONE;
5504 case MONO_PATCH_INFO_EXC_OVF: {
5505 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5506 MonoJumpInfo *newji;
5507 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5508 unsigned char *bcl = code;
5509 /* patch the initial jump: we arrived here with a call */
5510 ppc_patch (ip, code);
5511 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5513 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5514 /* patch the conditional jump to the right handler */
5515 /* make it processed next */
5516 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5517 newji->type = MONO_PATCH_INFO_EXC;
5518 newji->ip.i = bcl - cfg->native_code;
5519 newji->data.target = ovfj->data.exception;
5520 newji->next = patch_info->next;
5521 patch_info->next = newji;
5522 patch_info->type = MONO_PATCH_INFO_NONE;
5525 case MONO_PATCH_INFO_EXC: {
5526 MonoClass *exc_class;
5528 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5529 i = exception_id_by_name (patch_info->data.target);
5530 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5531 ppc_patch (ip, exc_throw_pos [i]);
5532 patch_info->type = MONO_PATCH_INFO_NONE;
5535 exc_throw_pos [i] = code;
5538 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5539 g_assert (exc_class);
5541 ppc_patch (ip, code);
5542 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5543 ppc_load (code, ppc_r3, exc_class->type_token);
5544 /* we got here from a conditional call, so the calling ip is set in lr */
5545 ppc_mflr (code, ppc_r4);
5546 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5547 patch_info->data.name = "mono_arch_throw_corlib_exception";
5548 patch_info->ip.i = code - cfg->native_code;
5549 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5550 ppc_load_func (code, PPC_CALL_REG, 0);
5551 ppc_mtctr (code, PPC_CALL_REG);
5552 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5564 cfg->code_len = code - cfg->native_code;
5566 g_assert (cfg->code_len <= cfg->code_size);
5572 try_offset_access (void *value, guint32 idx)
5574 register void* me __asm__ ("r2");
5575 void ***p = (void***)((char*)me + 284);
5576 int idx1 = idx / 32;
5577 int idx2 = idx % 32;
5580 if (value != p[idx1][idx2])
5587 setup_tls_access (void)
5589 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5590 size_t conf_size = 0;
5593 /* FIXME for darwin */
5594 guint32 *ins, *code;
5595 guint32 cmplwi_1023, li_0x48, blr_ins;
5599 tls_mode = TLS_MODE_FAILED;
5602 if (tls_mode == TLS_MODE_FAILED)
5604 if (g_getenv ("MONO_NO_TLS")) {
5605 tls_mode = TLS_MODE_FAILED;
5609 if (tls_mode == TLS_MODE_DETECT) {
5610 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5611 tls_mode = TLS_MODE_DARWIN_G4;
5612 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5613 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5614 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5615 tls_mode = TLS_MODE_NPTL;
5616 #elif !defined(TARGET_PS3)
5617 ins = (guint32*)pthread_getspecific;
5618 /* uncond branch to the real method */
5619 if ((*ins >> 26) == 18) {
5621 val = (*ins & ~3) << 6;
5625 ins = (guint32*)(long)val;
5627 ins = (guint32*) ((char*)ins + val);
5630 code = &cmplwi_1023;
5631 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5633 ppc_li (code, ppc_r4, 0x48);
5636 if (*ins == cmplwi_1023) {
5637 int found_lwz_284 = 0;
5639 for (ptk = 0; ptk < 20; ++ptk) {
5641 if (!*ins || *ins == blr_ins)
5643 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5648 if (!found_lwz_284) {
5649 tls_mode = TLS_MODE_FAILED;
5652 tls_mode = TLS_MODE_LTHREADS;
5653 } else if (*ins == li_0x48) {
5655 /* uncond branch to the real method */
5656 if ((*ins >> 26) == 18) {
5658 val = (*ins & ~3) << 6;
5662 ins = (guint32*)(long)val;
5664 ins = (guint32*) ((char*)ins + val);
5666 code = (guint32*)&val;
5667 ppc_li (code, ppc_r0, 0x7FF2);
5668 if (ins [1] == val) {
5669 /* Darwin on G4, implement */
5670 tls_mode = TLS_MODE_FAILED;
5673 code = (guint32*)&val;
5674 ppc_mfspr (code, ppc_r3, 104);
5675 if (ins [1] != val) {
5676 tls_mode = TLS_MODE_FAILED;
5679 tls_mode = TLS_MODE_DARWIN_G5;
5682 tls_mode = TLS_MODE_FAILED;
5686 tls_mode = TLS_MODE_FAILED;
5692 if (tls_mode == TLS_MODE_DETECT)
5693 tls_mode = TLS_MODE_FAILED;
5694 if (tls_mode == TLS_MODE_FAILED)
5696 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5697 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5701 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5702 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5703 if (lmf_pthread_key == -1) {
5704 guint32 ptk = mono_jit_tls_id;
5706 /*g_print ("MonoLMF at: %d\n", ptk);*/
5707 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5708 init_tls_failed = 1;
5711 lmf_pthread_key = ptk;
5720 mono_arch_finish_init (void)
5722 setup_tls_access ();
5726 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5730 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5732 #define LOADSTORE_SIZE 4
5733 #define JUMP_IMM_SIZE 12
5734 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5735 #define ENABLE_WRONG_METHOD_CHECK 0
5738 * LOCKING: called with the domain lock held
5741 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5742 gpointer fail_tramp)
5746 guint8 *code, *start;
5748 for (i = 0; i < count; ++i) {
5749 MonoIMTCheckItem *item = imt_entries [i];
5750 if (item->is_equals) {
5751 if (item->check_target_idx) {
5752 if (!item->compare_done)
5753 item->chunk_size += CMP_SIZE;
5754 if (item->has_target_code)
5755 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5757 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5760 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5761 if (!item->has_target_code)
5762 item->chunk_size += LOADSTORE_SIZE;
5764 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5765 #if ENABLE_WRONG_METHOD_CHECK
5766 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5771 item->chunk_size += CMP_SIZE + BR_SIZE;
5772 imt_entries [item->check_target_idx]->compare_done = TRUE;
5774 size += item->chunk_size;
5776 /* the initial load of the vtable address */
5777 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5779 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5781 code = mono_domain_code_reserve (domain, size);
5786 * We need to save and restore r12 because it might be
5787 * used by the caller as the vtable register, so
5788 * clobbering it will trip up the magic trampoline.
5790 * FIXME: Get rid of this by making sure that r12 is
5791 * not used as the vtable register in interface calls.
5793 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5794 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5796 for (i = 0; i < count; ++i) {
5797 MonoIMTCheckItem *item = imt_entries [i];
5798 item->code_target = code;
5799 if (item->is_equals) {
5800 if (item->check_target_idx) {
5801 if (!item->compare_done) {
5802 ppc_load (code, ppc_r0, (gsize)item->key);
5803 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5805 item->jmp_code = code;
5806 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5807 if (item->has_target_code) {
5808 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5810 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5811 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5813 ppc_mtctr (code, ppc_r0);
5814 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5817 ppc_load (code, ppc_r0, (gulong)item->key);
5818 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5819 item->jmp_code = code;
5820 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5821 if (item->has_target_code) {
5822 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5825 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5826 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5828 ppc_mtctr (code, ppc_r0);
5829 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5830 ppc_patch (item->jmp_code, code);
5831 ppc_load_ptr (code, ppc_r0, fail_tramp);
5832 ppc_mtctr (code, ppc_r0);
5833 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5834 item->jmp_code = NULL;
5836 /* enable the commented code to assert on wrong method */
5837 #if ENABLE_WRONG_METHOD_CHECK
5838 ppc_load (code, ppc_r0, (guint32)item->key);
5839 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5840 item->jmp_code = code;
5841 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5843 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5844 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5845 ppc_mtctr (code, ppc_r0);
5846 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5847 #if ENABLE_WRONG_METHOD_CHECK
5848 ppc_patch (item->jmp_code, code);
5850 item->jmp_code = NULL;
5855 ppc_load (code, ppc_r0, (gulong)item->key);
5856 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5857 item->jmp_code = code;
5858 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5861 /* patch the branches to get to the target items */
5862 for (i = 0; i < count; ++i) {
5863 MonoIMTCheckItem *item = imt_entries [i];
5864 if (item->jmp_code) {
5865 if (item->check_target_idx) {
5866 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5872 mono_stats.imt_thunks_size += code - start;
5873 g_assert (code - start <= size);
5874 mono_arch_flush_icache (start, size);
5876 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5882 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5884 mgreg_t *r = (mgreg_t*)regs;
5886 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5890 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5892 mgreg_t *r = (mgreg_t*)regs;
5894 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5898 mono_arch_get_cie_program (void)
5902 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5908 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5915 mono_arch_print_tree (MonoInst *tree, int arity)
5921 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5924 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5926 g_assert (reg >= ppc_r13);
5928 return ctx->regs [reg - ppc_r13];
5932 mono_arch_get_patch_offset (guint8 *code)
5938 * mono_aot_emit_load_got_addr:
5940 * Emit code to load the got address.
5941 * On PPC, the result is placed into r30.
5944 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5947 ppc_mflr (code, ppc_r30);
5949 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5951 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5952 /* arch_emit_got_address () patches this */
5953 #if defined(TARGET_POWERPC64)
5959 ppc_load32 (code, ppc_r0, 0);
5960 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5967 * mono_ppc_emit_load_aotconst:
5969 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5970 * TARGET from the mscorlib GOT in full-aot code.
5971 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5975 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
5977 /* Load the mscorlib got address */
5978 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5979 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5980 /* arch_emit_got_access () patches this */
5981 ppc_load32 (code, ppc_r0, 0);
5982 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5987 /* Soft Debug support */
5988 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5995 * mono_arch_set_breakpoint:
5997 * See mini-amd64.c for docs.
6000 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6003 guint8 *orig_code = code;
6005 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6006 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6008 g_assert (code - orig_code == BREAKPOINT_SIZE);
6010 mono_arch_flush_icache (orig_code, code - orig_code);
6014 * mono_arch_clear_breakpoint:
6016 * See mini-amd64.c for docs.
6019 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6024 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6027 mono_arch_flush_icache (ip, code - ip);
6031 * mono_arch_is_breakpoint_event:
6033 * See mini-amd64.c for docs.
6036 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6038 siginfo_t* sinfo = (siginfo_t*) info;
6039 /* Sometimes the address is off by 4 */
6040 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6047 * mono_arch_skip_breakpoint:
6049 * See mini-amd64.c for docs.
6052 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6054 /* skip the ldptr */
6055 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6063 * mono_arch_start_single_stepping:
6065 * See mini-amd64.c for docs.
6068 mono_arch_start_single_stepping (void)
6070 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6074 * mono_arch_stop_single_stepping:
6076 * See mini-amd64.c for docs.
6079 mono_arch_stop_single_stepping (void)
6081 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6085 * mono_arch_is_single_step_event:
6087 * See mini-amd64.c for docs.
6090 mono_arch_is_single_step_event (void *info, void *sigctx)
6092 siginfo_t* sinfo = (siginfo_t*) info;
6093 /* Sometimes the address is off by 4 */
6094 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6101 * mono_arch_skip_single_step:
6103 * See mini-amd64.c for docs.
6106 mono_arch_skip_single_step (MonoContext *ctx)
6108 /* skip the ldptr */
6109 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6113 * mono_arch_create_seq_point_info:
6115 * See mini-amd64.c for docs.
6118 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6125 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6127 ext->lmf.previous_lmf = prev_lmf;
6128 /* Mark that this is a MonoLMFExt */
6129 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6130 ext->lmf.ebp = (gssize)ext;
6136 mono_arch_opcode_supported (int opcode)
6139 case OP_ATOMIC_ADD_I4:
6140 case OP_ATOMIC_CAS_I4:
6141 #ifdef TARGET_POWERPC64
6142 case OP_ATOMIC_ADD_I8:
6143 case OP_ATOMIC_CAS_I8:
6153 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6154 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6155 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6158 mono_arch_create_handler_block_trampoline (void)