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, MonoError *error)
4748 MonoJumpInfo *patch_info;
4749 gboolean compile_aot = !run_cctors;
4751 mono_error_init (error);
4753 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4754 unsigned char *ip = patch_info->ip.i + code;
4755 unsigned char *target;
4756 gboolean is_fd = FALSE;
4758 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4759 return_if_nok (error);
4762 switch (patch_info->type) {
4763 case MONO_PATCH_INFO_BB:
4764 case MONO_PATCH_INFO_LABEL:
4767 /* No need to patch these */
4772 switch (patch_info->type) {
4773 case MONO_PATCH_INFO_IP:
4774 patch_load_sequence (ip, ip);
4776 case MONO_PATCH_INFO_METHOD_REL:
4777 g_assert_not_reached ();
4778 *((gpointer *)(ip)) = code + patch_info->data.offset;
4780 case MONO_PATCH_INFO_SWITCH: {
4781 gpointer *table = (gpointer *)patch_info->data.table->table;
4784 patch_load_sequence (ip, table);
4786 for (i = 0; i < patch_info->data.table->table_size; i++) {
4787 table [i] = (glong)patch_info->data.table->table [i] + code;
4789 /* we put into the table the absolute address, no need for ppc_patch in this case */
4792 case MONO_PATCH_INFO_METHODCONST:
4793 case MONO_PATCH_INFO_CLASS:
4794 case MONO_PATCH_INFO_IMAGE:
4795 case MONO_PATCH_INFO_FIELD:
4796 case MONO_PATCH_INFO_VTABLE:
4797 case MONO_PATCH_INFO_IID:
4798 case MONO_PATCH_INFO_SFLDA:
4799 case MONO_PATCH_INFO_LDSTR:
4800 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4801 case MONO_PATCH_INFO_LDTOKEN:
4802 /* from OP_AOTCONST : lis + ori */
4803 patch_load_sequence (ip, target);
4805 case MONO_PATCH_INFO_R4:
4806 case MONO_PATCH_INFO_R8:
4807 g_assert_not_reached ();
4808 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4810 case MONO_PATCH_INFO_EXC_NAME:
4811 g_assert_not_reached ();
4812 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4814 case MONO_PATCH_INFO_NONE:
4815 case MONO_PATCH_INFO_BB_OVF:
4816 case MONO_PATCH_INFO_EXC_OVF:
4817 /* everything is dealt with at epilog output time */
4819 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4820 case MONO_PATCH_INFO_INTERNAL_METHOD:
4821 case MONO_PATCH_INFO_ABS:
4822 case MONO_PATCH_INFO_RGCTX_FETCH:
4823 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4830 ppc_patch_full (ip, target, is_fd);
4835 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4836 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4837 * the instruction offset immediate for all the registers.
4840 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4844 for (i = 13; i <= 31; i++) {
4845 if (used_int_regs & (1 << i)) {
4846 ppc_str (code, i, pos, base_reg);
4847 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4848 pos += sizeof (mgreg_t);
4852 /* pos is the start of the MonoLMF structure */
4853 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4854 for (i = 13; i <= 31; i++) {
4855 ppc_str (code, i, offset, base_reg);
4856 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4857 offset += sizeof (mgreg_t);
4859 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4860 for (i = 14; i < 32; i++) {
4861 ppc_stfd (code, i, offset, base_reg);
4862 offset += sizeof (gdouble);
4869 * Stack frame layout:
4871 * ------------------- sp
4872 * MonoLMF structure or saved registers
4873 * -------------------
4875 * -------------------
4877 * -------------------
4878 * optional 8 bytes for tracing
4879 * -------------------
4880 * param area size is cfg->param_area
4881 * -------------------
4882 * linkage area size is PPC_STACK_PARAM_OFFSET
4883 * ------------------- sp
4887 mono_arch_emit_prolog (MonoCompile *cfg)
4889 MonoMethod *method = cfg->method;
4891 MonoMethodSignature *sig;
4893 long alloc_size, pos, max_offset, cfa_offset;
4899 int tailcall_struct_index;
4901 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4904 sig = mono_method_signature (method);
4905 cfg->code_size = 512 + sig->param_count * 32;
4906 code = cfg->native_code = g_malloc (cfg->code_size);
4910 /* We currently emit unwind info for aot, but don't use it */
4911 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4913 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4914 ppc_mflr (code, ppc_r0);
4915 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4916 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4919 alloc_size = cfg->stack_offset;
4922 if (!method->save_lmf) {
4923 for (i = 31; i >= 13; --i) {
4924 if (cfg->used_int_regs & (1 << i)) {
4925 pos += sizeof (mgreg_t);
4929 pos += sizeof (MonoLMF);
4933 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4934 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4935 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4936 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4939 cfg->stack_usage = alloc_size;
4940 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4942 if (ppc_is_imm16 (-alloc_size)) {
4943 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4944 cfa_offset = alloc_size;
4945 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4946 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4949 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4950 ppc_load (code, ppc_r0, -alloc_size);
4951 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4952 cfa_offset = alloc_size;
4953 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4954 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4957 if (cfg->frame_reg != ppc_sp) {
4958 ppc_mr (code, cfg->frame_reg, ppc_sp);
4959 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4962 /* store runtime generic context */
4963 if (cfg->rgctx_var) {
4964 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4965 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4967 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4970 /* compute max_offset in order to use short forward jumps
4971 * we always do it on ppc because the immediate displacement
4972 * for jumps is too small
4975 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4977 bb->max_offset = max_offset;
4979 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4982 MONO_BB_FOR_EACH_INS (bb, ins)
4983 max_offset += ins_native_length (cfg, ins);
4986 /* load arguments allocated to register from the stack */
4989 cinfo = get_call_info (sig);
4991 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4992 ArgInfo *ainfo = &cinfo->ret;
4994 inst = cfg->vret_addr;
4997 if (ppc_is_imm16 (inst->inst_offset)) {
4998 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5000 ppc_load (code, ppc_r12, inst->inst_offset);
5001 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5005 tailcall_struct_index = 0;
5006 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5007 ArgInfo *ainfo = cinfo->args + i;
5008 inst = cfg->args [pos];
5010 if (cfg->verbose_level > 2)
5011 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5012 if (inst->opcode == OP_REGVAR) {
5013 if (ainfo->regtype == RegTypeGeneral)
5014 ppc_mr (code, inst->dreg, ainfo->reg);
5015 else if (ainfo->regtype == RegTypeFP)
5016 ppc_fmr (code, inst->dreg, ainfo->reg);
5017 else if (ainfo->regtype == RegTypeBase) {
5018 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5019 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5021 g_assert_not_reached ();
5023 if (cfg->verbose_level > 2)
5024 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5026 /* the argument should be put on the stack: FIXME handle size != word */
5027 if (ainfo->regtype == RegTypeGeneral) {
5028 switch (ainfo->size) {
5030 if (ppc_is_imm16 (inst->inst_offset)) {
5031 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5033 if (ppc_is_imm32 (inst->inst_offset)) {
5034 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5035 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5037 ppc_load (code, ppc_r12, inst->inst_offset);
5038 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5043 if (ppc_is_imm16 (inst->inst_offset)) {
5044 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5046 if (ppc_is_imm32 (inst->inst_offset)) {
5047 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5048 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5050 ppc_load (code, ppc_r12, inst->inst_offset);
5051 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5055 #ifdef __mono_ppc64__
5057 if (ppc_is_imm16 (inst->inst_offset)) {
5058 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5060 if (ppc_is_imm32 (inst->inst_offset)) {
5061 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5062 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5064 ppc_load (code, ppc_r12, inst->inst_offset);
5065 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5070 if (ppc_is_imm16 (inst->inst_offset)) {
5071 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5073 ppc_load (code, ppc_r12, inst->inst_offset);
5074 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5079 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5080 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5081 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5083 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5084 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5085 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5086 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5091 if (ppc_is_imm16 (inst->inst_offset)) {
5092 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5094 if (ppc_is_imm32 (inst->inst_offset)) {
5095 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5096 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5098 ppc_load (code, ppc_r12, inst->inst_offset);
5099 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5104 } else if (ainfo->regtype == RegTypeBase) {
5105 g_assert (ppc_is_imm16 (ainfo->offset));
5106 /* load the previous stack pointer in r12 */
5107 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5108 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5109 switch (ainfo->size) {
5111 if (ppc_is_imm16 (inst->inst_offset)) {
5112 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5114 if (ppc_is_imm32 (inst->inst_offset)) {
5115 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5116 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5118 ppc_load (code, ppc_r12, inst->inst_offset);
5119 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5124 if (ppc_is_imm16 (inst->inst_offset)) {
5125 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5127 if (ppc_is_imm32 (inst->inst_offset)) {
5128 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5129 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5131 ppc_load (code, ppc_r12, inst->inst_offset);
5132 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5136 #ifdef __mono_ppc64__
5138 if (ppc_is_imm16 (inst->inst_offset)) {
5139 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5141 if (ppc_is_imm32 (inst->inst_offset)) {
5142 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5143 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5145 ppc_load (code, ppc_r12, inst->inst_offset);
5146 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5151 if (ppc_is_imm16 (inst->inst_offset)) {
5152 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5154 ppc_load (code, ppc_r12, inst->inst_offset);
5155 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5160 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5161 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5162 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5163 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5164 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5166 /* use r11 to load the 2nd half of the long before we clobber r12. */
5167 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5168 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5169 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5170 ppc_stw (code, ppc_r0, 0, ppc_r12);
5171 ppc_stw (code, ppc_r11, 4, ppc_r12);
5176 if (ppc_is_imm16 (inst->inst_offset)) {
5177 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5179 if (ppc_is_imm32 (inst->inst_offset)) {
5180 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5181 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5183 ppc_load (code, ppc_r12, inst->inst_offset);
5184 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5189 } else if (ainfo->regtype == RegTypeFP) {
5190 g_assert (ppc_is_imm16 (inst->inst_offset));
5191 if (ainfo->size == 8)
5192 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5193 else if (ainfo->size == 4)
5194 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5196 g_assert_not_reached ();
5197 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5198 int doffset = inst->inst_offset;
5202 g_assert (ppc_is_imm16 (inst->inst_offset));
5203 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5204 /* FIXME: what if there is no class? */
5205 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5206 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5207 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5208 if (ainfo->size == 4) {
5209 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5211 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5213 soffset += ainfo->size;
5214 doffset += ainfo->size;
5216 } else if (ainfo->regtype == RegTypeStructByVal) {
5217 int doffset = inst->inst_offset;
5221 g_assert (ppc_is_imm16 (inst->inst_offset));
5222 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5223 /* FIXME: what if there is no class? */
5224 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5225 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5226 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5229 * Darwin handles 1 and 2 byte
5230 * structs specially by
5231 * loading h/b into the arg
5232 * register. Only done for
5236 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5238 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5242 #ifdef __mono_ppc64__
5244 g_assert (cur_reg == 0);
5245 #if G_BYTE_ORDER == G_BIG_ENDIAN
5246 ppc_sldi (code, ppc_r0, ainfo->reg,
5247 (sizeof (gpointer) - ainfo->bytes) * 8);
5248 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5250 if (mono_class_native_size (inst->klass, NULL) == 1) {
5251 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5252 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5253 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5254 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5255 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5257 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5263 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5264 inst->inst_basereg);
5267 soffset += sizeof (gpointer);
5268 doffset += sizeof (gpointer);
5270 if (ainfo->vtsize) {
5271 /* FIXME: we need to do the shifting here, too */
5274 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5275 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5276 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5277 code = emit_memcpy (code, size - soffset,
5278 inst->inst_basereg, doffset,
5279 ppc_r12, ainfo->offset + soffset);
5281 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5282 inst->inst_basereg, doffset,
5283 ppc_r12, ainfo->offset + soffset);
5286 } else if (ainfo->regtype == RegTypeStructByAddr) {
5287 /* if it was originally a RegTypeBase */
5288 if (ainfo->offset) {
5289 /* load the previous stack pointer in r12 */
5290 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5291 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5293 ppc_mr (code, ppc_r12, ainfo->reg);
5296 if (cfg->tailcall_valuetype_addrs) {
5297 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5299 g_assert (ppc_is_imm16 (addr->inst_offset));
5300 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5302 tailcall_struct_index++;
5305 g_assert (ppc_is_imm16 (inst->inst_offset));
5306 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5307 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5309 g_assert_not_reached ();
5314 if (method->save_lmf) {
5315 if (lmf_pthread_key != -1) {
5316 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5317 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5318 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5320 if (cfg->compile_aot) {
5321 /* Compute the got address which is needed by the PLT entry */
5322 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5324 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5325 (gpointer)"mono_get_lmf_addr");
5326 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5327 ppc_load_func (code, PPC_CALL_REG, 0);
5328 ppc_mtlr (code, PPC_CALL_REG);
5334 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5335 /* lmf_offset is the offset from the previous stack pointer,
5336 * alloc_size is the total stack space allocated, so the offset
5337 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5338 * The pointer to the struct is put in ppc_r12 (new_lmf).
5339 * The callee-saved registers are already in the MonoLMF structure
5341 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5342 /* ppc_r3 is the result from mono_get_lmf_addr () */
5343 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5344 /* new_lmf->previous_lmf = *lmf_addr */
5345 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5346 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5347 /* *(lmf_addr) = r12 */
5348 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5349 /* save method info */
5350 if (cfg->compile_aot)
5352 ppc_load (code, ppc_r0, 0);
5354 ppc_load_ptr (code, ppc_r0, method);
5355 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5356 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5357 /* save the current IP */
5358 if (cfg->compile_aot) {
5360 ppc_mflr (code, ppc_r0);
5362 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5363 #ifdef __mono_ppc64__
5364 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5366 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5369 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5373 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5375 cfg->code_len = code - cfg->native_code;
5376 g_assert (cfg->code_len <= cfg->code_size);
5383 mono_arch_emit_epilog (MonoCompile *cfg)
5385 MonoMethod *method = cfg->method;
5387 int max_epilog_size = 16 + 20*4;
5390 if (cfg->method->save_lmf)
5391 max_epilog_size += 128;
5393 if (mono_jit_trace_calls != NULL)
5394 max_epilog_size += 50;
5396 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5397 max_epilog_size += 50;
5399 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5400 cfg->code_size *= 2;
5401 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5402 cfg->stat_code_reallocs++;
5406 * Keep in sync with OP_JMP
5408 code = cfg->native_code + cfg->code_len;
5410 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5411 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5415 if (method->save_lmf) {
5417 pos += sizeof (MonoLMF);
5419 /* save the frame reg in r8 */
5420 ppc_mr (code, ppc_r8, cfg->frame_reg);
5421 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5422 /* r5 = previous_lmf */
5423 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5425 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5426 /* *(lmf_addr) = previous_lmf */
5427 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5428 /* FIXME: speedup: there is no actual need to restore the registers if
5429 * we didn't actually change them (idea from Zoltan).
5432 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5434 /*for (i = 14; i < 32; i++) {
5435 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5437 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5438 /* use the saved copy of the frame reg in r8 */
5439 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5440 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5441 ppc_mtlr (code, ppc_r0);
5443 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5445 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5446 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5447 if (ppc_is_imm16 (return_offset)) {
5448 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5450 ppc_load (code, ppc_r12, return_offset);
5451 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5453 ppc_mtlr (code, ppc_r0);
5455 if (ppc_is_imm16 (cfg->stack_usage)) {
5456 int offset = cfg->stack_usage;
5457 for (i = 13; i <= 31; i++) {
5458 if (cfg->used_int_regs & (1 << i))
5459 offset -= sizeof (mgreg_t);
5461 if (cfg->frame_reg != ppc_sp)
5462 ppc_mr (code, ppc_r12, cfg->frame_reg);
5463 /* note r31 (possibly the frame register) is restored last */
5464 for (i = 13; i <= 31; i++) {
5465 if (cfg->used_int_regs & (1 << i)) {
5466 ppc_ldr (code, i, offset, cfg->frame_reg);
5467 offset += sizeof (mgreg_t);
5470 if (cfg->frame_reg != ppc_sp)
5471 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5473 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5475 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5476 if (cfg->used_int_regs) {
5477 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5478 for (i = 31; i >= 13; --i) {
5479 if (cfg->used_int_regs & (1 << i)) {
5480 pos += sizeof (mgreg_t);
5481 ppc_ldr (code, i, -pos, ppc_r12);
5484 ppc_mr (code, ppc_sp, ppc_r12);
5486 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5493 cfg->code_len = code - cfg->native_code;
5495 g_assert (cfg->code_len < cfg->code_size);
5498 #endif /* ifndef DISABLE_JIT */
5500 /* remove once throw_exception_by_name is eliminated */
5502 exception_id_by_name (const char *name)
5504 if (strcmp (name, "IndexOutOfRangeException") == 0)
5505 return MONO_EXC_INDEX_OUT_OF_RANGE;
5506 if (strcmp (name, "OverflowException") == 0)
5507 return MONO_EXC_OVERFLOW;
5508 if (strcmp (name, "ArithmeticException") == 0)
5509 return MONO_EXC_ARITHMETIC;
5510 if (strcmp (name, "DivideByZeroException") == 0)
5511 return MONO_EXC_DIVIDE_BY_ZERO;
5512 if (strcmp (name, "InvalidCastException") == 0)
5513 return MONO_EXC_INVALID_CAST;
5514 if (strcmp (name, "NullReferenceException") == 0)
5515 return MONO_EXC_NULL_REF;
5516 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5517 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5518 if (strcmp (name, "ArgumentException") == 0)
5519 return MONO_EXC_ARGUMENT;
5520 g_error ("Unknown intrinsic exception %s\n", name);
5526 mono_arch_emit_exceptions (MonoCompile *cfg)
5528 MonoJumpInfo *patch_info;
5531 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5532 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5533 int max_epilog_size = 50;
5535 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5536 exc_throw_pos [i] = NULL;
5537 exc_throw_found [i] = 0;
5540 /* count the number of exception infos */
5543 * make sure we have enough space for exceptions
5545 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5546 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5547 i = exception_id_by_name (patch_info->data.target);
5548 if (!exc_throw_found [i]) {
5549 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5550 exc_throw_found [i] = TRUE;
5552 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5553 max_epilog_size += 12;
5554 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5555 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5556 i = exception_id_by_name (ovfj->data.exception);
5557 if (!exc_throw_found [i]) {
5558 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5559 exc_throw_found [i] = TRUE;
5561 max_epilog_size += 8;
5565 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5566 cfg->code_size *= 2;
5567 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5568 cfg->stat_code_reallocs++;
5571 code = cfg->native_code + cfg->code_len;
5573 /* add code to raise exceptions */
5574 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5575 switch (patch_info->type) {
5576 case MONO_PATCH_INFO_BB_OVF: {
5577 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5578 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5579 /* patch the initial jump */
5580 ppc_patch (ip, code);
5581 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5583 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5584 /* jump back to the true target */
5586 ip = ovfj->data.bb->native_offset + cfg->native_code;
5587 ppc_patch (code - 4, ip);
5588 patch_info->type = MONO_PATCH_INFO_NONE;
5591 case MONO_PATCH_INFO_EXC_OVF: {
5592 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5593 MonoJumpInfo *newji;
5594 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5595 unsigned char *bcl = code;
5596 /* patch the initial jump: we arrived here with a call */
5597 ppc_patch (ip, code);
5598 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5600 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5601 /* patch the conditional jump to the right handler */
5602 /* make it processed next */
5603 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5604 newji->type = MONO_PATCH_INFO_EXC;
5605 newji->ip.i = bcl - cfg->native_code;
5606 newji->data.target = ovfj->data.exception;
5607 newji->next = patch_info->next;
5608 patch_info->next = newji;
5609 patch_info->type = MONO_PATCH_INFO_NONE;
5612 case MONO_PATCH_INFO_EXC: {
5613 MonoClass *exc_class;
5615 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5616 i = exception_id_by_name (patch_info->data.target);
5617 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5618 ppc_patch (ip, exc_throw_pos [i]);
5619 patch_info->type = MONO_PATCH_INFO_NONE;
5622 exc_throw_pos [i] = code;
5625 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5627 ppc_patch (ip, code);
5628 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5629 ppc_load (code, ppc_r3, exc_class->type_token);
5630 /* we got here from a conditional call, so the calling ip is set in lr */
5631 ppc_mflr (code, ppc_r4);
5632 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5633 patch_info->data.name = "mono_arch_throw_corlib_exception";
5634 patch_info->ip.i = code - cfg->native_code;
5635 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5636 ppc_load_func (code, PPC_CALL_REG, 0);
5637 ppc_mtctr (code, PPC_CALL_REG);
5638 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5650 cfg->code_len = code - cfg->native_code;
5652 g_assert (cfg->code_len <= cfg->code_size);
5658 try_offset_access (void *value, guint32 idx)
5660 register void* me __asm__ ("r2");
5661 void ***p = (void***)((char*)me + 284);
5662 int idx1 = idx / 32;
5663 int idx2 = idx % 32;
5666 if (value != p[idx1][idx2])
5673 setup_tls_access (void)
5675 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5676 size_t conf_size = 0;
5679 /* FIXME for darwin */
5680 guint32 *ins, *code;
5681 guint32 cmplwi_1023, li_0x48, blr_ins;
5685 tls_mode = TLS_MODE_FAILED;
5688 if (tls_mode == TLS_MODE_FAILED)
5690 if (g_getenv ("MONO_NO_TLS")) {
5691 tls_mode = TLS_MODE_FAILED;
5695 if (tls_mode == TLS_MODE_DETECT) {
5696 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5697 tls_mode = TLS_MODE_DARWIN_G4;
5698 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5699 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5700 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5701 tls_mode = TLS_MODE_NPTL;
5702 #elif !defined(TARGET_PS3)
5703 ins = (guint32*)pthread_getspecific;
5704 /* uncond branch to the real method */
5705 if ((*ins >> 26) == 18) {
5707 val = (*ins & ~3) << 6;
5711 ins = (guint32*)(long)val;
5713 ins = (guint32*) ((char*)ins + val);
5716 code = &cmplwi_1023;
5717 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5719 ppc_li (code, ppc_r4, 0x48);
5722 if (*ins == cmplwi_1023) {
5723 int found_lwz_284 = 0;
5725 for (ptk = 0; ptk < 20; ++ptk) {
5727 if (!*ins || *ins == blr_ins)
5729 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5734 if (!found_lwz_284) {
5735 tls_mode = TLS_MODE_FAILED;
5738 tls_mode = TLS_MODE_LTHREADS;
5739 } else if (*ins == li_0x48) {
5741 /* uncond branch to the real method */
5742 if ((*ins >> 26) == 18) {
5744 val = (*ins & ~3) << 6;
5748 ins = (guint32*)(long)val;
5750 ins = (guint32*) ((char*)ins + val);
5752 code = (guint32*)&val;
5753 ppc_li (code, ppc_r0, 0x7FF2);
5754 if (ins [1] == val) {
5755 /* Darwin on G4, implement */
5756 tls_mode = TLS_MODE_FAILED;
5759 code = (guint32*)&val;
5760 ppc_mfspr (code, ppc_r3, 104);
5761 if (ins [1] != val) {
5762 tls_mode = TLS_MODE_FAILED;
5765 tls_mode = TLS_MODE_DARWIN_G5;
5768 tls_mode = TLS_MODE_FAILED;
5772 tls_mode = TLS_MODE_FAILED;
5778 if (tls_mode == TLS_MODE_DETECT)
5779 tls_mode = TLS_MODE_FAILED;
5780 if (tls_mode == TLS_MODE_FAILED)
5782 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5783 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5787 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5788 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5789 if (lmf_pthread_key == -1) {
5790 guint32 ptk = mono_jit_tls_id;
5792 /*g_print ("MonoLMF at: %d\n", ptk);*/
5793 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5794 init_tls_failed = 1;
5797 lmf_pthread_key = ptk;
5806 mono_arch_finish_init (void)
5808 setup_tls_access ();
5812 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5816 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5818 #define LOADSTORE_SIZE 4
5819 #define JUMP_IMM_SIZE 12
5820 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5821 #define ENABLE_WRONG_METHOD_CHECK 0
5824 * LOCKING: called with the domain lock held
5827 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5828 gpointer fail_tramp)
5832 guint8 *code, *start;
5834 for (i = 0; i < count; ++i) {
5835 MonoIMTCheckItem *item = imt_entries [i];
5836 if (item->is_equals) {
5837 if (item->check_target_idx) {
5838 if (!item->compare_done)
5839 item->chunk_size += CMP_SIZE;
5840 if (item->has_target_code)
5841 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5843 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5846 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5847 if (!item->has_target_code)
5848 item->chunk_size += LOADSTORE_SIZE;
5850 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5851 #if ENABLE_WRONG_METHOD_CHECK
5852 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5857 item->chunk_size += CMP_SIZE + BR_SIZE;
5858 imt_entries [item->check_target_idx]->compare_done = TRUE;
5860 size += item->chunk_size;
5862 /* the initial load of the vtable address */
5863 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5865 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5867 code = mono_domain_code_reserve (domain, size);
5872 * We need to save and restore r12 because it might be
5873 * used by the caller as the vtable register, so
5874 * clobbering it will trip up the magic trampoline.
5876 * FIXME: Get rid of this by making sure that r12 is
5877 * not used as the vtable register in interface calls.
5879 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5880 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5882 for (i = 0; i < count; ++i) {
5883 MonoIMTCheckItem *item = imt_entries [i];
5884 item->code_target = code;
5885 if (item->is_equals) {
5886 if (item->check_target_idx) {
5887 if (!item->compare_done) {
5888 ppc_load (code, ppc_r0, (gsize)item->key);
5889 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5891 item->jmp_code = code;
5892 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5893 if (item->has_target_code) {
5894 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5896 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5897 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5899 ppc_mtctr (code, ppc_r0);
5900 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5903 ppc_load (code, ppc_r0, (gulong)item->key);
5904 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5905 item->jmp_code = code;
5906 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5907 if (item->has_target_code) {
5908 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5911 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5912 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5914 ppc_mtctr (code, ppc_r0);
5915 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5916 ppc_patch (item->jmp_code, code);
5917 ppc_load_ptr (code, ppc_r0, fail_tramp);
5918 ppc_mtctr (code, ppc_r0);
5919 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5920 item->jmp_code = NULL;
5922 /* enable the commented code to assert on wrong method */
5923 #if ENABLE_WRONG_METHOD_CHECK
5924 ppc_load (code, ppc_r0, (guint32)item->key);
5925 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5926 item->jmp_code = code;
5927 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5929 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5930 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5931 ppc_mtctr (code, ppc_r0);
5932 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5933 #if ENABLE_WRONG_METHOD_CHECK
5934 ppc_patch (item->jmp_code, code);
5936 item->jmp_code = NULL;
5941 ppc_load (code, ppc_r0, (gulong)item->key);
5942 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5943 item->jmp_code = code;
5944 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5947 /* patch the branches to get to the target items */
5948 for (i = 0; i < count; ++i) {
5949 MonoIMTCheckItem *item = imt_entries [i];
5950 if (item->jmp_code) {
5951 if (item->check_target_idx) {
5952 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5958 mono_stats.imt_thunks_size += code - start;
5959 g_assert (code - start <= size);
5960 mono_arch_flush_icache (start, size);
5962 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5968 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5970 mgreg_t *r = (mgreg_t*)regs;
5972 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5976 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5978 mgreg_t *r = (mgreg_t*)regs;
5980 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5984 mono_arch_get_cie_program (void)
5988 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5994 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
6001 mono_arch_print_tree (MonoInst *tree, int arity)
6007 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6010 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6012 g_assert (reg >= ppc_r13);
6014 return ctx->regs [reg - ppc_r13];
6018 mono_arch_get_patch_offset (guint8 *code)
6024 * mono_aot_emit_load_got_addr:
6026 * Emit code to load the got address.
6027 * On PPC, the result is placed into r30.
6030 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6033 ppc_mflr (code, ppc_r30);
6035 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6037 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6038 /* arch_emit_got_address () patches this */
6039 #if defined(TARGET_POWERPC64)
6045 ppc_load32 (code, ppc_r0, 0);
6046 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6053 * mono_ppc_emit_load_aotconst:
6055 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6056 * TARGET from the mscorlib GOT in full-aot code.
6057 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6061 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6063 /* Load the mscorlib got address */
6064 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6065 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6066 /* arch_emit_got_access () patches this */
6067 ppc_load32 (code, ppc_r0, 0);
6068 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6073 /* Soft Debug support */
6074 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6081 * mono_arch_set_breakpoint:
6083 * See mini-amd64.c for docs.
6086 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6089 guint8 *orig_code = code;
6091 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6092 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6094 g_assert (code - orig_code == BREAKPOINT_SIZE);
6096 mono_arch_flush_icache (orig_code, code - orig_code);
6100 * mono_arch_clear_breakpoint:
6102 * See mini-amd64.c for docs.
6105 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6110 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6113 mono_arch_flush_icache (ip, code - ip);
6117 * mono_arch_is_breakpoint_event:
6119 * See mini-amd64.c for docs.
6122 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6124 siginfo_t* sinfo = (siginfo_t*) info;
6125 /* Sometimes the address is off by 4 */
6126 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6133 * mono_arch_skip_breakpoint:
6135 * See mini-amd64.c for docs.
6138 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6140 /* skip the ldptr */
6141 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6149 * mono_arch_start_single_stepping:
6151 * See mini-amd64.c for docs.
6154 mono_arch_start_single_stepping (void)
6156 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6160 * mono_arch_stop_single_stepping:
6162 * See mini-amd64.c for docs.
6165 mono_arch_stop_single_stepping (void)
6167 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6171 * mono_arch_is_single_step_event:
6173 * See mini-amd64.c for docs.
6176 mono_arch_is_single_step_event (void *info, void *sigctx)
6178 siginfo_t* sinfo = (siginfo_t*) info;
6179 /* Sometimes the address is off by 4 */
6180 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6187 * mono_arch_skip_single_step:
6189 * See mini-amd64.c for docs.
6192 mono_arch_skip_single_step (MonoContext *ctx)
6194 /* skip the ldptr */
6195 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6199 * mono_arch_create_seq_point_info:
6201 * See mini-amd64.c for docs.
6204 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6211 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6213 ext->lmf.previous_lmf = prev_lmf;
6214 /* Mark that this is a MonoLMFExt */
6215 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6216 ext->lmf.ebp = (gssize)ext;
6222 mono_arch_opcode_supported (int opcode)
6225 case OP_ATOMIC_ADD_I4:
6226 case OP_ATOMIC_CAS_I4:
6227 #ifdef TARGET_POWERPC64
6228 case OP_ATOMIC_ADD_I8:
6229 case OP_ATOMIC_CAS_I8:
6239 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6240 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6241 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6244 mono_arch_create_handler_block_trampoline (void)