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 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
910 // Test if a structure is completely composed of either float XOR double fields and has fewer than
911 // PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTER members.
912 // If this is true the structure can be returned directly via float registers instead of by a hidden parameter
913 // pointing to where the return value should be stored.
914 // This is as per the ELF ABI v2.
917 is_float_struct_returnable_via_regs (MonoType *type, int* member_cnt, int* member_size)
919 int local_member_cnt, local_member_size;
921 member_cnt = &local_member_cnt;
924 member_size = &local_member_size;
927 gboolean is_all_floats = mini_type_is_hfa(type, member_cnt, member_size);
928 return is_all_floats && (*member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS);
932 #define is_float_struct_returnable_via_regs(a,b,c) (FALSE)
936 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
938 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
939 // completely composed of fields all of basic types.
940 // If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
941 // pointing to where the return value should be stored.
942 // This is as per the ELF ABI v2.
945 is_struct_returnable_via_regs (MonoClass *klass, gboolean is_pinvoke)
947 gboolean has_a_field = FALSE;
950 gpointer iter = NULL;
953 size = mono_type_native_stack_size (&klass->byval_arg, 0);
955 size = mini_type_stack_size (&klass->byval_arg, 0);
958 if (size > PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS)
960 while ((f = mono_class_get_fields (klass, &iter))) {
961 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
962 // TBD: Is there a better way to check for the basic types?
963 if (f->type->byref) {
965 } else if ((f->type->type >= MONO_TYPE_BOOLEAN) && (f->type->type <= MONO_TYPE_R8)) {
967 } else if (MONO_TYPE_ISSTRUCT (f->type)) {
968 MonoClass *klass = mono_class_from_mono_type (f->type);
969 if (is_struct_returnable_via_regs(klass, is_pinvoke)) {
984 #define is_struct_returnable_via_regs(a,b) (FALSE)
989 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
991 #ifdef __mono_ppc64__
996 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
997 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
998 ainfo->reg = ppc_sp; /* in the caller */
999 ainfo->regtype = RegTypeBase;
1000 *stack_size += sizeof (gpointer);
1002 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
1006 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
1007 #ifdef ALIGN_DOUBLES
1008 //*stack_size += (*stack_size % 8);
1010 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
1011 ainfo->reg = ppc_sp; /* in the caller */
1012 ainfo->regtype = RegTypeBase;
1015 #ifdef ALIGN_DOUBLES
1019 ALWAYS_ON_STACK (*stack_size += 8);
1027 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1029 has_only_a_r48_field (MonoClass *klass)
1033 gboolean have_field = FALSE;
1035 while ((f = mono_class_get_fields (klass, &iter))) {
1036 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1039 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1050 get_call_info (MonoMethodSignature *sig)
1052 guint i, fr, gr, pstart;
1053 int n = sig->hasthis + sig->param_count;
1054 MonoType *simpletype;
1055 guint32 stack_size = 0;
1056 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1057 gboolean is_pinvoke = sig->pinvoke;
1059 fr = PPC_FIRST_FPARG_REG;
1060 gr = PPC_FIRST_ARG_REG;
1062 /* FIXME: handle returning a struct */
1063 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064 cinfo->vtype_retaddr = TRUE;
1070 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1071 * the first argument, allowing 'this' to be always passed in the first arg reg.
1072 * Also do this if the first argument is a reference type, since virtual calls
1073 * are sometimes made using calli without sig->hasthis set, like in the delegate
1076 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1078 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1081 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1085 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1086 cinfo->struct_ret = cinfo->ret.reg;
1087 cinfo->vret_arg_index = 1;
1091 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1095 if (cinfo->vtype_retaddr) {
1096 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1097 cinfo->struct_ret = cinfo->ret.reg;
1101 DEBUG(printf("params: %d\n", sig->param_count));
1102 for (i = pstart; i < sig->param_count; ++i) {
1103 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1104 /* Prevent implicit arguments and sig_cookie from
1105 being passed in registers */
1106 gr = PPC_LAST_ARG_REG + 1;
1107 /* FIXME: don't we have to set fr, too? */
1108 /* Emit the signature cookie just before the implicit arguments */
1109 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1111 DEBUG(printf("param %d: ", i));
1112 if (sig->params [i]->byref) {
1113 DEBUG(printf("byref\n"));
1114 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1118 simpletype = mini_get_underlying_type (sig->params [i]);
1119 switch (simpletype->type) {
1120 case MONO_TYPE_BOOLEAN:
1123 cinfo->args [n].size = 1;
1124 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1127 case MONO_TYPE_CHAR:
1130 cinfo->args [n].size = 2;
1131 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1136 cinfo->args [n].size = 4;
1137 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1143 case MONO_TYPE_FNPTR:
1144 case MONO_TYPE_CLASS:
1145 case MONO_TYPE_OBJECT:
1146 case MONO_TYPE_STRING:
1147 case MONO_TYPE_SZARRAY:
1148 case MONO_TYPE_ARRAY:
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1153 case MONO_TYPE_GENERICINST:
1154 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1155 cinfo->args [n].size = sizeof (gpointer);
1156 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1161 case MONO_TYPE_VALUETYPE:
1162 case MONO_TYPE_TYPEDBYREF: {
1164 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1165 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1166 size = sizeof (MonoTypedRef);
1167 else if (is_pinvoke)
1168 size = mono_class_native_size (klass, NULL);
1170 size = mono_class_value_size (klass, NULL);
1172 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1173 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1174 cinfo->args [n].size = size;
1176 /* It was 7, now it is 8 in LinuxPPC */
1177 if (fr <= PPC_LAST_FPARG_REG) {
1178 cinfo->args [n].regtype = RegTypeFP;
1179 cinfo->args [n].reg = fr;
1181 FP_ALSO_IN_REG (gr ++);
1182 #if !defined(__mono_ppc64__)
1184 FP_ALSO_IN_REG (gr ++);
1186 ALWAYS_ON_STACK (stack_size += size);
1188 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1189 cinfo->args [n].regtype = RegTypeBase;
1190 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1197 DEBUG(printf ("load %d bytes struct\n",
1198 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1200 #if PPC_PASS_STRUCTS_BY_VALUE
1202 int align_size = size;
1204 int rest = PPC_LAST_ARG_REG - gr + 1;
1207 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1210 gboolean is_all_floats = is_float_struct_returnable_via_regs (sig->params [i], &mbr_cnt, &mbr_size);
1212 if (is_all_floats) {
1213 rest = PPC_LAST_FPARG_REG - fr + 1;
1215 // Pass small (<= 8 member) structures entirely made up of either float or double members
1216 // in FR registers. There have to be at least mbr_cnt registers left.
1217 if (is_all_floats &&
1218 (rest >= mbr_cnt)) {
1220 n_in_regs = MIN (rest, nregs);
1221 cinfo->args [n].regtype = RegTypeFPStructByVal;
1222 cinfo->args [n].vtregs = n_in_regs;
1223 cinfo->args [n].size = mbr_size;
1224 cinfo->args [n].vtsize = nregs - n_in_regs;
1225 cinfo->args [n].reg = fr;
1227 if (mbr_size == 4) {
1229 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1232 FP_ALSO_IN_REG (gr += (n_in_regs));
1237 align_size += (sizeof (gpointer) - 1);
1238 align_size &= ~(sizeof (gpointer) - 1);
1239 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1240 n_in_regs = MIN (rest, nregs);
1244 /* FIXME: check this */
1245 if (size >= 3 && size % 4 != 0)
1248 cinfo->args [n].regtype = RegTypeStructByVal;
1249 cinfo->args [n].vtregs = n_in_regs;
1250 cinfo->args [n].size = n_in_regs;
1251 cinfo->args [n].vtsize = nregs - n_in_regs;
1252 cinfo->args [n].reg = gr;
1256 #ifdef __mono_ppc64__
1257 if (nregs == 1 && is_pinvoke)
1258 cinfo->args [n].bytes = size;
1261 cinfo->args [n].bytes = 0;
1262 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1263 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1264 stack_size += nregs * sizeof (gpointer);
1267 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1268 cinfo->args [n].regtype = RegTypeStructByAddr;
1269 cinfo->args [n].vtsize = size;
1276 cinfo->args [n].size = 8;
1277 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1281 cinfo->args [n].size = 4;
1283 /* It was 7, now it is 8 in LinuxPPC */
1284 if (fr <= PPC_LAST_FPARG_REG
1285 // For non-native vararg calls the parms must go in storage
1286 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1288 cinfo->args [n].regtype = RegTypeFP;
1289 cinfo->args [n].reg = fr;
1291 FP_ALSO_IN_REG (gr ++);
1292 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1294 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1295 cinfo->args [n].regtype = RegTypeBase;
1296 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1297 stack_size += SIZEOF_REGISTER;
1302 cinfo->args [n].size = 8;
1303 /* It was 7, now it is 8 in LinuxPPC */
1304 if (fr <= PPC_LAST_FPARG_REG
1305 // For non-native vararg calls the parms must go in storage
1306 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1308 cinfo->args [n].regtype = RegTypeFP;
1309 cinfo->args [n].reg = fr;
1311 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1312 ALWAYS_ON_STACK (stack_size += 8);
1314 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1315 cinfo->args [n].regtype = RegTypeBase;
1316 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1322 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1327 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1328 /* Prevent implicit arguments and sig_cookie from
1329 being passed in registers */
1330 gr = PPC_LAST_ARG_REG + 1;
1331 /* Emit the signature cookie just before the implicit arguments */
1332 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1336 simpletype = mini_get_underlying_type (sig->ret);
1337 switch (simpletype->type) {
1338 case MONO_TYPE_BOOLEAN:
1343 case MONO_TYPE_CHAR:
1349 case MONO_TYPE_FNPTR:
1350 case MONO_TYPE_CLASS:
1351 case MONO_TYPE_OBJECT:
1352 case MONO_TYPE_SZARRAY:
1353 case MONO_TYPE_ARRAY:
1354 case MONO_TYPE_STRING:
1355 cinfo->ret.reg = ppc_r3;
1359 cinfo->ret.reg = ppc_r3;
1363 cinfo->ret.reg = ppc_f1;
1364 cinfo->ret.regtype = RegTypeFP;
1366 case MONO_TYPE_GENERICINST:
1367 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1368 cinfo->ret.reg = ppc_r3;
1372 case MONO_TYPE_VALUETYPE:
1374 case MONO_TYPE_TYPEDBYREF:
1375 case MONO_TYPE_VOID:
1378 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1382 /* align stack size to 16 */
1383 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1384 stack_size = (stack_size + 15) & ~15;
1386 cinfo->stack_usage = stack_size;
1391 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1397 c1 = get_call_info (caller_sig);
1398 c2 = get_call_info (callee_sig);
1399 res = c1->stack_usage >= c2->stack_usage;
1400 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1401 /* An address on the callee's stack is passed as the first argument */
1403 for (i = 0; i < c2->nargs; ++i) {
1404 if (c2->args [i].regtype == RegTypeStructByAddr)
1405 /* An address on the callee's stack is passed as the argument */
1410 if (!mono_debug_count ())
1421 * Set var information according to the calling convention. ppc version.
1422 * The locals var stuff should most likely be split in another method.
1425 mono_arch_allocate_vars (MonoCompile *m)
1427 MonoMethodSignature *sig;
1428 MonoMethodHeader *header;
1430 int i, offset, size, align, curinst;
1431 int frame_reg = ppc_sp;
1433 guint32 locals_stack_size, locals_stack_align;
1435 m->flags |= MONO_CFG_HAS_SPILLUP;
1437 /* allow room for the vararg method args: void* and long/double */
1438 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1439 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1440 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1441 * call convs needs to be handled this way.
1443 if (m->flags & MONO_CFG_HAS_VARARGS)
1444 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1445 /* gtk-sharp and other broken code will dllimport vararg functions even with
1446 * non-varargs signatures. Since there is little hope people will get this right
1447 * we assume they won't.
1449 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1450 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1455 * We use the frame register also for any method that has
1456 * exception clauses. This way, when the handlers are called,
1457 * the code will reference local variables using the frame reg instead of
1458 * the stack pointer: if we had to restore the stack pointer, we'd
1459 * corrupt the method frames that are already on the stack (since
1460 * filters get called before stack unwinding happens) when the filter
1461 * code would call any method (this also applies to finally etc.).
1463 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1464 frame_reg = ppc_r31;
1465 m->frame_reg = frame_reg;
1466 if (frame_reg != ppc_sp) {
1467 m->used_int_regs |= 1 << frame_reg;
1470 sig = mono_method_signature (m->method);
1474 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1475 m->ret->opcode = OP_REGVAR;
1476 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1478 /* FIXME: handle long values? */
1479 switch (mini_get_underlying_type (sig->ret)->type) {
1480 case MONO_TYPE_VOID:
1484 m->ret->opcode = OP_REGVAR;
1485 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1488 m->ret->opcode = OP_REGVAR;
1489 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1493 /* local vars are at a positive offset from the stack pointer */
1495 * also note that if the function uses alloca, we use ppc_r31
1496 * to point at the local variables.
1498 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1499 /* align the offset to 16 bytes: not sure this is needed here */
1501 //offset &= ~(16 - 1);
1503 /* add parameter area size for called functions */
1504 offset += m->param_area;
1506 offset &= ~(16 - 1);
1508 /* allow room to save the return value */
1509 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1512 /* the MonoLMF structure is stored just below the stack pointer */
1515 /* this stuff should not be needed on ppc and the new jit,
1516 * because a call on ppc to the handlers doesn't change the
1517 * stack pointer and the jist doesn't manipulate the stack pointer
1518 * for operations involving valuetypes.
1520 /* reserve space to store the esp */
1521 offset += sizeof (gpointer);
1523 /* this is a global constant */
1524 mono_exc_esp_offset = offset;
1527 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1528 offset += sizeof(gpointer) - 1;
1529 offset &= ~(sizeof(gpointer) - 1);
1531 m->vret_addr->opcode = OP_REGOFFSET;
1532 m->vret_addr->inst_basereg = frame_reg;
1533 m->vret_addr->inst_offset = offset;
1535 if (G_UNLIKELY (m->verbose_level > 1)) {
1536 printf ("vret_addr =");
1537 mono_print_ins (m->vret_addr);
1540 offset += sizeof(gpointer);
1543 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1544 if (locals_stack_align) {
1545 offset += (locals_stack_align - 1);
1546 offset &= ~(locals_stack_align - 1);
1548 for (i = m->locals_start; i < m->num_varinfo; i++) {
1549 if (offsets [i] != -1) {
1550 MonoInst *inst = m->varinfo [i];
1551 inst->opcode = OP_REGOFFSET;
1552 inst->inst_basereg = frame_reg;
1553 inst->inst_offset = offset + offsets [i];
1555 g_print ("allocating local %d (%s) to %d\n",
1556 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1560 offset += locals_stack_size;
1564 inst = m->args [curinst];
1565 if (inst->opcode != OP_REGVAR) {
1566 inst->opcode = OP_REGOFFSET;
1567 inst->inst_basereg = frame_reg;
1568 offset += sizeof (gpointer) - 1;
1569 offset &= ~(sizeof (gpointer) - 1);
1570 inst->inst_offset = offset;
1571 offset += sizeof (gpointer);
1576 for (i = 0; i < sig->param_count; ++i) {
1577 inst = m->args [curinst];
1578 if (inst->opcode != OP_REGVAR) {
1579 inst->opcode = OP_REGOFFSET;
1580 inst->inst_basereg = frame_reg;
1582 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1583 inst->backend.is_pinvoke = 1;
1585 size = mono_type_size (sig->params [i], &align);
1587 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1588 size = align = sizeof (gpointer);
1590 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1591 * they are saved using std in the prolog.
1593 align = sizeof (gpointer);
1594 offset += align - 1;
1595 offset &= ~(align - 1);
1596 inst->inst_offset = offset;
1602 /* some storage for fp conversions */
1605 m->arch.fp_conv_var_offset = offset;
1608 /* align the offset to 16 bytes */
1610 offset &= ~(16 - 1);
1613 m->stack_offset = offset;
1615 if (sig->call_convention == MONO_CALL_VARARG) {
1616 CallInfo *cinfo = get_call_info (m->method->signature);
1618 m->sig_cookie = cinfo->sig_cookie.offset;
1625 mono_arch_create_vars (MonoCompile *cfg)
1627 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1629 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1630 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1634 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1635 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1639 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1641 int sig_reg = mono_alloc_ireg (cfg);
1643 /* FIXME: Add support for signature tokens to AOT */
1644 cfg->disable_aot = TRUE;
1646 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1647 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1648 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1652 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1655 MonoMethodSignature *sig;
1659 sig = call->signature;
1660 n = sig->param_count + sig->hasthis;
1662 cinfo = get_call_info (sig);
1664 for (i = 0; i < n; ++i) {
1665 ArgInfo *ainfo = cinfo->args + i;
1668 if (i >= sig->hasthis)
1669 t = sig->params [i - sig->hasthis];
1671 t = &mono_defaults.int_class->byval_arg;
1672 t = mini_get_underlying_type (t);
1674 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1675 emit_sig_cookie (cfg, call, cinfo);
1677 in = call->args [i];
1679 if (ainfo->regtype == RegTypeGeneral) {
1680 #ifndef __mono_ppc64__
1681 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1682 MONO_INST_NEW (cfg, ins, OP_MOVE);
1683 ins->dreg = mono_alloc_ireg (cfg);
1684 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1685 MONO_ADD_INS (cfg->cbb, ins);
1686 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1688 MONO_INST_NEW (cfg, ins, OP_MOVE);
1689 ins->dreg = mono_alloc_ireg (cfg);
1690 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1691 MONO_ADD_INS (cfg->cbb, ins);
1692 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1696 MONO_INST_NEW (cfg, ins, OP_MOVE);
1697 ins->dreg = mono_alloc_ireg (cfg);
1698 ins->sreg1 = in->dreg;
1699 MONO_ADD_INS (cfg->cbb, ins);
1701 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1703 } else if (ainfo->regtype == RegTypeStructByAddr) {
1704 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1705 ins->opcode = OP_OUTARG_VT;
1706 ins->sreg1 = in->dreg;
1707 ins->klass = in->klass;
1708 ins->inst_p0 = call;
1709 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1710 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1711 MONO_ADD_INS (cfg->cbb, ins);
1712 } else if (ainfo->regtype == RegTypeStructByVal) {
1713 /* this is further handled in mono_arch_emit_outarg_vt () */
1714 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1715 ins->opcode = OP_OUTARG_VT;
1716 ins->sreg1 = in->dreg;
1717 ins->klass = in->klass;
1718 ins->inst_p0 = call;
1719 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1720 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1721 MONO_ADD_INS (cfg->cbb, ins);
1722 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1723 /* this is further handled in mono_arch_emit_outarg_vt () */
1724 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1725 ins->opcode = OP_OUTARG_VT;
1726 ins->sreg1 = in->dreg;
1727 ins->klass = in->klass;
1728 ins->inst_p0 = call;
1729 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1730 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1731 MONO_ADD_INS (cfg->cbb, ins);
1732 cfg->flags |= MONO_CFG_HAS_FPOUT;
1733 } else if (ainfo->regtype == RegTypeBase) {
1734 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1735 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1736 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1737 if (t->type == MONO_TYPE_R8)
1738 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1740 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1742 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1744 } else if (ainfo->regtype == RegTypeFP) {
1745 if (t->type == MONO_TYPE_VALUETYPE) {
1746 /* this is further handled in mono_arch_emit_outarg_vt () */
1747 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1748 ins->opcode = OP_OUTARG_VT;
1749 ins->sreg1 = in->dreg;
1750 ins->klass = in->klass;
1751 ins->inst_p0 = call;
1752 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1753 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1754 MONO_ADD_INS (cfg->cbb, ins);
1756 cfg->flags |= MONO_CFG_HAS_FPOUT;
1758 int dreg = mono_alloc_freg (cfg);
1760 if (ainfo->size == 4) {
1761 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1763 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1765 ins->sreg1 = in->dreg;
1766 MONO_ADD_INS (cfg->cbb, ins);
1769 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1770 cfg->flags |= MONO_CFG_HAS_FPOUT;
1773 g_assert_not_reached ();
1777 /* Emit the signature cookie in the case that there is no
1778 additional argument */
1779 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1780 emit_sig_cookie (cfg, call, cinfo);
1782 if (cinfo->struct_ret) {
1785 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1786 vtarg->sreg1 = call->vret_var->dreg;
1787 vtarg->dreg = mono_alloc_preg (cfg);
1788 MONO_ADD_INS (cfg->cbb, vtarg);
1790 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1793 call->stack_usage = cinfo->stack_usage;
1794 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1795 cfg->flags |= MONO_CFG_HAS_CALLS;
1803 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1805 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1806 ArgInfo *ainfo = ins->inst_p1;
1807 int ovf_size = ainfo->vtsize;
1808 int doffset = ainfo->offset;
1809 int i, soffset, dreg;
1811 if (ainfo->regtype == RegTypeStructByVal) {
1818 * Darwin pinvokes needs some special handling for 1
1819 * and 2 byte arguments
1821 g_assert (ins->klass);
1822 if (call->signature->pinvoke)
1823 size = mono_class_native_size (ins->klass, NULL);
1824 if (size == 2 || size == 1) {
1825 int tmpr = mono_alloc_ireg (cfg);
1827 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1829 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1830 dreg = mono_alloc_ireg (cfg);
1831 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1832 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1835 for (i = 0; i < ainfo->vtregs; ++i) {
1836 dreg = mono_alloc_ireg (cfg);
1837 #if G_BYTE_ORDER == G_BIG_ENDIAN
1838 int antipadding = 0;
1841 antipadding = sizeof (gpointer) - ainfo->bytes;
1843 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1845 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1847 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1849 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1850 soffset += sizeof (gpointer);
1853 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1854 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1856 for (i = 0; i < ainfo->vtregs; ++i) {
1857 int tmpr = mono_alloc_freg (cfg);
1858 if (ainfo->size == 4)
1859 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1861 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1862 dreg = mono_alloc_freg (cfg);
1863 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1864 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1865 soffset += ainfo->size;
1868 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1869 } else if (ainfo->regtype == RegTypeFP) {
1870 int tmpr = mono_alloc_freg (cfg);
1871 if (ainfo->size == 4)
1872 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1874 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1875 dreg = mono_alloc_freg (cfg);
1876 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1877 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1879 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1883 /* FIXME: alignment? */
1884 if (call->signature->pinvoke) {
1885 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1886 vtcopy->backend.is_pinvoke = 1;
1888 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1891 g_assert (ovf_size > 0);
1893 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1894 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1897 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1899 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1904 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1906 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1908 #ifndef __mono_ppc64__
1909 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1912 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1913 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1914 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1915 MONO_ADD_INS (cfg->cbb, ins);
1919 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1920 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1924 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1927 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1929 mono_arch_is_inst_imm (gint64 imm)
1934 #endif /* DISABLE_JIT */
1937 * Allow tracing to work with this interface (with an optional argument)
1941 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1945 ppc_load_ptr (code, ppc_r3, cfg->method);
1946 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1947 ppc_load_func (code, PPC_CALL_REG, func);
1948 ppc_mtlr (code, PPC_CALL_REG);
1962 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1965 int save_mode = SAVE_NONE;
1967 MonoMethod *method = cfg->method;
1968 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
1969 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1973 offset = code - cfg->native_code;
1974 /* we need about 16 instructions */
1975 if (offset > (cfg->code_size - 16 * 4)) {
1976 cfg->code_size *= 2;
1977 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1978 code = cfg->native_code + offset;
1982 case MONO_TYPE_VOID:
1983 /* special case string .ctor icall */
1984 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1985 save_mode = SAVE_ONE;
1987 save_mode = SAVE_NONE;
1989 #ifndef __mono_ppc64__
1992 save_mode = SAVE_TWO;
1997 save_mode = SAVE_FP;
1999 case MONO_TYPE_VALUETYPE:
2000 save_mode = SAVE_STRUCT;
2003 save_mode = SAVE_ONE;
2007 switch (save_mode) {
2009 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
2010 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2011 if (enable_arguments) {
2012 ppc_mr (code, ppc_r5, ppc_r4);
2013 ppc_mr (code, ppc_r4, ppc_r3);
2017 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
2018 if (enable_arguments) {
2019 ppc_mr (code, ppc_r4, ppc_r3);
2023 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
2024 if (enable_arguments) {
2025 /* FIXME: what reg? */
2026 ppc_fmr (code, ppc_f3, ppc_f1);
2027 /* FIXME: use 8 byte load on PPC64 */
2028 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
2029 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
2033 if (enable_arguments) {
2034 /* FIXME: get the actual address */
2035 ppc_mr (code, ppc_r4, ppc_r3);
2036 // FIXME: Support the new v2 ABI!
2044 ppc_load_ptr (code, ppc_r3, cfg->method);
2045 ppc_load_func (code, PPC_CALL_REG, func);
2046 ppc_mtlr (code, PPC_CALL_REG);
2049 switch (save_mode) {
2051 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
2052 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2055 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
2058 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
2068 * Conditional branches have a small offset, so if it is likely overflowed,
2069 * we do a branch to the end of the method (uncond branches have much larger
2070 * offsets) where we perform the conditional and jump back unconditionally.
2071 * It's slightly slower, since we add two uncond branches, but it's very simple
2072 * with the current patch implementation and such large methods are likely not
2073 * going to be perf critical anyway.
2078 const char *exception;
2085 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
2086 if (0 && ins->inst_true_bb->native_offset) { \
2087 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
2089 int br_disp = ins->inst_true_bb->max_offset - offset; \
2090 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2091 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2092 ovfj->data.bb = ins->inst_true_bb; \
2093 ovfj->ip_offset = 0; \
2094 ovfj->b0_cond = (b0); \
2095 ovfj->b1_cond = (b1); \
2096 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
2099 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2100 ppc_bc (code, (b0), (b1), 0); \
2104 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
2106 /* emit an exception if condition is fail
2108 * We assign the extra code used to throw the implicit exceptions
2109 * to cfg->bb_exit as far as the big branch handling is concerned
2111 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2113 int br_disp = cfg->bb_exit->max_offset - offset; \
2114 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2115 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2116 ovfj->data.exception = (exc_name); \
2117 ovfj->ip_offset = code - cfg->native_code; \
2118 ovfj->b0_cond = (b0); \
2119 ovfj->b1_cond = (b1); \
2120 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2122 cfg->bb_exit->max_offset += 24; \
2124 mono_add_patch_info (cfg, code - cfg->native_code, \
2125 MONO_PATCH_INFO_EXC, exc_name); \
2126 ppc_bcl (code, (b0), (b1), 0); \
2130 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2133 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2138 normalize_opcode (int opcode)
2141 #ifndef __mono_ilp32__
2142 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2143 return OP_LOAD_MEMBASE;
2144 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2145 return OP_LOAD_MEMINDEX;
2146 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2147 return OP_STORE_MEMBASE_REG;
2148 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2149 return OP_STORE_MEMBASE_IMM;
2150 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2151 return OP_STORE_MEMINDEX;
2153 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2155 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2156 return OP_SHR_UN_IMM;
2163 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2165 MonoInst *ins, *n, *last_ins = NULL;
2167 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2168 switch (normalize_opcode (ins->opcode)) {
2170 /* remove unnecessary multiplication with 1 */
2171 if (ins->inst_imm == 1) {
2172 if (ins->dreg != ins->sreg1) {
2173 ins->opcode = OP_MOVE;
2175 MONO_DELETE_INS (bb, ins);
2179 int power2 = mono_is_power_of_two (ins->inst_imm);
2181 ins->opcode = OP_SHL_IMM;
2182 ins->inst_imm = power2;
2186 case OP_LOAD_MEMBASE:
2188 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2189 * OP_LOAD_MEMBASE offset(basereg), reg
2191 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2192 ins->inst_basereg == last_ins->inst_destbasereg &&
2193 ins->inst_offset == last_ins->inst_offset) {
2194 if (ins->dreg == last_ins->sreg1) {
2195 MONO_DELETE_INS (bb, ins);
2198 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2199 ins->opcode = OP_MOVE;
2200 ins->sreg1 = last_ins->sreg1;
2204 * Note: reg1 must be different from the basereg in the second load
2205 * OP_LOAD_MEMBASE offset(basereg), reg1
2206 * OP_LOAD_MEMBASE offset(basereg), reg2
2208 * OP_LOAD_MEMBASE offset(basereg), reg1
2209 * OP_MOVE reg1, reg2
2211 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2212 ins->inst_basereg != last_ins->dreg &&
2213 ins->inst_basereg == last_ins->inst_basereg &&
2214 ins->inst_offset == last_ins->inst_offset) {
2216 if (ins->dreg == last_ins->dreg) {
2217 MONO_DELETE_INS (bb, ins);
2220 ins->opcode = OP_MOVE;
2221 ins->sreg1 = last_ins->dreg;
2224 //g_assert_not_reached ();
2228 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2229 * OP_LOAD_MEMBASE offset(basereg), reg
2231 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2232 * OP_ICONST reg, imm
2234 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2235 ins->inst_basereg == last_ins->inst_destbasereg &&
2236 ins->inst_offset == last_ins->inst_offset) {
2237 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2238 ins->opcode = OP_ICONST;
2239 ins->inst_c0 = last_ins->inst_imm;
2240 g_assert_not_reached (); // check this rule
2244 case OP_LOADU1_MEMBASE:
2245 case OP_LOADI1_MEMBASE:
2246 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2247 ins->inst_basereg == last_ins->inst_destbasereg &&
2248 ins->inst_offset == last_ins->inst_offset) {
2249 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2250 ins->sreg1 = last_ins->sreg1;
2253 case OP_LOADU2_MEMBASE:
2254 case OP_LOADI2_MEMBASE:
2255 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2256 ins->inst_basereg == last_ins->inst_destbasereg &&
2257 ins->inst_offset == last_ins->inst_offset) {
2258 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2259 ins->sreg1 = last_ins->sreg1;
2262 #ifdef __mono_ppc64__
2263 case OP_LOADU4_MEMBASE:
2264 case OP_LOADI4_MEMBASE:
2265 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2266 ins->inst_basereg == last_ins->inst_destbasereg &&
2267 ins->inst_offset == last_ins->inst_offset) {
2268 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2269 ins->sreg1 = last_ins->sreg1;
2274 ins->opcode = OP_MOVE;
2278 if (ins->dreg == ins->sreg1) {
2279 MONO_DELETE_INS (bb, ins);
2283 * OP_MOVE sreg, dreg
2284 * OP_MOVE dreg, sreg
2286 if (last_ins && last_ins->opcode == OP_MOVE &&
2287 ins->sreg1 == last_ins->dreg &&
2288 ins->dreg == last_ins->sreg1) {
2289 MONO_DELETE_INS (bb, ins);
2297 bb->last_ins = last_ins;
2301 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2303 switch (ins->opcode) {
2304 case OP_ICONV_TO_R_UN: {
2305 // This value is OK as-is for both big and little endian because of how it is stored
2306 static const guint64 adjust_val = 0x4330000000000000ULL;
2307 int msw_reg = mono_alloc_ireg (cfg);
2308 int adj_reg = mono_alloc_freg (cfg);
2309 int tmp_reg = mono_alloc_freg (cfg);
2310 int basereg = ppc_sp;
2312 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2313 if (!ppc_is_imm16 (offset + 4)) {
2314 basereg = mono_alloc_ireg (cfg);
2315 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2317 #if G_BYTE_ORDER == G_BIG_ENDIAN
2318 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2319 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2321 // For little endian the words are reversed
2322 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2323 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2325 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2326 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2327 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2328 ins->opcode = OP_NOP;
2331 #ifndef __mono_ppc64__
2332 case OP_ICONV_TO_R4:
2333 case OP_ICONV_TO_R8: {
2334 /* If we have a PPC_FEATURE_64 machine we can avoid
2335 this and use the fcfid instruction. Otherwise
2336 on an old 32-bit chip and we have to do this the
2338 if (!(cpu_hw_caps & PPC_ISA_64)) {
2339 /* FIXME: change precision for CEE_CONV_R4 */
2340 static const guint64 adjust_val = 0x4330000080000000ULL;
2341 int msw_reg = mono_alloc_ireg (cfg);
2342 int xored = mono_alloc_ireg (cfg);
2343 int adj_reg = mono_alloc_freg (cfg);
2344 int tmp_reg = mono_alloc_freg (cfg);
2345 int basereg = ppc_sp;
2347 if (!ppc_is_imm16 (offset + 4)) {
2348 basereg = mono_alloc_ireg (cfg);
2349 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2351 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2352 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2353 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2354 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2355 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2356 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2358 if (ins->opcode == OP_ICONV_TO_R4)
2359 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2360 ins->opcode = OP_NOP;
2366 int msw_reg = mono_alloc_ireg (cfg);
2367 int basereg = ppc_sp;
2369 if (!ppc_is_imm16 (offset + 4)) {
2370 basereg = mono_alloc_ireg (cfg);
2371 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2374 #if G_BYTE_ORDER == G_BIG_ENDIAN
2375 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2377 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2379 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2380 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2381 ins->opcode = OP_NOP;
2384 #ifdef __mono_ppc64__
2386 case OP_IADD_OVF_UN:
2388 int shifted1_reg = mono_alloc_ireg (cfg);
2389 int shifted2_reg = mono_alloc_ireg (cfg);
2390 int result_shifted_reg = mono_alloc_ireg (cfg);
2392 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2393 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2394 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2395 if (ins->opcode == OP_IADD_OVF_UN)
2396 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2398 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2399 ins->opcode = OP_NOP;
2409 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2411 switch (ins->opcode) {
2413 /* ADC sets the condition code */
2414 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2415 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2418 case OP_LADD_OVF_UN:
2419 /* ADC sets the condition code */
2420 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2421 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2425 /* SBB sets the condition code */
2426 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2427 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2430 case OP_LSUB_OVF_UN:
2431 /* SBB sets the condition code */
2432 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), MONO_LVREG_LS (ins->sreg2));
2433 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), MONO_LVREG_MS (ins->sreg2));
2437 /* From gcc generated code */
2438 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
2439 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1));
2448 * the branch_b0_table should maintain the order of these
2462 branch_b0_table [] = {
2477 branch_b1_table [] = {
2491 #define NEW_INS(cfg,dest,op) do { \
2492 MONO_INST_NEW((cfg), (dest), (op)); \
2493 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2497 map_to_reg_reg_op (int op)
2506 case OP_COMPARE_IMM:
2508 case OP_ICOMPARE_IMM:
2510 case OP_LCOMPARE_IMM:
2526 case OP_LOAD_MEMBASE:
2527 return OP_LOAD_MEMINDEX;
2528 case OP_LOADI4_MEMBASE:
2529 return OP_LOADI4_MEMINDEX;
2530 case OP_LOADU4_MEMBASE:
2531 return OP_LOADU4_MEMINDEX;
2532 case OP_LOADI8_MEMBASE:
2533 return OP_LOADI8_MEMINDEX;
2534 case OP_LOADU1_MEMBASE:
2535 return OP_LOADU1_MEMINDEX;
2536 case OP_LOADI2_MEMBASE:
2537 return OP_LOADI2_MEMINDEX;
2538 case OP_LOADU2_MEMBASE:
2539 return OP_LOADU2_MEMINDEX;
2540 case OP_LOADI1_MEMBASE:
2541 return OP_LOADI1_MEMINDEX;
2542 case OP_LOADR4_MEMBASE:
2543 return OP_LOADR4_MEMINDEX;
2544 case OP_LOADR8_MEMBASE:
2545 return OP_LOADR8_MEMINDEX;
2546 case OP_STOREI1_MEMBASE_REG:
2547 return OP_STOREI1_MEMINDEX;
2548 case OP_STOREI2_MEMBASE_REG:
2549 return OP_STOREI2_MEMINDEX;
2550 case OP_STOREI4_MEMBASE_REG:
2551 return OP_STOREI4_MEMINDEX;
2552 case OP_STOREI8_MEMBASE_REG:
2553 return OP_STOREI8_MEMINDEX;
2554 case OP_STORE_MEMBASE_REG:
2555 return OP_STORE_MEMINDEX;
2556 case OP_STORER4_MEMBASE_REG:
2557 return OP_STORER4_MEMINDEX;
2558 case OP_STORER8_MEMBASE_REG:
2559 return OP_STORER8_MEMINDEX;
2560 case OP_STORE_MEMBASE_IMM:
2561 return OP_STORE_MEMBASE_REG;
2562 case OP_STOREI1_MEMBASE_IMM:
2563 return OP_STOREI1_MEMBASE_REG;
2564 case OP_STOREI2_MEMBASE_IMM:
2565 return OP_STOREI2_MEMBASE_REG;
2566 case OP_STOREI4_MEMBASE_IMM:
2567 return OP_STOREI4_MEMBASE_REG;
2568 case OP_STOREI8_MEMBASE_IMM:
2569 return OP_STOREI8_MEMBASE_REG;
2571 if (mono_op_imm_to_op (op) == -1)
2572 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2573 return mono_op_imm_to_op (op);
2576 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2578 #define compare_opcode_is_unsigned(opcode) \
2579 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2580 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2581 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2582 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2583 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2584 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2585 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2586 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2589 * Remove from the instruction list the instructions that can't be
2590 * represented with very simple instructions with no register
2594 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2596 MonoInst *ins, *next, *temp, *last_ins = NULL;
2599 MONO_BB_FOR_EACH_INS (bb, ins) {
2601 switch (ins->opcode) {
2602 case OP_IDIV_UN_IMM:
2605 case OP_IREM_UN_IMM:
2606 CASE_PPC64 (OP_LREM_IMM) {
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 if (ins->opcode == OP_IDIV_IMM)
2612 ins->opcode = OP_IDIV;
2613 else if (ins->opcode == OP_IREM_IMM)
2614 ins->opcode = OP_IREM;
2615 else if (ins->opcode == OP_IDIV_UN_IMM)
2616 ins->opcode = OP_IDIV_UN;
2617 else if (ins->opcode == OP_IREM_UN_IMM)
2618 ins->opcode = OP_IREM_UN;
2619 else if (ins->opcode == OP_LREM_IMM)
2620 ins->opcode = OP_LREM;
2622 /* handle rem separately */
2627 CASE_PPC64 (OP_LREM)
2628 CASE_PPC64 (OP_LREM_UN) {
2630 /* we change a rem dest, src1, src2 to
2631 * div temp1, src1, src2
2632 * mul temp2, temp1, src2
2633 * sub dest, src1, temp2
2635 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2636 NEW_INS (cfg, mul, OP_IMUL);
2637 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2638 ins->opcode = OP_ISUB;
2640 NEW_INS (cfg, mul, OP_LMUL);
2641 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2642 ins->opcode = OP_LSUB;
2644 temp->sreg1 = ins->sreg1;
2645 temp->sreg2 = ins->sreg2;
2646 temp->dreg = mono_alloc_ireg (cfg);
2647 mul->sreg1 = temp->dreg;
2648 mul->sreg2 = ins->sreg2;
2649 mul->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg2 = mul->dreg;
2654 CASE_PPC64 (OP_LADD_IMM)
2657 if (!ppc_is_imm16 (ins->inst_imm)) {
2658 NEW_INS (cfg, temp, OP_ICONST);
2659 temp->inst_c0 = ins->inst_imm;
2660 temp->dreg = mono_alloc_ireg (cfg);
2661 ins->sreg2 = temp->dreg;
2662 ins->opcode = map_to_reg_reg_op (ins->opcode);
2666 CASE_PPC64 (OP_LSUB_IMM)
2668 if (!ppc_is_imm16 (-ins->inst_imm)) {
2669 NEW_INS (cfg, temp, OP_ICONST);
2670 temp->inst_c0 = ins->inst_imm;
2671 temp->dreg = mono_alloc_ireg (cfg);
2672 ins->sreg2 = temp->dreg;
2673 ins->opcode = map_to_reg_reg_op (ins->opcode);
2685 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2686 #ifdef __mono_ppc64__
2687 if (ins->inst_imm & 0xffffffff00000000ULL)
2691 NEW_INS (cfg, temp, OP_ICONST);
2692 temp->inst_c0 = ins->inst_imm;
2693 temp->dreg = mono_alloc_ireg (cfg);
2694 ins->sreg2 = temp->dreg;
2695 ins->opcode = map_to_reg_reg_op (ins->opcode);
2704 NEW_INS (cfg, temp, OP_ICONST);
2705 temp->inst_c0 = ins->inst_imm;
2706 temp->dreg = mono_alloc_ireg (cfg);
2707 ins->sreg2 = temp->dreg;
2708 ins->opcode = map_to_reg_reg_op (ins->opcode);
2710 case OP_COMPARE_IMM:
2711 case OP_ICOMPARE_IMM:
2712 CASE_PPC64 (OP_LCOMPARE_IMM)
2714 /* Branch opts can eliminate the branch */
2715 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2716 ins->opcode = OP_NOP;
2720 if (compare_opcode_is_unsigned (next->opcode)) {
2721 if (!ppc_is_uimm16 (ins->inst_imm)) {
2722 NEW_INS (cfg, temp, OP_ICONST);
2723 temp->inst_c0 = ins->inst_imm;
2724 temp->dreg = mono_alloc_ireg (cfg);
2725 ins->sreg2 = temp->dreg;
2726 ins->opcode = map_to_reg_reg_op (ins->opcode);
2729 if (!ppc_is_imm16 (ins->inst_imm)) {
2730 NEW_INS (cfg, temp, OP_ICONST);
2731 temp->inst_c0 = ins->inst_imm;
2732 temp->dreg = mono_alloc_ireg (cfg);
2733 ins->sreg2 = temp->dreg;
2734 ins->opcode = map_to_reg_reg_op (ins->opcode);
2740 if (ins->inst_imm == 1) {
2741 ins->opcode = OP_MOVE;
2744 if (ins->inst_imm == 0) {
2745 ins->opcode = OP_ICONST;
2749 imm = mono_is_power_of_two (ins->inst_imm);
2751 ins->opcode = OP_SHL_IMM;
2752 ins->inst_imm = imm;
2755 if (!ppc_is_imm16 (ins->inst_imm)) {
2756 NEW_INS (cfg, temp, OP_ICONST);
2757 temp->inst_c0 = ins->inst_imm;
2758 temp->dreg = mono_alloc_ireg (cfg);
2759 ins->sreg2 = temp->dreg;
2760 ins->opcode = map_to_reg_reg_op (ins->opcode);
2763 case OP_LOCALLOC_IMM:
2764 NEW_INS (cfg, temp, OP_ICONST);
2765 temp->inst_c0 = ins->inst_imm;
2766 temp->dreg = mono_alloc_ireg (cfg);
2767 ins->sreg1 = temp->dreg;
2768 ins->opcode = OP_LOCALLOC;
2770 case OP_LOAD_MEMBASE:
2771 case OP_LOADI4_MEMBASE:
2772 CASE_PPC64 (OP_LOADI8_MEMBASE)
2773 case OP_LOADU4_MEMBASE:
2774 case OP_LOADI2_MEMBASE:
2775 case OP_LOADU2_MEMBASE:
2776 case OP_LOADI1_MEMBASE:
2777 case OP_LOADU1_MEMBASE:
2778 case OP_LOADR4_MEMBASE:
2779 case OP_LOADR8_MEMBASE:
2780 case OP_STORE_MEMBASE_REG:
2781 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2782 case OP_STOREI4_MEMBASE_REG:
2783 case OP_STOREI2_MEMBASE_REG:
2784 case OP_STOREI1_MEMBASE_REG:
2785 case OP_STORER4_MEMBASE_REG:
2786 case OP_STORER8_MEMBASE_REG:
2787 /* we can do two things: load the immed in a register
2788 * and use an indexed load, or see if the immed can be
2789 * represented as an ad_imm + a load with a smaller offset
2790 * that fits. We just do the first for now, optimize later.
2792 if (ppc_is_imm16 (ins->inst_offset))
2794 NEW_INS (cfg, temp, OP_ICONST);
2795 temp->inst_c0 = ins->inst_offset;
2796 temp->dreg = mono_alloc_ireg (cfg);
2797 ins->sreg2 = temp->dreg;
2798 ins->opcode = map_to_reg_reg_op (ins->opcode);
2800 case OP_STORE_MEMBASE_IMM:
2801 case OP_STOREI1_MEMBASE_IMM:
2802 case OP_STOREI2_MEMBASE_IMM:
2803 case OP_STOREI4_MEMBASE_IMM:
2804 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2805 NEW_INS (cfg, temp, OP_ICONST);
2806 temp->inst_c0 = ins->inst_imm;
2807 temp->dreg = mono_alloc_ireg (cfg);
2808 ins->sreg1 = temp->dreg;
2809 ins->opcode = map_to_reg_reg_op (ins->opcode);
2811 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2814 if (cfg->compile_aot) {
2815 /* Keep these in the aot case */
2818 NEW_INS (cfg, temp, OP_ICONST);
2819 temp->inst_c0 = (gulong)ins->inst_p0;
2820 temp->dreg = mono_alloc_ireg (cfg);
2821 ins->inst_basereg = temp->dreg;
2822 ins->inst_offset = 0;
2823 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2825 /* make it handle the possibly big ins->inst_offset
2826 * later optimize to use lis + load_membase
2832 bb->last_ins = last_ins;
2833 bb->max_vreg = cfg->next_vreg;
2837 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2839 long offset = cfg->arch.fp_conv_var_offset;
2841 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2842 #ifdef __mono_ppc64__
2844 ppc_fctidz (code, ppc_f0, sreg);
2849 ppc_fctiwz (code, ppc_f0, sreg);
2852 if (ppc_is_imm16 (offset + sub_offset)) {
2853 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2855 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2857 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2859 ppc_load (code, dreg, offset);
2860 ppc_add (code, dreg, dreg, cfg->frame_reg);
2861 ppc_stfd (code, ppc_f0, 0, dreg);
2863 ppc_ldr (code, dreg, sub_offset, dreg);
2865 ppc_lwz (code, dreg, sub_offset, dreg);
2869 ppc_andid (code, dreg, dreg, 0xff);
2871 ppc_andid (code, dreg, dreg, 0xffff);
2872 #ifdef __mono_ppc64__
2874 ppc_clrldi (code, dreg, dreg, 32);
2878 ppc_extsb (code, dreg, dreg);
2880 ppc_extsh (code, dreg, dreg);
2881 #ifdef __mono_ppc64__
2883 ppc_extsw (code, dreg, dreg);
2891 const guchar *target;
2896 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2899 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2900 #ifdef __mono_ppc64__
2901 g_assert_not_reached ();
2903 PatchData *pdata = (PatchData*)user_data;
2904 guchar *code = data;
2905 guint32 *thunks = data;
2906 guint32 *endthunks = (guint32*)(code + bsize);
2910 int difflow, diffhigh;
2912 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2913 difflow = (char*)pdata->code - (char*)thunks;
2914 diffhigh = (char*)pdata->code - (char*)endthunks;
2915 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2918 templ = (guchar*)load;
2919 ppc_load_sequence (templ, ppc_r0, pdata->target);
2921 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2922 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2923 while (thunks < endthunks) {
2924 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2925 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2926 ppc_patch (pdata->code, (guchar*)thunks);
2929 static int num_thunks = 0;
2931 if ((num_thunks % 20) == 0)
2932 g_print ("num_thunks lookup: %d\n", num_thunks);
2935 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2936 /* found a free slot instead: emit thunk */
2937 code = (guchar*)thunks;
2938 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2939 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2940 ppc_mtctr (code, ppc_r0);
2941 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2942 mono_arch_flush_icache ((guchar*)thunks, 16);
2944 ppc_patch (pdata->code, (guchar*)thunks);
2947 static int num_thunks = 0;
2949 if ((num_thunks % 20) == 0)
2950 g_print ("num_thunks: %d\n", num_thunks);
2954 /* skip 16 bytes, the size of the thunk */
2958 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2965 handle_thunk (int absolute, guchar *code, const guchar *target) {
2966 MonoDomain *domain = mono_domain_get ();
2970 pdata.target = target;
2971 pdata.absolute = absolute;
2974 mono_domain_lock (domain);
2975 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2978 /* this uses the first available slot */
2980 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2982 mono_domain_unlock (domain);
2984 if (pdata.found != 1)
2985 g_print ("thunk failed for %p from %p\n", target, code);
2986 g_assert (pdata.found == 1);
2990 patch_ins (guint8 *code, guint32 ins)
2992 *(guint32*)code = ins;
2993 mono_arch_flush_icache (code, 4);
2997 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2999 guint32 ins = *(guint32*)code;
3000 guint32 prim = ins >> 26;
3003 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3005 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
3006 gint diff = target - code;
3009 if (diff <= 33554431){
3010 ins = (18 << 26) | (diff) | (ins & 1);
3011 patch_ins (code, ins);
3015 /* diff between 0 and -33554432 */
3016 if (diff >= -33554432){
3017 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
3018 patch_ins (code, ins);
3023 if ((glong)target >= 0){
3024 if ((glong)target <= 33554431){
3025 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
3026 patch_ins (code, ins);
3030 if ((glong)target >= -33554432){
3031 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
3032 patch_ins (code, ins);
3037 handle_thunk (TRUE, code, target);
3040 g_assert_not_reached ();
3048 guint32 li = (gulong)target;
3049 ins = (ins & 0xffff0000) | (ins & 3);
3050 ovf = li & 0xffff0000;
3051 if (ovf != 0 && ovf != 0xffff0000)
3052 g_assert_not_reached ();
3055 // FIXME: assert the top bits of li are 0
3057 gint diff = target - code;
3058 ins = (ins & 0xffff0000) | (ins & 3);
3059 ovf = diff & 0xffff0000;
3060 if (ovf != 0 && ovf != 0xffff0000)
3061 g_assert_not_reached ();
3065 patch_ins (code, ins);
3069 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3070 #ifdef __mono_ppc64__
3071 guint32 *seq = (guint32*)code;
3072 guint32 *branch_ins;
3074 /* the trampoline code will try to patch the blrl, blr, bcctr */
3075 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3077 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
3082 if (ppc_is_load_op (seq [5])
3083 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3084 /* With function descs we need to do more careful
3086 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3089 branch_ins = seq + 8;
3091 branch_ins = seq + 6;
3094 seq = (guint32*)code;
3095 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3096 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3098 if (ppc_is_load_op (seq [5])) {
3099 g_assert (ppc_is_load_op (seq [6]));
3102 guint8 *buf = (guint8*)&seq [5];
3103 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3108 target = mono_get_addr_from_ftnptr ((gpointer)target);
3111 /* FIXME: make this thread safe */
3112 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3113 /* FIXME: we're assuming we're using r12 here */
3114 ppc_load_ptr_sequence (code, ppc_r12, target);
3116 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3118 mono_arch_flush_icache ((guint8*)seq, 28);
3121 /* the trampoline code will try to patch the blrl, blr, bcctr */
3122 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3125 /* this is the lis/ori/mtlr/blrl sequence */
3126 seq = (guint32*)code;
3127 g_assert ((seq [0] >> 26) == 15);
3128 g_assert ((seq [1] >> 26) == 24);
3129 g_assert ((seq [2] >> 26) == 31);
3130 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3131 /* FIXME: make this thread safe */
3132 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3133 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3134 mono_arch_flush_icache (code - 8, 8);
3137 g_assert_not_reached ();
3139 // g_print ("patched with 0x%08x\n", ins);
3143 ppc_patch (guchar *code, const guchar *target)
3145 ppc_patch_full (code, target, FALSE);
3149 mono_ppc_patch (guchar *code, const guchar *target)
3151 ppc_patch (code, target);
3155 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3157 switch (ins->opcode) {
3160 case OP_FCALL_MEMBASE:
3161 if (ins->dreg != ppc_f1)
3162 ppc_fmr (code, ins->dreg, ppc_f1);
3170 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3172 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3176 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3178 long size = cfg->param_area;
3180 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3181 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3186 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3187 if (ppc_is_imm16 (-size)) {
3188 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3190 ppc_load (code, ppc_r12, -size);
3191 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3198 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3200 long size = cfg->param_area;
3202 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3203 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3208 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3209 if (ppc_is_imm16 (size)) {
3210 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3212 ppc_load (code, ppc_r12, size);
3213 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3219 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3223 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3225 MonoInst *ins, *next;
3228 guint8 *code = cfg->native_code + cfg->code_len;
3229 MonoInst *last_ins = NULL;
3230 guint last_offset = 0;
3234 /* we don't align basic blocks of loops on ppc */
3236 if (cfg->verbose_level > 2)
3237 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3239 cpos = bb->max_offset;
3241 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3242 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3243 //g_assert (!mono_compile_aot);
3246 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3247 /* this is not thread save, but good enough */
3248 /* fixme: howto handle overflows? */
3249 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3252 MONO_BB_FOR_EACH_INS (bb, ins) {
3253 offset = code - cfg->native_code;
3255 max_len = ins_native_length (cfg, ins);
3257 if (offset > (cfg->code_size - max_len - 16)) {
3258 cfg->code_size *= 2;
3259 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3260 code = cfg->native_code + offset;
3262 // if (ins->cil_code)
3263 // g_print ("cil code\n");
3264 mono_debug_record_line_number (cfg, ins, offset);
3266 switch (normalize_opcode (ins->opcode)) {
3267 case OP_RELAXED_NOP:
3270 case OP_DUMMY_STORE:
3271 case OP_NOT_REACHED:
3274 case OP_IL_SEQ_POINT:
3275 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3277 case OP_SEQ_POINT: {
3280 if (cfg->compile_aot)
3284 * Read from the single stepping trigger page. This will cause a
3285 * SIGSEGV when single stepping is enabled.
3286 * We do this _before_ the breakpoint, so single stepping after
3287 * a breakpoint is hit will step to the next IL offset.
3289 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3290 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3291 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3294 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3297 * A placeholder for a possible breakpoint inserted by
3298 * mono_arch_set_breakpoint ().
3300 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3305 emit_tls_access (code, ins->dreg, ins->inst_offset);
3308 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3309 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3310 ppc_mr (code, ppc_r4, ppc_r0);
3313 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3314 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3315 ppc_mr (code, ppc_r4, ppc_r0);
3317 case OP_MEMORY_BARRIER:
3320 case OP_STOREI1_MEMBASE_REG:
3321 if (ppc_is_imm16 (ins->inst_offset)) {
3322 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3324 if (ppc_is_imm32 (ins->inst_offset)) {
3325 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3326 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3328 ppc_load (code, ppc_r0, ins->inst_offset);
3329 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3333 case OP_STOREI2_MEMBASE_REG:
3334 if (ppc_is_imm16 (ins->inst_offset)) {
3335 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3337 if (ppc_is_imm32 (ins->inst_offset)) {
3338 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3339 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3341 ppc_load (code, ppc_r0, ins->inst_offset);
3342 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3346 case OP_STORE_MEMBASE_REG:
3347 if (ppc_is_imm16 (ins->inst_offset)) {
3348 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3350 if (ppc_is_imm32 (ins->inst_offset)) {
3351 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3352 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3354 ppc_load (code, ppc_r0, ins->inst_offset);
3355 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3359 #ifdef __mono_ilp32__
3360 case OP_STOREI8_MEMBASE_REG:
3361 if (ppc_is_imm16 (ins->inst_offset)) {
3362 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3364 ppc_load (code, ppc_r0, ins->inst_offset);
3365 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3369 case OP_STOREI1_MEMINDEX:
3370 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3372 case OP_STOREI2_MEMINDEX:
3373 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3375 case OP_STORE_MEMINDEX:
3376 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3379 g_assert_not_reached ();
3381 case OP_LOAD_MEMBASE:
3382 if (ppc_is_imm16 (ins->inst_offset)) {
3383 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3385 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3386 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3387 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3389 ppc_load (code, ppc_r0, ins->inst_offset);
3390 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3394 case OP_LOADI4_MEMBASE:
3395 #ifdef __mono_ppc64__
3396 if (ppc_is_imm16 (ins->inst_offset)) {
3397 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3399 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3400 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3401 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3403 ppc_load (code, ppc_r0, ins->inst_offset);
3404 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3409 case OP_LOADU4_MEMBASE:
3410 if (ppc_is_imm16 (ins->inst_offset)) {
3411 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3413 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3414 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3415 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3417 ppc_load (code, ppc_r0, ins->inst_offset);
3418 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3422 case OP_LOADI1_MEMBASE:
3423 case OP_LOADU1_MEMBASE:
3424 if (ppc_is_imm16 (ins->inst_offset)) {
3425 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3427 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3428 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3429 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3431 ppc_load (code, ppc_r0, ins->inst_offset);
3432 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3435 if (ins->opcode == OP_LOADI1_MEMBASE)
3436 ppc_extsb (code, ins->dreg, ins->dreg);
3438 case OP_LOADU2_MEMBASE:
3439 if (ppc_is_imm16 (ins->inst_offset)) {
3440 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3442 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3443 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3444 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3446 ppc_load (code, ppc_r0, ins->inst_offset);
3447 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3451 case OP_LOADI2_MEMBASE:
3452 if (ppc_is_imm16 (ins->inst_offset)) {
3453 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3455 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3456 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3457 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3459 ppc_load (code, ppc_r0, ins->inst_offset);
3460 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3464 #ifdef __mono_ilp32__
3465 case OP_LOADI8_MEMBASE:
3466 if (ppc_is_imm16 (ins->inst_offset)) {
3467 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3469 ppc_load (code, ppc_r0, ins->inst_offset);
3470 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3474 case OP_LOAD_MEMINDEX:
3475 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3477 case OP_LOADI4_MEMINDEX:
3478 #ifdef __mono_ppc64__
3479 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3482 case OP_LOADU4_MEMINDEX:
3483 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3485 case OP_LOADU2_MEMINDEX:
3486 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3488 case OP_LOADI2_MEMINDEX:
3489 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3491 case OP_LOADU1_MEMINDEX:
3492 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3494 case OP_LOADI1_MEMINDEX:
3495 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3496 ppc_extsb (code, ins->dreg, ins->dreg);
3498 case OP_ICONV_TO_I1:
3499 CASE_PPC64 (OP_LCONV_TO_I1)
3500 ppc_extsb (code, ins->dreg, ins->sreg1);
3502 case OP_ICONV_TO_I2:
3503 CASE_PPC64 (OP_LCONV_TO_I2)
3504 ppc_extsh (code, ins->dreg, ins->sreg1);
3506 case OP_ICONV_TO_U1:
3507 CASE_PPC64 (OP_LCONV_TO_U1)
3508 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3510 case OP_ICONV_TO_U2:
3511 CASE_PPC64 (OP_LCONV_TO_U2)
3512 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3516 CASE_PPC64 (OP_LCOMPARE)
3517 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3519 if (next && compare_opcode_is_unsigned (next->opcode))
3520 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3522 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3524 case OP_COMPARE_IMM:
3525 case OP_ICOMPARE_IMM:
3526 CASE_PPC64 (OP_LCOMPARE_IMM)
3527 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3529 if (next && compare_opcode_is_unsigned (next->opcode)) {
3530 if (ppc_is_uimm16 (ins->inst_imm)) {
3531 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3533 g_assert_not_reached ();
3536 if (ppc_is_imm16 (ins->inst_imm)) {
3537 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3539 g_assert_not_reached ();
3545 * gdb does not like encountering a trap in the debugged code. So
3546 * instead of emitting a trap, we emit a call a C function and place a
3550 ppc_mr (code, ppc_r3, ins->sreg1);
3551 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3552 (gpointer)"mono_break");
3553 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3554 ppc_load_func (code, PPC_CALL_REG, 0);
3555 ppc_mtlr (code, PPC_CALL_REG);
3563 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 CASE_PPC64 (OP_LADD)
3567 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3571 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3574 if (ppc_is_imm16 (ins->inst_imm)) {
3575 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3577 g_assert_not_reached ();
3582 CASE_PPC64 (OP_LADD_IMM)
3583 if (ppc_is_imm16 (ins->inst_imm)) {
3584 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3586 g_assert_not_reached ();
3590 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3592 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3593 ppc_mfspr (code, ppc_r0, ppc_xer);
3594 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3595 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3597 case OP_IADD_OVF_UN:
3598 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3600 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3601 ppc_mfspr (code, ppc_r0, ppc_xer);
3602 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3603 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3606 CASE_PPC64 (OP_LSUB_OVF)
3607 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3609 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3610 ppc_mfspr (code, ppc_r0, ppc_xer);
3611 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3612 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3614 case OP_ISUB_OVF_UN:
3615 CASE_PPC64 (OP_LSUB_OVF_UN)
3616 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3618 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3619 ppc_mfspr (code, ppc_r0, ppc_xer);
3620 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3621 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3623 case OP_ADD_OVF_CARRY:
3624 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3626 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 ppc_mfspr (code, ppc_r0, ppc_xer);
3628 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3629 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3631 case OP_ADD_OVF_UN_CARRY:
3632 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3634 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3635 ppc_mfspr (code, ppc_r0, ppc_xer);
3636 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3637 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3639 case OP_SUB_OVF_CARRY:
3640 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3642 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3643 ppc_mfspr (code, ppc_r0, ppc_xer);
3644 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3645 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3647 case OP_SUB_OVF_UN_CARRY:
3648 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3650 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3651 ppc_mfspr (code, ppc_r0, ppc_xer);
3652 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3653 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3657 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3660 CASE_PPC64 (OP_LSUB)
3661 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3665 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3669 CASE_PPC64 (OP_LSUB_IMM)
3670 // we add the negated value
3671 if (ppc_is_imm16 (-ins->inst_imm))
3672 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3674 g_assert_not_reached ();
3678 g_assert (ppc_is_imm16 (ins->inst_imm));
3679 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3682 ppc_subfze (code, ins->dreg, ins->sreg1);
3685 CASE_PPC64 (OP_LAND)
3686 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3687 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3691 CASE_PPC64 (OP_LAND_IMM)
3692 if (!(ins->inst_imm & 0xffff0000)) {
3693 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3694 } else if (!(ins->inst_imm & 0xffff)) {
3695 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3697 g_assert_not_reached ();
3701 CASE_PPC64 (OP_LDIV) {
3702 guint8 *divisor_is_m1;
3703 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3705 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3706 divisor_is_m1 = code;
3707 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3708 ppc_lis (code, ppc_r0, 0x8000);
3709 #ifdef __mono_ppc64__
3710 if (ins->opcode == OP_LDIV)
3711 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3713 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3714 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3715 ppc_patch (divisor_is_m1, code);
3716 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3718 if (ins->opcode == OP_IDIV)
3719 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3720 #ifdef __mono_ppc64__
3722 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3724 ppc_mfspr (code, ppc_r0, ppc_xer);
3725 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3726 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3730 CASE_PPC64 (OP_LDIV_UN)
3731 if (ins->opcode == OP_IDIV_UN)
3732 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3733 #ifdef __mono_ppc64__
3735 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3737 ppc_mfspr (code, ppc_r0, ppc_xer);
3738 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3739 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3745 g_assert_not_reached ();
3748 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3752 CASE_PPC64 (OP_LOR_IMM)
3753 if (!(ins->inst_imm & 0xffff0000)) {
3754 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3755 } else if (!(ins->inst_imm & 0xffff)) {
3756 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3758 g_assert_not_reached ();
3762 CASE_PPC64 (OP_LXOR)
3763 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3767 CASE_PPC64 (OP_LXOR_IMM)
3768 if (!(ins->inst_imm & 0xffff0000)) {
3769 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3770 } else if (!(ins->inst_imm & 0xffff)) {
3771 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3773 g_assert_not_reached ();
3777 CASE_PPC64 (OP_LSHL)
3778 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3782 CASE_PPC64 (OP_LSHL_IMM)
3783 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3786 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3789 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3792 if (MASK_SHIFT_IMM (ins->inst_imm))
3793 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3795 ppc_mr (code, ins->dreg, ins->sreg1);
3798 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3801 CASE_PPC64 (OP_LNOT)
3802 ppc_not (code, ins->dreg, ins->sreg1);
3805 CASE_PPC64 (OP_LNEG)
3806 ppc_neg (code, ins->dreg, ins->sreg1);
3809 CASE_PPC64 (OP_LMUL)
3810 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3814 CASE_PPC64 (OP_LMUL_IMM)
3815 if (ppc_is_imm16 (ins->inst_imm)) {
3816 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3818 g_assert_not_reached ();
3822 CASE_PPC64 (OP_LMUL_OVF)
3823 /* we annot use mcrxr, since it's not implemented on some processors
3824 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3826 if (ins->opcode == OP_IMUL_OVF)
3827 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3828 #ifdef __mono_ppc64__
3830 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3832 ppc_mfspr (code, ppc_r0, ppc_xer);
3833 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3834 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3836 case OP_IMUL_OVF_UN:
3837 CASE_PPC64 (OP_LMUL_OVF_UN)
3838 /* we first multiply to get the high word and compare to 0
3839 * to set the flags, then the result is discarded and then
3840 * we multiply to get the lower * bits result
3842 if (ins->opcode == OP_IMUL_OVF_UN)
3843 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3844 #ifdef __mono_ppc64__
3846 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3848 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3849 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3850 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3853 ppc_load (code, ins->dreg, ins->inst_c0);
3856 ppc_load (code, ins->dreg, ins->inst_l);
3859 case OP_LOAD_GOTADDR:
3860 /* The PLT implementation depends on this */
3861 g_assert (ins->dreg == ppc_r30);
3863 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3866 // FIXME: Fix max instruction length
3867 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3868 /* arch_emit_got_access () patches this */
3869 ppc_load32 (code, ppc_r0, 0);
3870 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3873 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3874 ppc_load_sequence (code, ins->dreg, 0);
3876 CASE_PPC32 (OP_ICONV_TO_I4)
3877 CASE_PPC32 (OP_ICONV_TO_U4)
3879 if (ins->dreg != ins->sreg1)
3880 ppc_mr (code, ins->dreg, ins->sreg1);
3883 int saved = ins->sreg1;
3884 if (ins->sreg1 == ppc_r3) {
3885 ppc_mr (code, ppc_r0, ins->sreg1);
3888 if (ins->sreg2 != ppc_r3)
3889 ppc_mr (code, ppc_r3, ins->sreg2);
3890 if (saved != ppc_r4)
3891 ppc_mr (code, ppc_r4, saved);
3895 if (ins->dreg != ins->sreg1)
3896 ppc_fmr (code, ins->dreg, ins->sreg1);
3898 case OP_MOVE_F_TO_I4:
3899 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3900 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3902 case OP_MOVE_I4_TO_F:
3903 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3904 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3906 case OP_FCONV_TO_R4:
3907 ppc_frsp (code, ins->dreg, ins->sreg1);
3911 MonoCallInst *call = (MonoCallInst*)ins;
3914 * Keep in sync with mono_arch_emit_epilog
3916 g_assert (!cfg->method->save_lmf);
3918 * Note: we can use ppc_r12 here because it is dead anyway:
3919 * we're leaving the method.
3921 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3922 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3923 if (ppc_is_imm16 (ret_offset)) {
3924 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3926 ppc_load (code, ppc_r12, ret_offset);
3927 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3929 ppc_mtlr (code, ppc_r0);
3932 if (ppc_is_imm16 (cfg->stack_usage)) {
3933 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3935 /* cfg->stack_usage is an int, so we can use
3936 * an addis/addi sequence here even in 64-bit. */
3937 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3938 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3940 if (!cfg->method->save_lmf) {
3942 for (i = 31; i >= 13; --i) {
3943 if (cfg->used_int_regs & (1 << i)) {
3944 pos += sizeof (gpointer);
3945 ppc_ldptr (code, i, -pos, ppc_r12);
3949 /* FIXME restore from MonoLMF: though this can't happen yet */
3952 /* Copy arguments on the stack to our argument area */
3953 if (call->stack_usage) {
3954 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3955 /* r12 was clobbered */
3956 g_assert (cfg->frame_reg == ppc_sp);
3957 if (ppc_is_imm16 (cfg->stack_usage)) {
3958 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3960 /* cfg->stack_usage is an int, so we can use
3961 * an addis/addi sequence here even in 64-bit. */
3962 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3963 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3967 ppc_mr (code, ppc_sp, ppc_r12);
3968 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3969 if (cfg->compile_aot) {
3970 /* arch_emit_got_access () patches this */
3971 ppc_load32 (code, ppc_r0, 0);
3972 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3973 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3974 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3976 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3978 ppc_mtctr (code, ppc_r0);
3979 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3986 /* ensure ins->sreg1 is not NULL */
3987 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3990 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3991 if (ppc_is_imm16 (cookie_offset)) {
3992 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3994 ppc_load (code, ppc_r0, cookie_offset);
3995 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3997 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
4006 call = (MonoCallInst*)ins;
4007 if (ins->flags & MONO_INST_HAS_METHOD)
4008 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4010 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4011 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4012 ppc_load_func (code, PPC_CALL_REG, 0);
4013 ppc_mtlr (code, PPC_CALL_REG);
4018 /* FIXME: this should be handled somewhere else in the new jit */
4019 code = emit_move_return_value (cfg, ins, code);
4025 case OP_VOIDCALL_REG:
4027 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4028 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4029 /* FIXME: if we know that this is a method, we
4030 can omit this load */
4031 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4032 ppc_mtlr (code, ppc_r0);
4034 #if (_CALL_ELF == 2)
4035 if (ins->flags & MONO_INST_HAS_METHOD) {
4036 // Not a global entry point
4038 // Need to set up r12 with function entry address for global entry point
4039 if (ppc_r12 != ins->sreg1) {
4040 ppc_mr(code,ppc_r12,ins->sreg1);
4044 ppc_mtlr (code, ins->sreg1);
4047 /* FIXME: this should be handled somewhere else in the new jit */
4048 code = emit_move_return_value (cfg, ins, code);
4050 case OP_FCALL_MEMBASE:
4051 case OP_LCALL_MEMBASE:
4052 case OP_VCALL_MEMBASE:
4053 case OP_VCALL2_MEMBASE:
4054 case OP_VOIDCALL_MEMBASE:
4055 case OP_CALL_MEMBASE:
4056 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
4057 /* The trampolines clobber this */
4058 ppc_mr (code, ppc_r29, ins->sreg1);
4059 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4061 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4063 ppc_mtlr (code, ppc_r0);
4065 /* FIXME: this should be handled somewhere else in the new jit */
4066 code = emit_move_return_value (cfg, ins, code);
4069 guint8 * zero_loop_jump, * zero_loop_start;
4070 /* keep alignment */
4071 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4072 int area_offset = alloca_waste;
4074 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4075 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4076 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4077 /* use ctr to store the number of words to 0 if needed */
4078 if (ins->flags & MONO_INST_INIT) {
4079 /* we zero 4 bytes at a time:
4080 * we add 7 instead of 3 so that we set the counter to
4081 * at least 1, otherwise the bdnz instruction will make
4082 * it negative and iterate billions of times.
4084 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4085 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4086 ppc_mtctr (code, ppc_r0);
4088 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4089 ppc_neg (code, ppc_r12, ppc_r12);
4090 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4092 /* FIXME: make this loop work in 8 byte
4093 increments on PPC64 */
4094 if (ins->flags & MONO_INST_INIT) {
4095 /* adjust the dest reg by -4 so we can use stwu */
4096 /* we actually adjust -8 because we let the loop
4099 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4100 ppc_li (code, ppc_r12, 0);
4101 zero_loop_start = code;
4102 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4103 zero_loop_jump = code;
4104 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4105 ppc_patch (zero_loop_jump, zero_loop_start);
4107 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4112 ppc_mr (code, ppc_r3, ins->sreg1);
4113 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4114 (gpointer)"mono_arch_throw_exception");
4115 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4116 ppc_load_func (code, PPC_CALL_REG, 0);
4117 ppc_mtlr (code, PPC_CALL_REG);
4126 ppc_mr (code, ppc_r3, ins->sreg1);
4127 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4128 (gpointer)"mono_arch_rethrow_exception");
4129 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4130 ppc_load_func (code, PPC_CALL_REG, 0);
4131 ppc_mtlr (code, PPC_CALL_REG);
4138 case OP_START_HANDLER: {
4139 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4140 g_assert (spvar->inst_basereg != ppc_sp);
4141 code = emit_reserve_param_area (cfg, code);
4142 ppc_mflr (code, ppc_r0);
4143 if (ppc_is_imm16 (spvar->inst_offset)) {
4144 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4146 ppc_load (code, ppc_r12, spvar->inst_offset);
4147 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4151 case OP_ENDFILTER: {
4152 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4153 g_assert (spvar->inst_basereg != ppc_sp);
4154 code = emit_unreserve_param_area (cfg, code);
4155 if (ins->sreg1 != ppc_r3)
4156 ppc_mr (code, ppc_r3, ins->sreg1);
4157 if (ppc_is_imm16 (spvar->inst_offset)) {
4158 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4160 ppc_load (code, ppc_r12, spvar->inst_offset);
4161 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4163 ppc_mtlr (code, ppc_r0);
4167 case OP_ENDFINALLY: {
4168 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4169 g_assert (spvar->inst_basereg != ppc_sp);
4170 code = emit_unreserve_param_area (cfg, code);
4171 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4172 ppc_mtlr (code, ppc_r0);
4176 case OP_CALL_HANDLER:
4177 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4179 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4182 ins->inst_c0 = code - cfg->native_code;
4185 /*if (ins->inst_target_bb->native_offset) {
4187 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4189 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4194 ppc_mtctr (code, ins->sreg1);
4195 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4199 CASE_PPC64 (OP_LCEQ)
4200 ppc_li (code, ins->dreg, 0);
4201 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4202 ppc_li (code, ins->dreg, 1);
4208 CASE_PPC64 (OP_LCLT)
4209 CASE_PPC64 (OP_LCLT_UN)
4210 ppc_li (code, ins->dreg, 1);
4211 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4212 ppc_li (code, ins->dreg, 0);
4218 CASE_PPC64 (OP_LCGT)
4219 CASE_PPC64 (OP_LCGT_UN)
4220 ppc_li (code, ins->dreg, 1);
4221 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4222 ppc_li (code, ins->dreg, 0);
4224 case OP_COND_EXC_EQ:
4225 case OP_COND_EXC_NE_UN:
4226 case OP_COND_EXC_LT:
4227 case OP_COND_EXC_LT_UN:
4228 case OP_COND_EXC_GT:
4229 case OP_COND_EXC_GT_UN:
4230 case OP_COND_EXC_GE:
4231 case OP_COND_EXC_GE_UN:
4232 case OP_COND_EXC_LE:
4233 case OP_COND_EXC_LE_UN:
4234 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4236 case OP_COND_EXC_IEQ:
4237 case OP_COND_EXC_INE_UN:
4238 case OP_COND_EXC_ILT:
4239 case OP_COND_EXC_ILT_UN:
4240 case OP_COND_EXC_IGT:
4241 case OP_COND_EXC_IGT_UN:
4242 case OP_COND_EXC_IGE:
4243 case OP_COND_EXC_IGE_UN:
4244 case OP_COND_EXC_ILE:
4245 case OP_COND_EXC_ILE_UN:
4246 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4258 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4261 /* floating point opcodes */
4263 g_assert (cfg->compile_aot);
4265 /* FIXME: Optimize this */
4267 ppc_mflr (code, ppc_r12);
4269 *(double*)code = *(double*)ins->inst_p0;
4271 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4274 g_assert_not_reached ();
4276 case OP_STORER8_MEMBASE_REG:
4277 if (ppc_is_imm16 (ins->inst_offset)) {
4278 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4280 if (ppc_is_imm32 (ins->inst_offset)) {
4281 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4282 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4284 ppc_load (code, ppc_r0, ins->inst_offset);
4285 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4289 case OP_LOADR8_MEMBASE:
4290 if (ppc_is_imm16 (ins->inst_offset)) {
4291 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4293 if (ppc_is_imm32 (ins->inst_offset)) {
4294 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4295 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4297 ppc_load (code, ppc_r0, ins->inst_offset);
4298 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4302 case OP_STORER4_MEMBASE_REG:
4303 ppc_frsp (code, ins->sreg1, ins->sreg1);
4304 if (ppc_is_imm16 (ins->inst_offset)) {
4305 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4307 if (ppc_is_imm32 (ins->inst_offset)) {
4308 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4309 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4311 ppc_load (code, ppc_r0, ins->inst_offset);
4312 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4316 case OP_LOADR4_MEMBASE:
4317 if (ppc_is_imm16 (ins->inst_offset)) {
4318 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4320 if (ppc_is_imm32 (ins->inst_offset)) {
4321 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4322 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4324 ppc_load (code, ppc_r0, ins->inst_offset);
4325 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4329 case OP_LOADR4_MEMINDEX:
4330 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4332 case OP_LOADR8_MEMINDEX:
4333 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4335 case OP_STORER4_MEMINDEX:
4336 ppc_frsp (code, ins->sreg1, ins->sreg1);
4337 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4339 case OP_STORER8_MEMINDEX:
4340 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4343 case CEE_CONV_R4: /* FIXME: change precision */
4345 g_assert_not_reached ();
4346 case OP_FCONV_TO_I1:
4347 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4349 case OP_FCONV_TO_U1:
4350 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4352 case OP_FCONV_TO_I2:
4353 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4355 case OP_FCONV_TO_U2:
4356 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4358 case OP_FCONV_TO_I4:
4360 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4362 case OP_FCONV_TO_U4:
4364 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4366 case OP_LCONV_TO_R_UN:
4367 g_assert_not_reached ();
4368 /* Implemented as helper calls */
4370 case OP_LCONV_TO_OVF_I4_2:
4371 case OP_LCONV_TO_OVF_I: {
4372 #ifdef __mono_ppc64__
4375 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4376 // Check if its negative
4377 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4378 negative_branch = code;
4379 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4380 // Its positive msword == 0
4381 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4382 msword_positive_branch = code;
4383 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4385 ovf_ex_target = code;
4386 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4388 ppc_patch (negative_branch, code);
4389 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4390 msword_negative_branch = code;
4391 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4392 ppc_patch (msword_negative_branch, ovf_ex_target);
4394 ppc_patch (msword_positive_branch, code);
4395 if (ins->dreg != ins->sreg1)
4396 ppc_mr (code, ins->dreg, ins->sreg1);
4401 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4404 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4407 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4410 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4413 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4416 ppc_fneg (code, ins->dreg, ins->sreg1);
4420 g_assert_not_reached ();
4423 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4426 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 0);
4428 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4429 ppc_li (code, ins->dreg, 1);
4432 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4433 ppc_li (code, ins->dreg, 1);
4434 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4435 ppc_li (code, ins->dreg, 0);
4438 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4439 ppc_li (code, ins->dreg, 1);
4440 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4441 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4442 ppc_li (code, ins->dreg, 0);
4445 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4446 ppc_li (code, ins->dreg, 1);
4447 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4448 ppc_li (code, ins->dreg, 0);
4451 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4452 ppc_li (code, ins->dreg, 1);
4453 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4454 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4455 ppc_li (code, ins->dreg, 0);
4458 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4461 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4464 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4465 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4468 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4469 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4472 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4473 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4476 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4477 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4480 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4481 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4484 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4487 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4488 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4491 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4494 g_assert_not_reached ();
4495 case OP_CHECK_FINITE: {
4496 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4497 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4498 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4499 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4502 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4503 #ifdef __mono_ppc64__
4504 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4506 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4511 #ifdef __mono_ppc64__
4512 case OP_ICONV_TO_I4:
4514 ppc_extsw (code, ins->dreg, ins->sreg1);
4516 case OP_ICONV_TO_U4:
4518 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4520 case OP_ICONV_TO_R4:
4521 case OP_ICONV_TO_R8:
4522 case OP_LCONV_TO_R4:
4523 case OP_LCONV_TO_R8: {
4525 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4526 ppc_extsw (code, ppc_r0, ins->sreg1);
4531 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4532 ppc_mffgpr (code, ins->dreg, tmp);
4534 ppc_str (code, tmp, -8, ppc_r1);
4535 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4537 ppc_fcfid (code, ins->dreg, ins->dreg);
4538 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4539 ppc_frsp (code, ins->dreg, ins->dreg);
4543 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4546 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4549 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4551 ppc_mfspr (code, ppc_r0, ppc_xer);
4552 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4553 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4555 case OP_COND_EXC_OV:
4556 ppc_mfspr (code, ppc_r0, ppc_xer);
4557 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4558 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4570 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4572 case OP_FCONV_TO_I8:
4573 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4575 case OP_FCONV_TO_U8:
4576 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4578 case OP_STOREI4_MEMBASE_REG:
4579 if (ppc_is_imm16 (ins->inst_offset)) {
4580 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4582 ppc_load (code, ppc_r0, ins->inst_offset);
4583 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4586 case OP_STOREI4_MEMINDEX:
4587 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4590 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4592 case OP_ISHR_UN_IMM:
4593 if (ins->inst_imm & 0x1f)
4594 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4596 ppc_mr (code, ins->dreg, ins->sreg1);
4599 case OP_ICONV_TO_R4:
4600 case OP_ICONV_TO_R8: {
4601 if (cpu_hw_caps & PPC_ISA_64) {
4602 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4603 ppc_stw (code, ppc_r0, -8, ppc_r1);
4604 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4605 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4606 ppc_fcfid (code, ins->dreg, ins->dreg);
4607 if (ins->opcode == OP_ICONV_TO_R4)
4608 ppc_frsp (code, ins->dreg, ins->dreg);
4614 case OP_ATOMIC_ADD_I4:
4615 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4616 int location = ins->inst_basereg;
4617 int addend = ins->sreg2;
4618 guint8 *loop, *branch;
4619 g_assert (ins->inst_offset == 0);
4623 if (ins->opcode == OP_ATOMIC_ADD_I4)
4624 ppc_lwarx (code, ppc_r0, 0, location);
4625 #ifdef __mono_ppc64__
4627 ppc_ldarx (code, ppc_r0, 0, location);
4630 ppc_add (code, ppc_r0, ppc_r0, addend);
4632 if (ins->opcode == OP_ATOMIC_ADD_I4)
4633 ppc_stwcxd (code, ppc_r0, 0, location);
4634 #ifdef __mono_ppc64__
4636 ppc_stdcxd (code, ppc_r0, 0, location);
4640 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4641 ppc_patch (branch, loop);
4644 ppc_mr (code, ins->dreg, ppc_r0);
4647 case OP_ATOMIC_CAS_I4:
4648 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4649 int location = ins->sreg1;
4650 int value = ins->sreg2;
4651 int comparand = ins->sreg3;
4652 guint8 *start, *not_equal, *lost_reservation;
4656 if (ins->opcode == OP_ATOMIC_CAS_I4)
4657 ppc_lwarx (code, ppc_r0, 0, location);
4658 #ifdef __mono_ppc64__
4660 ppc_ldarx (code, ppc_r0, 0, location);
4663 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4665 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4667 if (ins->opcode == OP_ATOMIC_CAS_I4)
4668 ppc_stwcxd (code, value, 0, location);
4669 #ifdef __mono_ppc64__
4671 ppc_stdcxd (code, value, 0, location);
4674 lost_reservation = code;
4675 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4676 ppc_patch (lost_reservation, start);
4677 ppc_patch (not_equal, code);
4680 ppc_mr (code, ins->dreg, ppc_r0);
4683 case OP_GC_SAFE_POINT:
4687 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4688 g_assert_not_reached ();
4691 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4692 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4693 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4694 g_assert_not_reached ();
4700 last_offset = offset;
4703 cfg->code_len = code - cfg->native_code;
4705 #endif /* !DISABLE_JIT */
4708 mono_arch_register_lowlevel_calls (void)
4710 /* The signature doesn't matter */
4711 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4714 #ifdef __mono_ppc64__
4715 #ifdef _LITTLE_ENDIAN
4716 #define patch_load_sequence(ip,val) do {\
4717 guint16 *__load = (guint16*)(ip); \
4718 g_assert (sizeof (val) == sizeof (gsize)); \
4719 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4720 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4721 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4722 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4724 #elif defined _BIG_ENDIAN
4725 #define patch_load_sequence(ip,val) do {\
4726 guint16 *__load = (guint16*)(ip); \
4727 g_assert (sizeof (val) == sizeof (gsize)); \
4728 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4729 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4730 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4731 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4734 #error huh? No endianess defined by compiler
4737 #define patch_load_sequence(ip,val) do {\
4738 guint16 *__lis_ori = (guint16*)(ip); \
4739 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4740 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4746 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4748 MonoJumpInfo *patch_info;
4749 gboolean compile_aot = !run_cctors;
4752 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4753 unsigned char *ip = patch_info->ip.i + code;
4754 unsigned char *target;
4755 gboolean is_fd = FALSE;
4757 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
4758 mono_error_raise_exception (&error); /* FIXME: don't raise here */
4761 switch (patch_info->type) {
4762 case MONO_PATCH_INFO_BB:
4763 case MONO_PATCH_INFO_LABEL:
4766 /* No need to patch these */
4771 switch (patch_info->type) {
4772 case MONO_PATCH_INFO_IP:
4773 patch_load_sequence (ip, ip);
4775 case MONO_PATCH_INFO_METHOD_REL:
4776 g_assert_not_reached ();
4777 *((gpointer *)(ip)) = code + patch_info->data.offset;
4779 case MONO_PATCH_INFO_SWITCH: {
4780 gpointer *table = (gpointer *)patch_info->data.table->table;
4783 patch_load_sequence (ip, table);
4785 for (i = 0; i < patch_info->data.table->table_size; i++) {
4786 table [i] = (glong)patch_info->data.table->table [i] + code;
4788 /* we put into the table the absolute address, no need for ppc_patch in this case */
4791 case MONO_PATCH_INFO_METHODCONST:
4792 case MONO_PATCH_INFO_CLASS:
4793 case MONO_PATCH_INFO_IMAGE:
4794 case MONO_PATCH_INFO_FIELD:
4795 case MONO_PATCH_INFO_VTABLE:
4796 case MONO_PATCH_INFO_IID:
4797 case MONO_PATCH_INFO_SFLDA:
4798 case MONO_PATCH_INFO_LDSTR:
4799 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4800 case MONO_PATCH_INFO_LDTOKEN:
4801 /* from OP_AOTCONST : lis + ori */
4802 patch_load_sequence (ip, target);
4804 case MONO_PATCH_INFO_R4:
4805 case MONO_PATCH_INFO_R8:
4806 g_assert_not_reached ();
4807 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4809 case MONO_PATCH_INFO_EXC_NAME:
4810 g_assert_not_reached ();
4811 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4813 case MONO_PATCH_INFO_NONE:
4814 case MONO_PATCH_INFO_BB_OVF:
4815 case MONO_PATCH_INFO_EXC_OVF:
4816 /* everything is dealt with at epilog output time */
4818 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4819 case MONO_PATCH_INFO_INTERNAL_METHOD:
4820 case MONO_PATCH_INFO_ABS:
4821 case MONO_PATCH_INFO_RGCTX_FETCH:
4822 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4829 ppc_patch_full (ip, target, is_fd);
4834 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4835 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4836 * the instruction offset immediate for all the registers.
4839 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4843 for (i = 13; i <= 31; i++) {
4844 if (used_int_regs & (1 << i)) {
4845 ppc_str (code, i, pos, base_reg);
4846 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4847 pos += sizeof (mgreg_t);
4851 /* pos is the start of the MonoLMF structure */
4852 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4853 for (i = 13; i <= 31; i++) {
4854 ppc_str (code, i, offset, base_reg);
4855 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4856 offset += sizeof (mgreg_t);
4858 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4859 for (i = 14; i < 32; i++) {
4860 ppc_stfd (code, i, offset, base_reg);
4861 offset += sizeof (gdouble);
4868 * Stack frame layout:
4870 * ------------------- sp
4871 * MonoLMF structure or saved registers
4872 * -------------------
4874 * -------------------
4876 * -------------------
4877 * optional 8 bytes for tracing
4878 * -------------------
4879 * param area size is cfg->param_area
4880 * -------------------
4881 * linkage area size is PPC_STACK_PARAM_OFFSET
4882 * ------------------- sp
4886 mono_arch_emit_prolog (MonoCompile *cfg)
4888 MonoMethod *method = cfg->method;
4890 MonoMethodSignature *sig;
4892 long alloc_size, pos, max_offset, cfa_offset;
4898 int tailcall_struct_index;
4900 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4903 sig = mono_method_signature (method);
4904 cfg->code_size = 512 + sig->param_count * 32;
4905 code = cfg->native_code = g_malloc (cfg->code_size);
4909 /* We currently emit unwind info for aot, but don't use it */
4910 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4912 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4913 ppc_mflr (code, ppc_r0);
4914 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4915 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4918 alloc_size = cfg->stack_offset;
4921 if (!method->save_lmf) {
4922 for (i = 31; i >= 13; --i) {
4923 if (cfg->used_int_regs & (1 << i)) {
4924 pos += sizeof (mgreg_t);
4928 pos += sizeof (MonoLMF);
4932 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4933 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4934 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4935 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4938 cfg->stack_usage = alloc_size;
4939 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4941 if (ppc_is_imm16 (-alloc_size)) {
4942 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4943 cfa_offset = alloc_size;
4944 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4945 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4948 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4949 ppc_load (code, ppc_r0, -alloc_size);
4950 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4951 cfa_offset = alloc_size;
4952 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4953 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4956 if (cfg->frame_reg != ppc_sp) {
4957 ppc_mr (code, cfg->frame_reg, ppc_sp);
4958 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4961 /* store runtime generic context */
4962 if (cfg->rgctx_var) {
4963 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4964 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4966 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4969 /* compute max_offset in order to use short forward jumps
4970 * we always do it on ppc because the immediate displacement
4971 * for jumps is too small
4974 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4976 bb->max_offset = max_offset;
4978 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4981 MONO_BB_FOR_EACH_INS (bb, ins)
4982 max_offset += ins_native_length (cfg, ins);
4985 /* load arguments allocated to register from the stack */
4988 cinfo = get_call_info (sig);
4990 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4991 ArgInfo *ainfo = &cinfo->ret;
4993 inst = cfg->vret_addr;
4996 if (ppc_is_imm16 (inst->inst_offset)) {
4997 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4999 ppc_load (code, ppc_r12, inst->inst_offset);
5000 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5004 tailcall_struct_index = 0;
5005 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5006 ArgInfo *ainfo = cinfo->args + i;
5007 inst = cfg->args [pos];
5009 if (cfg->verbose_level > 2)
5010 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5011 if (inst->opcode == OP_REGVAR) {
5012 if (ainfo->regtype == RegTypeGeneral)
5013 ppc_mr (code, inst->dreg, ainfo->reg);
5014 else if (ainfo->regtype == RegTypeFP)
5015 ppc_fmr (code, inst->dreg, ainfo->reg);
5016 else if (ainfo->regtype == RegTypeBase) {
5017 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5018 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5020 g_assert_not_reached ();
5022 if (cfg->verbose_level > 2)
5023 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5025 /* the argument should be put on the stack: FIXME handle size != word */
5026 if (ainfo->regtype == RegTypeGeneral) {
5027 switch (ainfo->size) {
5029 if (ppc_is_imm16 (inst->inst_offset)) {
5030 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5032 if (ppc_is_imm32 (inst->inst_offset)) {
5033 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5034 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5036 ppc_load (code, ppc_r12, inst->inst_offset);
5037 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5042 if (ppc_is_imm16 (inst->inst_offset)) {
5043 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5045 if (ppc_is_imm32 (inst->inst_offset)) {
5046 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5047 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5049 ppc_load (code, ppc_r12, inst->inst_offset);
5050 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5054 #ifdef __mono_ppc64__
5056 if (ppc_is_imm16 (inst->inst_offset)) {
5057 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5059 if (ppc_is_imm32 (inst->inst_offset)) {
5060 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5061 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5063 ppc_load (code, ppc_r12, inst->inst_offset);
5064 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5069 if (ppc_is_imm16 (inst->inst_offset)) {
5070 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5072 ppc_load (code, ppc_r12, inst->inst_offset);
5073 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5078 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5079 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5080 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5082 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5083 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5084 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5085 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5090 if (ppc_is_imm16 (inst->inst_offset)) {
5091 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5093 if (ppc_is_imm32 (inst->inst_offset)) {
5094 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5095 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5097 ppc_load (code, ppc_r12, inst->inst_offset);
5098 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5103 } else if (ainfo->regtype == RegTypeBase) {
5104 g_assert (ppc_is_imm16 (ainfo->offset));
5105 /* load the previous stack pointer in r12 */
5106 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5107 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5108 switch (ainfo->size) {
5110 if (ppc_is_imm16 (inst->inst_offset)) {
5111 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5113 if (ppc_is_imm32 (inst->inst_offset)) {
5114 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5115 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5117 ppc_load (code, ppc_r12, inst->inst_offset);
5118 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5123 if (ppc_is_imm16 (inst->inst_offset)) {
5124 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5126 if (ppc_is_imm32 (inst->inst_offset)) {
5127 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5128 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5130 ppc_load (code, ppc_r12, inst->inst_offset);
5131 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5135 #ifdef __mono_ppc64__
5137 if (ppc_is_imm16 (inst->inst_offset)) {
5138 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5140 if (ppc_is_imm32 (inst->inst_offset)) {
5141 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5142 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5144 ppc_load (code, ppc_r12, inst->inst_offset);
5145 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5150 if (ppc_is_imm16 (inst->inst_offset)) {
5151 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5153 ppc_load (code, ppc_r12, inst->inst_offset);
5154 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5159 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5160 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5161 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5162 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5163 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5165 /* use r11 to load the 2nd half of the long before we clobber r12. */
5166 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5167 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5168 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5169 ppc_stw (code, ppc_r0, 0, ppc_r12);
5170 ppc_stw (code, ppc_r11, 4, ppc_r12);
5175 if (ppc_is_imm16 (inst->inst_offset)) {
5176 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5178 if (ppc_is_imm32 (inst->inst_offset)) {
5179 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5180 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5182 ppc_load (code, ppc_r12, inst->inst_offset);
5183 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5188 } else if (ainfo->regtype == RegTypeFP) {
5189 g_assert (ppc_is_imm16 (inst->inst_offset));
5190 if (ainfo->size == 8)
5191 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5192 else if (ainfo->size == 4)
5193 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5195 g_assert_not_reached ();
5196 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5197 int doffset = inst->inst_offset;
5201 g_assert (ppc_is_imm16 (inst->inst_offset));
5202 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5203 /* FIXME: what if there is no class? */
5204 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5205 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5206 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5207 if (ainfo->size == 4) {
5208 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5210 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5212 soffset += ainfo->size;
5213 doffset += ainfo->size;
5215 } else if (ainfo->regtype == RegTypeStructByVal) {
5216 int doffset = inst->inst_offset;
5220 g_assert (ppc_is_imm16 (inst->inst_offset));
5221 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5222 /* FIXME: what if there is no class? */
5223 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5224 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5225 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5228 * Darwin handles 1 and 2 byte
5229 * structs specially by
5230 * loading h/b into the arg
5231 * register. Only done for
5235 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5237 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5241 #ifdef __mono_ppc64__
5243 g_assert (cur_reg == 0);
5244 #if G_BYTE_ORDER == G_BIG_ENDIAN
5245 ppc_sldi (code, ppc_r0, ainfo->reg,
5246 (sizeof (gpointer) - ainfo->bytes) * 8);
5247 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5249 if (mono_class_native_size (inst->klass, NULL) == 1) {
5250 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5251 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5252 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5253 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5254 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5256 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5262 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5263 inst->inst_basereg);
5266 soffset += sizeof (gpointer);
5267 doffset += sizeof (gpointer);
5269 if (ainfo->vtsize) {
5270 /* FIXME: we need to do the shifting here, too */
5273 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5274 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5275 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5276 code = emit_memcpy (code, size - soffset,
5277 inst->inst_basereg, doffset,
5278 ppc_r12, ainfo->offset + soffset);
5280 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5281 inst->inst_basereg, doffset,
5282 ppc_r12, ainfo->offset + soffset);
5285 } else if (ainfo->regtype == RegTypeStructByAddr) {
5286 /* if it was originally a RegTypeBase */
5287 if (ainfo->offset) {
5288 /* load the previous stack pointer in r12 */
5289 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5290 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5292 ppc_mr (code, ppc_r12, ainfo->reg);
5295 if (cfg->tailcall_valuetype_addrs) {
5296 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5298 g_assert (ppc_is_imm16 (addr->inst_offset));
5299 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5301 tailcall_struct_index++;
5304 g_assert (ppc_is_imm16 (inst->inst_offset));
5305 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5306 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5308 g_assert_not_reached ();
5313 if (method->save_lmf) {
5314 if (lmf_pthread_key != -1) {
5315 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5316 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5317 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5319 if (cfg->compile_aot) {
5320 /* Compute the got address which is needed by the PLT entry */
5321 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5323 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5324 (gpointer)"mono_get_lmf_addr");
5325 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5326 ppc_load_func (code, PPC_CALL_REG, 0);
5327 ppc_mtlr (code, PPC_CALL_REG);
5333 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5334 /* lmf_offset is the offset from the previous stack pointer,
5335 * alloc_size is the total stack space allocated, so the offset
5336 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5337 * The pointer to the struct is put in ppc_r12 (new_lmf).
5338 * The callee-saved registers are already in the MonoLMF structure
5340 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5341 /* ppc_r3 is the result from mono_get_lmf_addr () */
5342 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5343 /* new_lmf->previous_lmf = *lmf_addr */
5344 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5345 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5346 /* *(lmf_addr) = r12 */
5347 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5348 /* save method info */
5349 if (cfg->compile_aot)
5351 ppc_load (code, ppc_r0, 0);
5353 ppc_load_ptr (code, ppc_r0, method);
5354 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5355 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5356 /* save the current IP */
5357 if (cfg->compile_aot) {
5359 ppc_mflr (code, ppc_r0);
5361 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5362 #ifdef __mono_ppc64__
5363 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5365 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5368 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5372 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5374 cfg->code_len = code - cfg->native_code;
5375 g_assert (cfg->code_len <= cfg->code_size);
5382 mono_arch_emit_epilog (MonoCompile *cfg)
5384 MonoMethod *method = cfg->method;
5386 int max_epilog_size = 16 + 20*4;
5389 if (cfg->method->save_lmf)
5390 max_epilog_size += 128;
5392 if (mono_jit_trace_calls != NULL)
5393 max_epilog_size += 50;
5395 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5396 max_epilog_size += 50;
5398 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5399 cfg->code_size *= 2;
5400 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5401 cfg->stat_code_reallocs++;
5405 * Keep in sync with OP_JMP
5407 code = cfg->native_code + cfg->code_len;
5409 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5410 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5414 if (method->save_lmf) {
5416 pos += sizeof (MonoLMF);
5418 /* save the frame reg in r8 */
5419 ppc_mr (code, ppc_r8, cfg->frame_reg);
5420 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5421 /* r5 = previous_lmf */
5422 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5424 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5425 /* *(lmf_addr) = previous_lmf */
5426 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5427 /* FIXME: speedup: there is no actual need to restore the registers if
5428 * we didn't actually change them (idea from Zoltan).
5431 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5433 /*for (i = 14; i < 32; i++) {
5434 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5436 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5437 /* use the saved copy of the frame reg in r8 */
5438 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5439 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5440 ppc_mtlr (code, ppc_r0);
5442 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5444 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5445 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5446 if (ppc_is_imm16 (return_offset)) {
5447 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5449 ppc_load (code, ppc_r12, return_offset);
5450 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5452 ppc_mtlr (code, ppc_r0);
5454 if (ppc_is_imm16 (cfg->stack_usage)) {
5455 int offset = cfg->stack_usage;
5456 for (i = 13; i <= 31; i++) {
5457 if (cfg->used_int_regs & (1 << i))
5458 offset -= sizeof (mgreg_t);
5460 if (cfg->frame_reg != ppc_sp)
5461 ppc_mr (code, ppc_r12, cfg->frame_reg);
5462 /* note r31 (possibly the frame register) is restored last */
5463 for (i = 13; i <= 31; i++) {
5464 if (cfg->used_int_regs & (1 << i)) {
5465 ppc_ldr (code, i, offset, cfg->frame_reg);
5466 offset += sizeof (mgreg_t);
5469 if (cfg->frame_reg != ppc_sp)
5470 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5472 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5474 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5475 if (cfg->used_int_regs) {
5476 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5477 for (i = 31; i >= 13; --i) {
5478 if (cfg->used_int_regs & (1 << i)) {
5479 pos += sizeof (mgreg_t);
5480 ppc_ldr (code, i, -pos, ppc_r12);
5483 ppc_mr (code, ppc_sp, ppc_r12);
5485 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5492 cfg->code_len = code - cfg->native_code;
5494 g_assert (cfg->code_len < cfg->code_size);
5497 #endif /* ifndef DISABLE_JIT */
5499 /* remove once throw_exception_by_name is eliminated */
5501 exception_id_by_name (const char *name)
5503 if (strcmp (name, "IndexOutOfRangeException") == 0)
5504 return MONO_EXC_INDEX_OUT_OF_RANGE;
5505 if (strcmp (name, "OverflowException") == 0)
5506 return MONO_EXC_OVERFLOW;
5507 if (strcmp (name, "ArithmeticException") == 0)
5508 return MONO_EXC_ARITHMETIC;
5509 if (strcmp (name, "DivideByZeroException") == 0)
5510 return MONO_EXC_DIVIDE_BY_ZERO;
5511 if (strcmp (name, "InvalidCastException") == 0)
5512 return MONO_EXC_INVALID_CAST;
5513 if (strcmp (name, "NullReferenceException") == 0)
5514 return MONO_EXC_NULL_REF;
5515 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5516 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5517 if (strcmp (name, "ArgumentException") == 0)
5518 return MONO_EXC_ARGUMENT;
5519 g_error ("Unknown intrinsic exception %s\n", name);
5525 mono_arch_emit_exceptions (MonoCompile *cfg)
5527 MonoJumpInfo *patch_info;
5530 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5531 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5532 int max_epilog_size = 50;
5534 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5535 exc_throw_pos [i] = NULL;
5536 exc_throw_found [i] = 0;
5539 /* count the number of exception infos */
5542 * make sure we have enough space for exceptions
5544 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5545 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5546 i = exception_id_by_name (patch_info->data.target);
5547 if (!exc_throw_found [i]) {
5548 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5549 exc_throw_found [i] = TRUE;
5551 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5552 max_epilog_size += 12;
5553 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5554 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5555 i = exception_id_by_name (ovfj->data.exception);
5556 if (!exc_throw_found [i]) {
5557 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5558 exc_throw_found [i] = TRUE;
5560 max_epilog_size += 8;
5564 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5565 cfg->code_size *= 2;
5566 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5567 cfg->stat_code_reallocs++;
5570 code = cfg->native_code + cfg->code_len;
5572 /* add code to raise exceptions */
5573 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5574 switch (patch_info->type) {
5575 case MONO_PATCH_INFO_BB_OVF: {
5576 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5577 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5578 /* patch the initial jump */
5579 ppc_patch (ip, code);
5580 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5582 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5583 /* jump back to the true target */
5585 ip = ovfj->data.bb->native_offset + cfg->native_code;
5586 ppc_patch (code - 4, ip);
5587 patch_info->type = MONO_PATCH_INFO_NONE;
5590 case MONO_PATCH_INFO_EXC_OVF: {
5591 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5592 MonoJumpInfo *newji;
5593 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5594 unsigned char *bcl = code;
5595 /* patch the initial jump: we arrived here with a call */
5596 ppc_patch (ip, code);
5597 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5599 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5600 /* patch the conditional jump to the right handler */
5601 /* make it processed next */
5602 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5603 newji->type = MONO_PATCH_INFO_EXC;
5604 newji->ip.i = bcl - cfg->native_code;
5605 newji->data.target = ovfj->data.exception;
5606 newji->next = patch_info->next;
5607 patch_info->next = newji;
5608 patch_info->type = MONO_PATCH_INFO_NONE;
5611 case MONO_PATCH_INFO_EXC: {
5612 MonoClass *exc_class;
5614 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5615 i = exception_id_by_name (patch_info->data.target);
5616 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5617 ppc_patch (ip, exc_throw_pos [i]);
5618 patch_info->type = MONO_PATCH_INFO_NONE;
5621 exc_throw_pos [i] = code;
5624 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5626 ppc_patch (ip, code);
5627 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5628 ppc_load (code, ppc_r3, exc_class->type_token);
5629 /* we got here from a conditional call, so the calling ip is set in lr */
5630 ppc_mflr (code, ppc_r4);
5631 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5632 patch_info->data.name = "mono_arch_throw_corlib_exception";
5633 patch_info->ip.i = code - cfg->native_code;
5634 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5635 ppc_load_func (code, PPC_CALL_REG, 0);
5636 ppc_mtctr (code, PPC_CALL_REG);
5637 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5649 cfg->code_len = code - cfg->native_code;
5651 g_assert (cfg->code_len <= cfg->code_size);
5657 try_offset_access (void *value, guint32 idx)
5659 register void* me __asm__ ("r2");
5660 void ***p = (void***)((char*)me + 284);
5661 int idx1 = idx / 32;
5662 int idx2 = idx % 32;
5665 if (value != p[idx1][idx2])
5672 setup_tls_access (void)
5674 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5675 size_t conf_size = 0;
5678 /* FIXME for darwin */
5679 guint32 *ins, *code;
5680 guint32 cmplwi_1023, li_0x48, blr_ins;
5684 tls_mode = TLS_MODE_FAILED;
5687 if (tls_mode == TLS_MODE_FAILED)
5689 if (g_getenv ("MONO_NO_TLS")) {
5690 tls_mode = TLS_MODE_FAILED;
5694 if (tls_mode == TLS_MODE_DETECT) {
5695 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5696 tls_mode = TLS_MODE_DARWIN_G4;
5697 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5698 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5699 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5700 tls_mode = TLS_MODE_NPTL;
5701 #elif !defined(TARGET_PS3)
5702 ins = (guint32*)pthread_getspecific;
5703 /* uncond branch to the real method */
5704 if ((*ins >> 26) == 18) {
5706 val = (*ins & ~3) << 6;
5710 ins = (guint32*)(long)val;
5712 ins = (guint32*) ((char*)ins + val);
5715 code = &cmplwi_1023;
5716 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5718 ppc_li (code, ppc_r4, 0x48);
5721 if (*ins == cmplwi_1023) {
5722 int found_lwz_284 = 0;
5724 for (ptk = 0; ptk < 20; ++ptk) {
5726 if (!*ins || *ins == blr_ins)
5728 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5733 if (!found_lwz_284) {
5734 tls_mode = TLS_MODE_FAILED;
5737 tls_mode = TLS_MODE_LTHREADS;
5738 } else if (*ins == li_0x48) {
5740 /* uncond branch to the real method */
5741 if ((*ins >> 26) == 18) {
5743 val = (*ins & ~3) << 6;
5747 ins = (guint32*)(long)val;
5749 ins = (guint32*) ((char*)ins + val);
5751 code = (guint32*)&val;
5752 ppc_li (code, ppc_r0, 0x7FF2);
5753 if (ins [1] == val) {
5754 /* Darwin on G4, implement */
5755 tls_mode = TLS_MODE_FAILED;
5758 code = (guint32*)&val;
5759 ppc_mfspr (code, ppc_r3, 104);
5760 if (ins [1] != val) {
5761 tls_mode = TLS_MODE_FAILED;
5764 tls_mode = TLS_MODE_DARWIN_G5;
5767 tls_mode = TLS_MODE_FAILED;
5771 tls_mode = TLS_MODE_FAILED;
5777 if (tls_mode == TLS_MODE_DETECT)
5778 tls_mode = TLS_MODE_FAILED;
5779 if (tls_mode == TLS_MODE_FAILED)
5781 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5782 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5786 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5787 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5788 if (lmf_pthread_key == -1) {
5789 guint32 ptk = mono_jit_tls_id;
5791 /*g_print ("MonoLMF at: %d\n", ptk);*/
5792 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5793 init_tls_failed = 1;
5796 lmf_pthread_key = ptk;
5805 mono_arch_finish_init (void)
5807 setup_tls_access ();
5811 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5815 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5817 #define LOADSTORE_SIZE 4
5818 #define JUMP_IMM_SIZE 12
5819 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5820 #define ENABLE_WRONG_METHOD_CHECK 0
5823 * LOCKING: called with the domain lock held
5826 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5827 gpointer fail_tramp)
5831 guint8 *code, *start;
5833 for (i = 0; i < count; ++i) {
5834 MonoIMTCheckItem *item = imt_entries [i];
5835 if (item->is_equals) {
5836 if (item->check_target_idx) {
5837 if (!item->compare_done)
5838 item->chunk_size += CMP_SIZE;
5839 if (item->has_target_code)
5840 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5842 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5845 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5846 if (!item->has_target_code)
5847 item->chunk_size += LOADSTORE_SIZE;
5849 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5850 #if ENABLE_WRONG_METHOD_CHECK
5851 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5856 item->chunk_size += CMP_SIZE + BR_SIZE;
5857 imt_entries [item->check_target_idx]->compare_done = TRUE;
5859 size += item->chunk_size;
5861 /* the initial load of the vtable address */
5862 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5864 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5866 code = mono_domain_code_reserve (domain, size);
5871 * We need to save and restore r12 because it might be
5872 * used by the caller as the vtable register, so
5873 * clobbering it will trip up the magic trampoline.
5875 * FIXME: Get rid of this by making sure that r12 is
5876 * not used as the vtable register in interface calls.
5878 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5879 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5881 for (i = 0; i < count; ++i) {
5882 MonoIMTCheckItem *item = imt_entries [i];
5883 item->code_target = code;
5884 if (item->is_equals) {
5885 if (item->check_target_idx) {
5886 if (!item->compare_done) {
5887 ppc_load (code, ppc_r0, (gsize)item->key);
5888 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5890 item->jmp_code = code;
5891 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5892 if (item->has_target_code) {
5893 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5895 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5896 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5898 ppc_mtctr (code, ppc_r0);
5899 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5902 ppc_load (code, ppc_r0, (gulong)item->key);
5903 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5904 item->jmp_code = code;
5905 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5906 if (item->has_target_code) {
5907 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5910 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5911 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5913 ppc_mtctr (code, ppc_r0);
5914 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5915 ppc_patch (item->jmp_code, code);
5916 ppc_load_ptr (code, ppc_r0, fail_tramp);
5917 ppc_mtctr (code, ppc_r0);
5918 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5919 item->jmp_code = NULL;
5921 /* enable the commented code to assert on wrong method */
5922 #if ENABLE_WRONG_METHOD_CHECK
5923 ppc_load (code, ppc_r0, (guint32)item->key);
5924 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5925 item->jmp_code = code;
5926 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5928 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5929 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5930 ppc_mtctr (code, ppc_r0);
5931 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5932 #if ENABLE_WRONG_METHOD_CHECK
5933 ppc_patch (item->jmp_code, code);
5935 item->jmp_code = NULL;
5940 ppc_load (code, ppc_r0, (gulong)item->key);
5941 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5942 item->jmp_code = code;
5943 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5946 /* patch the branches to get to the target items */
5947 for (i = 0; i < count; ++i) {
5948 MonoIMTCheckItem *item = imt_entries [i];
5949 if (item->jmp_code) {
5950 if (item->check_target_idx) {
5951 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5957 mono_stats.imt_thunks_size += code - start;
5958 g_assert (code - start <= size);
5959 mono_arch_flush_icache (start, size);
5961 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5967 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5969 mgreg_t *r = (mgreg_t*)regs;
5971 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5975 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5977 mgreg_t *r = (mgreg_t*)regs;
5979 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5983 mono_arch_get_cie_program (void)
5987 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5993 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
6000 mono_arch_print_tree (MonoInst *tree, int arity)
6006 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6009 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6011 g_assert (reg >= ppc_r13);
6013 return ctx->regs [reg - ppc_r13];
6017 mono_arch_get_patch_offset (guint8 *code)
6023 * mono_aot_emit_load_got_addr:
6025 * Emit code to load the got address.
6026 * On PPC, the result is placed into r30.
6029 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6032 ppc_mflr (code, ppc_r30);
6034 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6036 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6037 /* arch_emit_got_address () patches this */
6038 #if defined(TARGET_POWERPC64)
6044 ppc_load32 (code, ppc_r0, 0);
6045 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6052 * mono_ppc_emit_load_aotconst:
6054 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6055 * TARGET from the mscorlib GOT in full-aot code.
6056 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6060 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6062 /* Load the mscorlib got address */
6063 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6064 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6065 /* arch_emit_got_access () patches this */
6066 ppc_load32 (code, ppc_r0, 0);
6067 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6072 /* Soft Debug support */
6073 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6080 * mono_arch_set_breakpoint:
6082 * See mini-amd64.c for docs.
6085 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6088 guint8 *orig_code = code;
6090 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6091 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6093 g_assert (code - orig_code == BREAKPOINT_SIZE);
6095 mono_arch_flush_icache (orig_code, code - orig_code);
6099 * mono_arch_clear_breakpoint:
6101 * See mini-amd64.c for docs.
6104 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6109 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6112 mono_arch_flush_icache (ip, code - ip);
6116 * mono_arch_is_breakpoint_event:
6118 * See mini-amd64.c for docs.
6121 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6123 siginfo_t* sinfo = (siginfo_t*) info;
6124 /* Sometimes the address is off by 4 */
6125 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6132 * mono_arch_skip_breakpoint:
6134 * See mini-amd64.c for docs.
6137 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6139 /* skip the ldptr */
6140 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6148 * mono_arch_start_single_stepping:
6150 * See mini-amd64.c for docs.
6153 mono_arch_start_single_stepping (void)
6155 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6159 * mono_arch_stop_single_stepping:
6161 * See mini-amd64.c for docs.
6164 mono_arch_stop_single_stepping (void)
6166 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6170 * mono_arch_is_single_step_event:
6172 * See mini-amd64.c for docs.
6175 mono_arch_is_single_step_event (void *info, void *sigctx)
6177 siginfo_t* sinfo = (siginfo_t*) info;
6178 /* Sometimes the address is off by 4 */
6179 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6186 * mono_arch_skip_single_step:
6188 * See mini-amd64.c for docs.
6191 mono_arch_skip_single_step (MonoContext *ctx)
6193 /* skip the ldptr */
6194 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6198 * mono_arch_create_seq_point_info:
6200 * See mini-amd64.c for docs.
6203 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6210 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6212 ext->lmf.previous_lmf = prev_lmf;
6213 /* Mark that this is a MonoLMFExt */
6214 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6215 ext->lmf.ebp = (gssize)ext;
6221 mono_arch_opcode_supported (int opcode)
6224 case OP_ATOMIC_ADD_I4:
6225 case OP_ATOMIC_CAS_I4:
6226 #ifdef TARGET_POWERPC64
6227 case OP_ATOMIC_ADD_I8:
6228 case OP_ATOMIC_CAS_I8:
6238 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6239 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6240 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6243 mono_arch_create_handler_block_trampoline (void)