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 = in->dreg + 1;
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 = in->dreg + 2;
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 = val->dreg + 1;
1914 ins->sreg2 = val->dreg + 2;
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, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2415 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2418 case OP_LADD_OVF_UN:
2419 /* ADC sets the condition code */
2420 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2421 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2425 /* SBB sets the condition code */
2426 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2427 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2430 case OP_LSUB_OVF_UN:
2431 /* SBB sets the condition code */
2432 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2433 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2437 /* From gcc generated code */
2438 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2439 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
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 return mono_op_imm_to_op (op);
2574 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2576 #define compare_opcode_is_unsigned(opcode) \
2577 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2578 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2579 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2580 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2581 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2582 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2583 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2584 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2587 * Remove from the instruction list the instructions that can't be
2588 * represented with very simple instructions with no register
2592 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2594 MonoInst *ins, *next, *temp, *last_ins = NULL;
2597 MONO_BB_FOR_EACH_INS (bb, ins) {
2599 switch (ins->opcode) {
2600 case OP_IDIV_UN_IMM:
2603 case OP_IREM_UN_IMM:
2604 CASE_PPC64 (OP_LREM_IMM) {
2605 NEW_INS (cfg, temp, OP_ICONST);
2606 temp->inst_c0 = ins->inst_imm;
2607 temp->dreg = mono_alloc_ireg (cfg);
2608 ins->sreg2 = temp->dreg;
2609 if (ins->opcode == OP_IDIV_IMM)
2610 ins->opcode = OP_IDIV;
2611 else if (ins->opcode == OP_IREM_IMM)
2612 ins->opcode = OP_IREM;
2613 else if (ins->opcode == OP_IDIV_UN_IMM)
2614 ins->opcode = OP_IDIV_UN;
2615 else if (ins->opcode == OP_IREM_UN_IMM)
2616 ins->opcode = OP_IREM_UN;
2617 else if (ins->opcode == OP_LREM_IMM)
2618 ins->opcode = OP_LREM;
2620 /* handle rem separately */
2625 CASE_PPC64 (OP_LREM)
2626 CASE_PPC64 (OP_LREM_UN) {
2628 /* we change a rem dest, src1, src2 to
2629 * div temp1, src1, src2
2630 * mul temp2, temp1, src2
2631 * sub dest, src1, temp2
2633 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2634 NEW_INS (cfg, mul, OP_IMUL);
2635 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2636 ins->opcode = OP_ISUB;
2638 NEW_INS (cfg, mul, OP_LMUL);
2639 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2640 ins->opcode = OP_LSUB;
2642 temp->sreg1 = ins->sreg1;
2643 temp->sreg2 = ins->sreg2;
2644 temp->dreg = mono_alloc_ireg (cfg);
2645 mul->sreg1 = temp->dreg;
2646 mul->sreg2 = ins->sreg2;
2647 mul->dreg = mono_alloc_ireg (cfg);
2648 ins->sreg2 = mul->dreg;
2652 CASE_PPC64 (OP_LADD_IMM)
2655 if (!ppc_is_imm16 (ins->inst_imm)) {
2656 NEW_INS (cfg, temp, OP_ICONST);
2657 temp->inst_c0 = ins->inst_imm;
2658 temp->dreg = mono_alloc_ireg (cfg);
2659 ins->sreg2 = temp->dreg;
2660 ins->opcode = map_to_reg_reg_op (ins->opcode);
2664 CASE_PPC64 (OP_LSUB_IMM)
2666 if (!ppc_is_imm16 (-ins->inst_imm)) {
2667 NEW_INS (cfg, temp, OP_ICONST);
2668 temp->inst_c0 = ins->inst_imm;
2669 temp->dreg = mono_alloc_ireg (cfg);
2670 ins->sreg2 = temp->dreg;
2671 ins->opcode = map_to_reg_reg_op (ins->opcode);
2683 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2684 #ifdef __mono_ppc64__
2685 if (ins->inst_imm & 0xffffffff00000000ULL)
2689 NEW_INS (cfg, temp, OP_ICONST);
2690 temp->inst_c0 = ins->inst_imm;
2691 temp->dreg = mono_alloc_ireg (cfg);
2692 ins->sreg2 = temp->dreg;
2693 ins->opcode = map_to_reg_reg_op (ins->opcode);
2702 NEW_INS (cfg, temp, OP_ICONST);
2703 temp->inst_c0 = ins->inst_imm;
2704 temp->dreg = mono_alloc_ireg (cfg);
2705 ins->sreg2 = temp->dreg;
2706 ins->opcode = map_to_reg_reg_op (ins->opcode);
2708 case OP_COMPARE_IMM:
2709 case OP_ICOMPARE_IMM:
2710 CASE_PPC64 (OP_LCOMPARE_IMM)
2712 /* Branch opts can eliminate the branch */
2713 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2714 ins->opcode = OP_NOP;
2718 if (compare_opcode_is_unsigned (next->opcode)) {
2719 if (!ppc_is_uimm16 (ins->inst_imm)) {
2720 NEW_INS (cfg, temp, OP_ICONST);
2721 temp->inst_c0 = ins->inst_imm;
2722 temp->dreg = mono_alloc_ireg (cfg);
2723 ins->sreg2 = temp->dreg;
2724 ins->opcode = map_to_reg_reg_op (ins->opcode);
2727 if (!ppc_is_imm16 (ins->inst_imm)) {
2728 NEW_INS (cfg, temp, OP_ICONST);
2729 temp->inst_c0 = ins->inst_imm;
2730 temp->dreg = mono_alloc_ireg (cfg);
2731 ins->sreg2 = temp->dreg;
2732 ins->opcode = map_to_reg_reg_op (ins->opcode);
2738 if (ins->inst_imm == 1) {
2739 ins->opcode = OP_MOVE;
2742 if (ins->inst_imm == 0) {
2743 ins->opcode = OP_ICONST;
2747 imm = mono_is_power_of_two (ins->inst_imm);
2749 ins->opcode = OP_SHL_IMM;
2750 ins->inst_imm = imm;
2753 if (!ppc_is_imm16 (ins->inst_imm)) {
2754 NEW_INS (cfg, temp, OP_ICONST);
2755 temp->inst_c0 = ins->inst_imm;
2756 temp->dreg = mono_alloc_ireg (cfg);
2757 ins->sreg2 = temp->dreg;
2758 ins->opcode = map_to_reg_reg_op (ins->opcode);
2761 case OP_LOCALLOC_IMM:
2762 NEW_INS (cfg, temp, OP_ICONST);
2763 temp->inst_c0 = ins->inst_imm;
2764 temp->dreg = mono_alloc_ireg (cfg);
2765 ins->sreg1 = temp->dreg;
2766 ins->opcode = OP_LOCALLOC;
2768 case OP_LOAD_MEMBASE:
2769 case OP_LOADI4_MEMBASE:
2770 CASE_PPC64 (OP_LOADI8_MEMBASE)
2771 case OP_LOADU4_MEMBASE:
2772 case OP_LOADI2_MEMBASE:
2773 case OP_LOADU2_MEMBASE:
2774 case OP_LOADI1_MEMBASE:
2775 case OP_LOADU1_MEMBASE:
2776 case OP_LOADR4_MEMBASE:
2777 case OP_LOADR8_MEMBASE:
2778 case OP_STORE_MEMBASE_REG:
2779 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2780 case OP_STOREI4_MEMBASE_REG:
2781 case OP_STOREI2_MEMBASE_REG:
2782 case OP_STOREI1_MEMBASE_REG:
2783 case OP_STORER4_MEMBASE_REG:
2784 case OP_STORER8_MEMBASE_REG:
2785 /* we can do two things: load the immed in a register
2786 * and use an indexed load, or see if the immed can be
2787 * represented as an ad_imm + a load with a smaller offset
2788 * that fits. We just do the first for now, optimize later.
2790 if (ppc_is_imm16 (ins->inst_offset))
2792 NEW_INS (cfg, temp, OP_ICONST);
2793 temp->inst_c0 = ins->inst_offset;
2794 temp->dreg = mono_alloc_ireg (cfg);
2795 ins->sreg2 = temp->dreg;
2796 ins->opcode = map_to_reg_reg_op (ins->opcode);
2798 case OP_STORE_MEMBASE_IMM:
2799 case OP_STOREI1_MEMBASE_IMM:
2800 case OP_STOREI2_MEMBASE_IMM:
2801 case OP_STOREI4_MEMBASE_IMM:
2802 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2803 NEW_INS (cfg, temp, OP_ICONST);
2804 temp->inst_c0 = ins->inst_imm;
2805 temp->dreg = mono_alloc_ireg (cfg);
2806 ins->sreg1 = temp->dreg;
2807 ins->opcode = map_to_reg_reg_op (ins->opcode);
2809 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2812 if (cfg->compile_aot) {
2813 /* Keep these in the aot case */
2816 NEW_INS (cfg, temp, OP_ICONST);
2817 temp->inst_c0 = (gulong)ins->inst_p0;
2818 temp->dreg = mono_alloc_ireg (cfg);
2819 ins->inst_basereg = temp->dreg;
2820 ins->inst_offset = 0;
2821 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2823 /* make it handle the possibly big ins->inst_offset
2824 * later optimize to use lis + load_membase
2830 bb->last_ins = last_ins;
2831 bb->max_vreg = cfg->next_vreg;
2835 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2837 long offset = cfg->arch.fp_conv_var_offset;
2839 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2840 #ifdef __mono_ppc64__
2842 ppc_fctidz (code, ppc_f0, sreg);
2847 ppc_fctiwz (code, ppc_f0, sreg);
2850 if (ppc_is_imm16 (offset + sub_offset)) {
2851 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2853 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2855 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2857 ppc_load (code, dreg, offset);
2858 ppc_add (code, dreg, dreg, cfg->frame_reg);
2859 ppc_stfd (code, ppc_f0, 0, dreg);
2861 ppc_ldr (code, dreg, sub_offset, dreg);
2863 ppc_lwz (code, dreg, sub_offset, dreg);
2867 ppc_andid (code, dreg, dreg, 0xff);
2869 ppc_andid (code, dreg, dreg, 0xffff);
2870 #ifdef __mono_ppc64__
2872 ppc_clrldi (code, dreg, dreg, 32);
2876 ppc_extsb (code, dreg, dreg);
2878 ppc_extsh (code, dreg, dreg);
2879 #ifdef __mono_ppc64__
2881 ppc_extsw (code, dreg, dreg);
2889 const guchar *target;
2894 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2897 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2898 #ifdef __mono_ppc64__
2899 g_assert_not_reached ();
2901 PatchData *pdata = (PatchData*)user_data;
2902 guchar *code = data;
2903 guint32 *thunks = data;
2904 guint32 *endthunks = (guint32*)(code + bsize);
2908 int difflow, diffhigh;
2910 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2911 difflow = (char*)pdata->code - (char*)thunks;
2912 diffhigh = (char*)pdata->code - (char*)endthunks;
2913 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2916 templ = (guchar*)load;
2917 ppc_load_sequence (templ, ppc_r0, pdata->target);
2919 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2920 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2921 while (thunks < endthunks) {
2922 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2923 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2924 ppc_patch (pdata->code, (guchar*)thunks);
2927 static int num_thunks = 0;
2929 if ((num_thunks % 20) == 0)
2930 g_print ("num_thunks lookup: %d\n", num_thunks);
2933 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2934 /* found a free slot instead: emit thunk */
2935 code = (guchar*)thunks;
2936 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2937 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2938 ppc_mtctr (code, ppc_r0);
2939 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2940 mono_arch_flush_icache ((guchar*)thunks, 16);
2942 ppc_patch (pdata->code, (guchar*)thunks);
2945 static int num_thunks = 0;
2947 if ((num_thunks % 20) == 0)
2948 g_print ("num_thunks: %d\n", num_thunks);
2952 /* skip 16 bytes, the size of the thunk */
2956 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2963 handle_thunk (int absolute, guchar *code, const guchar *target) {
2964 MonoDomain *domain = mono_domain_get ();
2968 pdata.target = target;
2969 pdata.absolute = absolute;
2972 mono_domain_lock (domain);
2973 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2976 /* this uses the first available slot */
2978 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2980 mono_domain_unlock (domain);
2982 if (pdata.found != 1)
2983 g_print ("thunk failed for %p from %p\n", target, code);
2984 g_assert (pdata.found == 1);
2988 patch_ins (guint8 *code, guint32 ins)
2990 *(guint32*)code = ins;
2991 mono_arch_flush_icache (code, 4);
2995 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2997 guint32 ins = *(guint32*)code;
2998 guint32 prim = ins >> 26;
3001 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3003 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
3004 gint diff = target - code;
3007 if (diff <= 33554431){
3008 ins = (18 << 26) | (diff) | (ins & 1);
3009 patch_ins (code, ins);
3013 /* diff between 0 and -33554432 */
3014 if (diff >= -33554432){
3015 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
3016 patch_ins (code, ins);
3021 if ((glong)target >= 0){
3022 if ((glong)target <= 33554431){
3023 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
3024 patch_ins (code, ins);
3028 if ((glong)target >= -33554432){
3029 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
3030 patch_ins (code, ins);
3035 handle_thunk (TRUE, code, target);
3038 g_assert_not_reached ();
3046 guint32 li = (gulong)target;
3047 ins = (ins & 0xffff0000) | (ins & 3);
3048 ovf = li & 0xffff0000;
3049 if (ovf != 0 && ovf != 0xffff0000)
3050 g_assert_not_reached ();
3053 // FIXME: assert the top bits of li are 0
3055 gint diff = target - code;
3056 ins = (ins & 0xffff0000) | (ins & 3);
3057 ovf = diff & 0xffff0000;
3058 if (ovf != 0 && ovf != 0xffff0000)
3059 g_assert_not_reached ();
3063 patch_ins (code, ins);
3067 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3068 #ifdef __mono_ppc64__
3069 guint32 *seq = (guint32*)code;
3070 guint32 *branch_ins;
3072 /* the trampoline code will try to patch the blrl, blr, bcctr */
3073 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3075 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
3080 if (ppc_is_load_op (seq [5])
3081 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3082 /* With function descs we need to do more careful
3084 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3087 branch_ins = seq + 8;
3089 branch_ins = seq + 6;
3092 seq = (guint32*)code;
3093 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3094 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3096 if (ppc_is_load_op (seq [5])) {
3097 g_assert (ppc_is_load_op (seq [6]));
3100 guint8 *buf = (guint8*)&seq [5];
3101 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3106 target = mono_get_addr_from_ftnptr ((gpointer)target);
3109 /* FIXME: make this thread safe */
3110 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3111 /* FIXME: we're assuming we're using r12 here */
3112 ppc_load_ptr_sequence (code, ppc_r12, target);
3114 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3116 mono_arch_flush_icache ((guint8*)seq, 28);
3119 /* the trampoline code will try to patch the blrl, blr, bcctr */
3120 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3123 /* this is the lis/ori/mtlr/blrl sequence */
3124 seq = (guint32*)code;
3125 g_assert ((seq [0] >> 26) == 15);
3126 g_assert ((seq [1] >> 26) == 24);
3127 g_assert ((seq [2] >> 26) == 31);
3128 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3129 /* FIXME: make this thread safe */
3130 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3131 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3132 mono_arch_flush_icache (code - 8, 8);
3135 g_assert_not_reached ();
3137 // g_print ("patched with 0x%08x\n", ins);
3141 ppc_patch (guchar *code, const guchar *target)
3143 ppc_patch_full (code, target, FALSE);
3147 mono_ppc_patch (guchar *code, const guchar *target)
3149 ppc_patch (code, target);
3153 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3155 switch (ins->opcode) {
3158 case OP_FCALL_MEMBASE:
3159 if (ins->dreg != ppc_f1)
3160 ppc_fmr (code, ins->dreg, ppc_f1);
3168 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3170 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3174 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3176 long size = cfg->param_area;
3178 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3179 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3184 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3185 if (ppc_is_imm16 (-size)) {
3186 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3188 ppc_load (code, ppc_r12, -size);
3189 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3196 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3198 long size = cfg->param_area;
3200 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3201 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3206 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3207 if (ppc_is_imm16 (size)) {
3208 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3210 ppc_load (code, ppc_r12, size);
3211 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3217 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3221 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3223 MonoInst *ins, *next;
3226 guint8 *code = cfg->native_code + cfg->code_len;
3227 MonoInst *last_ins = NULL;
3228 guint last_offset = 0;
3232 /* we don't align basic blocks of loops on ppc */
3234 if (cfg->verbose_level > 2)
3235 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3237 cpos = bb->max_offset;
3239 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3240 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3241 //g_assert (!mono_compile_aot);
3244 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3245 /* this is not thread save, but good enough */
3246 /* fixme: howto handle overflows? */
3247 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3250 MONO_BB_FOR_EACH_INS (bb, ins) {
3251 offset = code - cfg->native_code;
3253 max_len = ins_native_length (cfg, ins);
3255 if (offset > (cfg->code_size - max_len - 16)) {
3256 cfg->code_size *= 2;
3257 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3258 code = cfg->native_code + offset;
3260 // if (ins->cil_code)
3261 // g_print ("cil code\n");
3262 mono_debug_record_line_number (cfg, ins, offset);
3264 switch (normalize_opcode (ins->opcode)) {
3265 case OP_RELAXED_NOP:
3268 case OP_DUMMY_STORE:
3269 case OP_NOT_REACHED:
3272 case OP_IL_SEQ_POINT:
3273 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3275 case OP_SEQ_POINT: {
3278 if (cfg->compile_aot)
3282 * Read from the single stepping trigger page. This will cause a
3283 * SIGSEGV when single stepping is enabled.
3284 * We do this _before_ the breakpoint, so single stepping after
3285 * a breakpoint is hit will step to the next IL offset.
3287 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3288 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3289 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3292 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3295 * A placeholder for a possible breakpoint inserted by
3296 * mono_arch_set_breakpoint ().
3298 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3303 emit_tls_access (code, ins->dreg, ins->inst_offset);
3306 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3307 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3308 ppc_mr (code, ppc_r4, ppc_r0);
3311 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3312 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3313 ppc_mr (code, ppc_r4, ppc_r0);
3315 case OP_MEMORY_BARRIER:
3318 case OP_STOREI1_MEMBASE_REG:
3319 if (ppc_is_imm16 (ins->inst_offset)) {
3320 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3322 if (ppc_is_imm32 (ins->inst_offset)) {
3323 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3324 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3326 ppc_load (code, ppc_r0, ins->inst_offset);
3327 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3331 case OP_STOREI2_MEMBASE_REG:
3332 if (ppc_is_imm16 (ins->inst_offset)) {
3333 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3335 if (ppc_is_imm32 (ins->inst_offset)) {
3336 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3337 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3339 ppc_load (code, ppc_r0, ins->inst_offset);
3340 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3344 case OP_STORE_MEMBASE_REG:
3345 if (ppc_is_imm16 (ins->inst_offset)) {
3346 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3348 if (ppc_is_imm32 (ins->inst_offset)) {
3349 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3350 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3352 ppc_load (code, ppc_r0, ins->inst_offset);
3353 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3357 #ifdef __mono_ilp32__
3358 case OP_STOREI8_MEMBASE_REG:
3359 if (ppc_is_imm16 (ins->inst_offset)) {
3360 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3362 ppc_load (code, ppc_r0, ins->inst_offset);
3363 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3367 case OP_STOREI1_MEMINDEX:
3368 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3370 case OP_STOREI2_MEMINDEX:
3371 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3373 case OP_STORE_MEMINDEX:
3374 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3377 g_assert_not_reached ();
3379 case OP_LOAD_MEMBASE:
3380 if (ppc_is_imm16 (ins->inst_offset)) {
3381 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3383 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3384 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3385 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3387 ppc_load (code, ppc_r0, ins->inst_offset);
3388 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3392 case OP_LOADI4_MEMBASE:
3393 #ifdef __mono_ppc64__
3394 if (ppc_is_imm16 (ins->inst_offset)) {
3395 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3397 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3398 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3399 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3401 ppc_load (code, ppc_r0, ins->inst_offset);
3402 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3407 case OP_LOADU4_MEMBASE:
3408 if (ppc_is_imm16 (ins->inst_offset)) {
3409 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3411 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3412 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3413 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3415 ppc_load (code, ppc_r0, ins->inst_offset);
3416 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3420 case OP_LOADI1_MEMBASE:
3421 case OP_LOADU1_MEMBASE:
3422 if (ppc_is_imm16 (ins->inst_offset)) {
3423 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3425 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3426 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3427 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3429 ppc_load (code, ppc_r0, ins->inst_offset);
3430 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3433 if (ins->opcode == OP_LOADI1_MEMBASE)
3434 ppc_extsb (code, ins->dreg, ins->dreg);
3436 case OP_LOADU2_MEMBASE:
3437 if (ppc_is_imm16 (ins->inst_offset)) {
3438 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3440 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3441 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3442 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3444 ppc_load (code, ppc_r0, ins->inst_offset);
3445 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3449 case OP_LOADI2_MEMBASE:
3450 if (ppc_is_imm16 (ins->inst_offset)) {
3451 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3453 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3454 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3455 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3457 ppc_load (code, ppc_r0, ins->inst_offset);
3458 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3462 #ifdef __mono_ilp32__
3463 case OP_LOADI8_MEMBASE:
3464 if (ppc_is_imm16 (ins->inst_offset)) {
3465 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3467 ppc_load (code, ppc_r0, ins->inst_offset);
3468 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3472 case OP_LOAD_MEMINDEX:
3473 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3475 case OP_LOADI4_MEMINDEX:
3476 #ifdef __mono_ppc64__
3477 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3480 case OP_LOADU4_MEMINDEX:
3481 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3483 case OP_LOADU2_MEMINDEX:
3484 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3486 case OP_LOADI2_MEMINDEX:
3487 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3489 case OP_LOADU1_MEMINDEX:
3490 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3492 case OP_LOADI1_MEMINDEX:
3493 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3494 ppc_extsb (code, ins->dreg, ins->dreg);
3496 case OP_ICONV_TO_I1:
3497 CASE_PPC64 (OP_LCONV_TO_I1)
3498 ppc_extsb (code, ins->dreg, ins->sreg1);
3500 case OP_ICONV_TO_I2:
3501 CASE_PPC64 (OP_LCONV_TO_I2)
3502 ppc_extsh (code, ins->dreg, ins->sreg1);
3504 case OP_ICONV_TO_U1:
3505 CASE_PPC64 (OP_LCONV_TO_U1)
3506 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3508 case OP_ICONV_TO_U2:
3509 CASE_PPC64 (OP_LCONV_TO_U2)
3510 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3514 CASE_PPC64 (OP_LCOMPARE)
3515 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3517 if (next && compare_opcode_is_unsigned (next->opcode))
3518 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3520 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3522 case OP_COMPARE_IMM:
3523 case OP_ICOMPARE_IMM:
3524 CASE_PPC64 (OP_LCOMPARE_IMM)
3525 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3527 if (next && compare_opcode_is_unsigned (next->opcode)) {
3528 if (ppc_is_uimm16 (ins->inst_imm)) {
3529 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3531 g_assert_not_reached ();
3534 if (ppc_is_imm16 (ins->inst_imm)) {
3535 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3537 g_assert_not_reached ();
3543 * gdb does not like encountering a trap in the debugged code. So
3544 * instead of emitting a trap, we emit a call a C function and place a
3548 ppc_mr (code, ppc_r3, ins->sreg1);
3549 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3550 (gpointer)"mono_break");
3551 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3552 ppc_load_func (code, PPC_CALL_REG, 0);
3553 ppc_mtlr (code, PPC_CALL_REG);
3561 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3564 CASE_PPC64 (OP_LADD)
3565 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3569 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3572 if (ppc_is_imm16 (ins->inst_imm)) {
3573 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3575 g_assert_not_reached ();
3580 CASE_PPC64 (OP_LADD_IMM)
3581 if (ppc_is_imm16 (ins->inst_imm)) {
3582 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3584 g_assert_not_reached ();
3588 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3590 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3591 ppc_mfspr (code, ppc_r0, ppc_xer);
3592 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3593 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3595 case OP_IADD_OVF_UN:
3596 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3598 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 ppc_mfspr (code, ppc_r0, ppc_xer);
3600 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3601 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3604 CASE_PPC64 (OP_LSUB_OVF)
3605 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3607 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3608 ppc_mfspr (code, ppc_r0, ppc_xer);
3609 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3610 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3612 case OP_ISUB_OVF_UN:
3613 CASE_PPC64 (OP_LSUB_OVF_UN)
3614 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3616 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3617 ppc_mfspr (code, ppc_r0, ppc_xer);
3618 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3619 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3621 case OP_ADD_OVF_CARRY:
3622 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3624 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 ppc_mfspr (code, ppc_r0, ppc_xer);
3626 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3627 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3629 case OP_ADD_OVF_UN_CARRY:
3630 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3632 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3633 ppc_mfspr (code, ppc_r0, ppc_xer);
3634 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3635 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3637 case OP_SUB_OVF_CARRY:
3638 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3640 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3641 ppc_mfspr (code, ppc_r0, ppc_xer);
3642 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3643 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3645 case OP_SUB_OVF_UN_CARRY:
3646 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3648 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3649 ppc_mfspr (code, ppc_r0, ppc_xer);
3650 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3651 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3655 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3658 CASE_PPC64 (OP_LSUB)
3659 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3663 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3667 CASE_PPC64 (OP_LSUB_IMM)
3668 // we add the negated value
3669 if (ppc_is_imm16 (-ins->inst_imm))
3670 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3672 g_assert_not_reached ();
3676 g_assert (ppc_is_imm16 (ins->inst_imm));
3677 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3680 ppc_subfze (code, ins->dreg, ins->sreg1);
3683 CASE_PPC64 (OP_LAND)
3684 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3685 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3689 CASE_PPC64 (OP_LAND_IMM)
3690 if (!(ins->inst_imm & 0xffff0000)) {
3691 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3692 } else if (!(ins->inst_imm & 0xffff)) {
3693 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3695 g_assert_not_reached ();
3699 CASE_PPC64 (OP_LDIV) {
3700 guint8 *divisor_is_m1;
3701 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3703 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3704 divisor_is_m1 = code;
3705 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3706 ppc_lis (code, ppc_r0, 0x8000);
3707 #ifdef __mono_ppc64__
3708 if (ins->opcode == OP_LDIV)
3709 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3711 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3712 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3713 ppc_patch (divisor_is_m1, code);
3714 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3716 if (ins->opcode == OP_IDIV)
3717 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3718 #ifdef __mono_ppc64__
3720 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3722 ppc_mfspr (code, ppc_r0, ppc_xer);
3723 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3724 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3728 CASE_PPC64 (OP_LDIV_UN)
3729 if (ins->opcode == OP_IDIV_UN)
3730 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3731 #ifdef __mono_ppc64__
3733 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3735 ppc_mfspr (code, ppc_r0, ppc_xer);
3736 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3737 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3743 g_assert_not_reached ();
3746 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3750 CASE_PPC64 (OP_LOR_IMM)
3751 if (!(ins->inst_imm & 0xffff0000)) {
3752 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3753 } else if (!(ins->inst_imm & 0xffff)) {
3754 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3756 g_assert_not_reached ();
3760 CASE_PPC64 (OP_LXOR)
3761 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3765 CASE_PPC64 (OP_LXOR_IMM)
3766 if (!(ins->inst_imm & 0xffff0000)) {
3767 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3768 } else if (!(ins->inst_imm & 0xffff)) {
3769 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3771 g_assert_not_reached ();
3775 CASE_PPC64 (OP_LSHL)
3776 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3780 CASE_PPC64 (OP_LSHL_IMM)
3781 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3784 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3787 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3790 if (MASK_SHIFT_IMM (ins->inst_imm))
3791 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3793 ppc_mr (code, ins->dreg, ins->sreg1);
3796 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3799 CASE_PPC64 (OP_LNOT)
3800 ppc_not (code, ins->dreg, ins->sreg1);
3803 CASE_PPC64 (OP_LNEG)
3804 ppc_neg (code, ins->dreg, ins->sreg1);
3807 CASE_PPC64 (OP_LMUL)
3808 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3812 CASE_PPC64 (OP_LMUL_IMM)
3813 if (ppc_is_imm16 (ins->inst_imm)) {
3814 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3816 g_assert_not_reached ();
3820 CASE_PPC64 (OP_LMUL_OVF)
3821 /* we annot use mcrxr, since it's not implemented on some processors
3822 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3824 if (ins->opcode == OP_IMUL_OVF)
3825 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3826 #ifdef __mono_ppc64__
3828 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3830 ppc_mfspr (code, ppc_r0, ppc_xer);
3831 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3832 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3834 case OP_IMUL_OVF_UN:
3835 CASE_PPC64 (OP_LMUL_OVF_UN)
3836 /* we first multiply to get the high word and compare to 0
3837 * to set the flags, then the result is discarded and then
3838 * we multiply to get the lower * bits result
3840 if (ins->opcode == OP_IMUL_OVF_UN)
3841 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3842 #ifdef __mono_ppc64__
3844 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3846 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3847 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3848 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3851 ppc_load (code, ins->dreg, ins->inst_c0);
3854 ppc_load (code, ins->dreg, ins->inst_l);
3857 case OP_LOAD_GOTADDR:
3858 /* The PLT implementation depends on this */
3859 g_assert (ins->dreg == ppc_r30);
3861 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3864 // FIXME: Fix max instruction length
3865 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3866 /* arch_emit_got_access () patches this */
3867 ppc_load32 (code, ppc_r0, 0);
3868 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3871 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3872 ppc_load_sequence (code, ins->dreg, 0);
3874 CASE_PPC32 (OP_ICONV_TO_I4)
3875 CASE_PPC32 (OP_ICONV_TO_U4)
3877 if (ins->dreg != ins->sreg1)
3878 ppc_mr (code, ins->dreg, ins->sreg1);
3881 int saved = ins->sreg1;
3882 if (ins->sreg1 == ppc_r3) {
3883 ppc_mr (code, ppc_r0, ins->sreg1);
3886 if (ins->sreg2 != ppc_r3)
3887 ppc_mr (code, ppc_r3, ins->sreg2);
3888 if (saved != ppc_r4)
3889 ppc_mr (code, ppc_r4, saved);
3893 if (ins->dreg != ins->sreg1)
3894 ppc_fmr (code, ins->dreg, ins->sreg1);
3896 case OP_MOVE_F_TO_I4:
3897 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3898 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3900 case OP_MOVE_I4_TO_F:
3901 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3902 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3904 case OP_FCONV_TO_R4:
3905 ppc_frsp (code, ins->dreg, ins->sreg1);
3909 MonoCallInst *call = (MonoCallInst*)ins;
3912 * Keep in sync with mono_arch_emit_epilog
3914 g_assert (!cfg->method->save_lmf);
3916 * Note: we can use ppc_r12 here because it is dead anyway:
3917 * we're leaving the method.
3919 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3920 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3921 if (ppc_is_imm16 (ret_offset)) {
3922 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3924 ppc_load (code, ppc_r12, ret_offset);
3925 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3927 ppc_mtlr (code, ppc_r0);
3930 if (ppc_is_imm16 (cfg->stack_usage)) {
3931 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3933 /* cfg->stack_usage is an int, so we can use
3934 * an addis/addi sequence here even in 64-bit. */
3935 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3936 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3938 if (!cfg->method->save_lmf) {
3940 for (i = 31; i >= 13; --i) {
3941 if (cfg->used_int_regs & (1 << i)) {
3942 pos += sizeof (gpointer);
3943 ppc_ldptr (code, i, -pos, ppc_r12);
3947 /* FIXME restore from MonoLMF: though this can't happen yet */
3950 /* Copy arguments on the stack to our argument area */
3951 if (call->stack_usage) {
3952 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3953 /* r12 was clobbered */
3954 g_assert (cfg->frame_reg == ppc_sp);
3955 if (ppc_is_imm16 (cfg->stack_usage)) {
3956 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3958 /* cfg->stack_usage is an int, so we can use
3959 * an addis/addi sequence here even in 64-bit. */
3960 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3961 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3965 ppc_mr (code, ppc_sp, ppc_r12);
3966 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3967 if (cfg->compile_aot) {
3968 /* arch_emit_got_access () patches this */
3969 ppc_load32 (code, ppc_r0, 0);
3970 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3971 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3972 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3974 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3976 ppc_mtctr (code, ppc_r0);
3977 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3984 /* ensure ins->sreg1 is not NULL */
3985 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3988 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3989 if (ppc_is_imm16 (cookie_offset)) {
3990 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3992 ppc_load (code, ppc_r0, cookie_offset);
3993 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3995 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
4004 call = (MonoCallInst*)ins;
4005 if (ins->flags & MONO_INST_HAS_METHOD)
4006 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4008 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4009 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4010 ppc_load_func (code, PPC_CALL_REG, 0);
4011 ppc_mtlr (code, PPC_CALL_REG);
4016 /* FIXME: this should be handled somewhere else in the new jit */
4017 code = emit_move_return_value (cfg, ins, code);
4023 case OP_VOIDCALL_REG:
4025 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4026 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4027 /* FIXME: if we know that this is a method, we
4028 can omit this load */
4029 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4030 ppc_mtlr (code, ppc_r0);
4032 #if (_CALL_ELF == 2)
4033 if (ins->flags & MONO_INST_HAS_METHOD) {
4034 // Not a global entry point
4036 // Need to set up r12 with function entry address for global entry point
4037 if (ppc_r12 != ins->sreg1) {
4038 ppc_mr(code,ppc_r12,ins->sreg1);
4042 ppc_mtlr (code, ins->sreg1);
4045 /* FIXME: this should be handled somewhere else in the new jit */
4046 code = emit_move_return_value (cfg, ins, code);
4048 case OP_FCALL_MEMBASE:
4049 case OP_LCALL_MEMBASE:
4050 case OP_VCALL_MEMBASE:
4051 case OP_VCALL2_MEMBASE:
4052 case OP_VOIDCALL_MEMBASE:
4053 case OP_CALL_MEMBASE:
4054 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
4055 /* The trampolines clobber this */
4056 ppc_mr (code, ppc_r29, ins->sreg1);
4057 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4059 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4061 ppc_mtlr (code, ppc_r0);
4063 /* FIXME: this should be handled somewhere else in the new jit */
4064 code = emit_move_return_value (cfg, ins, code);
4067 guint8 * zero_loop_jump, * zero_loop_start;
4068 /* keep alignment */
4069 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4070 int area_offset = alloca_waste;
4072 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4073 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4074 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4075 /* use ctr to store the number of words to 0 if needed */
4076 if (ins->flags & MONO_INST_INIT) {
4077 /* we zero 4 bytes at a time:
4078 * we add 7 instead of 3 so that we set the counter to
4079 * at least 1, otherwise the bdnz instruction will make
4080 * it negative and iterate billions of times.
4082 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4083 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4084 ppc_mtctr (code, ppc_r0);
4086 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4087 ppc_neg (code, ppc_r12, ppc_r12);
4088 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4090 /* FIXME: make this loop work in 8 byte
4091 increments on PPC64 */
4092 if (ins->flags & MONO_INST_INIT) {
4093 /* adjust the dest reg by -4 so we can use stwu */
4094 /* we actually adjust -8 because we let the loop
4097 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4098 ppc_li (code, ppc_r12, 0);
4099 zero_loop_start = code;
4100 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4101 zero_loop_jump = code;
4102 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4103 ppc_patch (zero_loop_jump, zero_loop_start);
4105 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4110 ppc_mr (code, ppc_r3, ins->sreg1);
4111 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4112 (gpointer)"mono_arch_throw_exception");
4113 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4114 ppc_load_func (code, PPC_CALL_REG, 0);
4115 ppc_mtlr (code, PPC_CALL_REG);
4124 ppc_mr (code, ppc_r3, ins->sreg1);
4125 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4126 (gpointer)"mono_arch_rethrow_exception");
4127 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4128 ppc_load_func (code, PPC_CALL_REG, 0);
4129 ppc_mtlr (code, PPC_CALL_REG);
4136 case OP_START_HANDLER: {
4137 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4138 g_assert (spvar->inst_basereg != ppc_sp);
4139 code = emit_reserve_param_area (cfg, code);
4140 ppc_mflr (code, ppc_r0);
4141 if (ppc_is_imm16 (spvar->inst_offset)) {
4142 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4144 ppc_load (code, ppc_r12, spvar->inst_offset);
4145 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4149 case OP_ENDFILTER: {
4150 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4151 g_assert (spvar->inst_basereg != ppc_sp);
4152 code = emit_unreserve_param_area (cfg, code);
4153 if (ins->sreg1 != ppc_r3)
4154 ppc_mr (code, ppc_r3, ins->sreg1);
4155 if (ppc_is_imm16 (spvar->inst_offset)) {
4156 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4158 ppc_load (code, ppc_r12, spvar->inst_offset);
4159 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4161 ppc_mtlr (code, ppc_r0);
4165 case OP_ENDFINALLY: {
4166 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4167 g_assert (spvar->inst_basereg != ppc_sp);
4168 code = emit_unreserve_param_area (cfg, code);
4169 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4170 ppc_mtlr (code, ppc_r0);
4174 case OP_CALL_HANDLER:
4175 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4177 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4180 ins->inst_c0 = code - cfg->native_code;
4183 /*if (ins->inst_target_bb->native_offset) {
4185 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4187 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4192 ppc_mtctr (code, ins->sreg1);
4193 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4197 CASE_PPC64 (OP_LCEQ)
4198 ppc_li (code, ins->dreg, 0);
4199 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4200 ppc_li (code, ins->dreg, 1);
4206 CASE_PPC64 (OP_LCLT)
4207 CASE_PPC64 (OP_LCLT_UN)
4208 ppc_li (code, ins->dreg, 1);
4209 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4210 ppc_li (code, ins->dreg, 0);
4216 CASE_PPC64 (OP_LCGT)
4217 CASE_PPC64 (OP_LCGT_UN)
4218 ppc_li (code, ins->dreg, 1);
4219 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4220 ppc_li (code, ins->dreg, 0);
4222 case OP_COND_EXC_EQ:
4223 case OP_COND_EXC_NE_UN:
4224 case OP_COND_EXC_LT:
4225 case OP_COND_EXC_LT_UN:
4226 case OP_COND_EXC_GT:
4227 case OP_COND_EXC_GT_UN:
4228 case OP_COND_EXC_GE:
4229 case OP_COND_EXC_GE_UN:
4230 case OP_COND_EXC_LE:
4231 case OP_COND_EXC_LE_UN:
4232 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4234 case OP_COND_EXC_IEQ:
4235 case OP_COND_EXC_INE_UN:
4236 case OP_COND_EXC_ILT:
4237 case OP_COND_EXC_ILT_UN:
4238 case OP_COND_EXC_IGT:
4239 case OP_COND_EXC_IGT_UN:
4240 case OP_COND_EXC_IGE:
4241 case OP_COND_EXC_IGE_UN:
4242 case OP_COND_EXC_ILE:
4243 case OP_COND_EXC_ILE_UN:
4244 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4256 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4259 /* floating point opcodes */
4261 g_assert (cfg->compile_aot);
4263 /* FIXME: Optimize this */
4265 ppc_mflr (code, ppc_r12);
4267 *(double*)code = *(double*)ins->inst_p0;
4269 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4272 g_assert_not_reached ();
4274 case OP_STORER8_MEMBASE_REG:
4275 if (ppc_is_imm16 (ins->inst_offset)) {
4276 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4278 if (ppc_is_imm32 (ins->inst_offset)) {
4279 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4280 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4282 ppc_load (code, ppc_r0, ins->inst_offset);
4283 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4287 case OP_LOADR8_MEMBASE:
4288 if (ppc_is_imm16 (ins->inst_offset)) {
4289 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4291 if (ppc_is_imm32 (ins->inst_offset)) {
4292 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4293 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4295 ppc_load (code, ppc_r0, ins->inst_offset);
4296 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4300 case OP_STORER4_MEMBASE_REG:
4301 ppc_frsp (code, ins->sreg1, ins->sreg1);
4302 if (ppc_is_imm16 (ins->inst_offset)) {
4303 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4305 if (ppc_is_imm32 (ins->inst_offset)) {
4306 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4307 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4309 ppc_load (code, ppc_r0, ins->inst_offset);
4310 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4314 case OP_LOADR4_MEMBASE:
4315 if (ppc_is_imm16 (ins->inst_offset)) {
4316 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4318 if (ppc_is_imm32 (ins->inst_offset)) {
4319 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4320 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4322 ppc_load (code, ppc_r0, ins->inst_offset);
4323 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4327 case OP_LOADR4_MEMINDEX:
4328 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4330 case OP_LOADR8_MEMINDEX:
4331 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4333 case OP_STORER4_MEMINDEX:
4334 ppc_frsp (code, ins->sreg1, ins->sreg1);
4335 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4337 case OP_STORER8_MEMINDEX:
4338 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4341 case CEE_CONV_R4: /* FIXME: change precision */
4343 g_assert_not_reached ();
4344 case OP_FCONV_TO_I1:
4345 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4347 case OP_FCONV_TO_U1:
4348 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4350 case OP_FCONV_TO_I2:
4351 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4353 case OP_FCONV_TO_U2:
4354 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4356 case OP_FCONV_TO_I4:
4358 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4360 case OP_FCONV_TO_U4:
4362 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4364 case OP_LCONV_TO_R_UN:
4365 g_assert_not_reached ();
4366 /* Implemented as helper calls */
4368 case OP_LCONV_TO_OVF_I4_2:
4369 case OP_LCONV_TO_OVF_I: {
4370 #ifdef __mono_ppc64__
4373 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4374 // Check if its negative
4375 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4376 negative_branch = code;
4377 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4378 // Its positive msword == 0
4379 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4380 msword_positive_branch = code;
4381 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4383 ovf_ex_target = code;
4384 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4386 ppc_patch (negative_branch, code);
4387 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4388 msword_negative_branch = code;
4389 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4390 ppc_patch (msword_negative_branch, ovf_ex_target);
4392 ppc_patch (msword_positive_branch, code);
4393 if (ins->dreg != ins->sreg1)
4394 ppc_mr (code, ins->dreg, ins->sreg1);
4399 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4402 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4405 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4408 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4411 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4414 ppc_fneg (code, ins->dreg, ins->sreg1);
4418 g_assert_not_reached ();
4421 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4424 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4425 ppc_li (code, ins->dreg, 0);
4426 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4427 ppc_li (code, ins->dreg, 1);
4430 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4431 ppc_li (code, ins->dreg, 1);
4432 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4433 ppc_li (code, ins->dreg, 0);
4436 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4437 ppc_li (code, ins->dreg, 1);
4438 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4439 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4440 ppc_li (code, ins->dreg, 0);
4443 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4444 ppc_li (code, ins->dreg, 1);
4445 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4446 ppc_li (code, ins->dreg, 0);
4449 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4450 ppc_li (code, ins->dreg, 1);
4451 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4452 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4453 ppc_li (code, ins->dreg, 0);
4456 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4459 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4462 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4463 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4466 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4467 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4470 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4471 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4474 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4475 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4478 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4479 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4482 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4485 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4486 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4489 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4492 g_assert_not_reached ();
4493 case OP_CHECK_FINITE: {
4494 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4495 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4496 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4497 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4500 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4501 #ifdef __mono_ppc64__
4502 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4504 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4509 #ifdef __mono_ppc64__
4510 case OP_ICONV_TO_I4:
4512 ppc_extsw (code, ins->dreg, ins->sreg1);
4514 case OP_ICONV_TO_U4:
4516 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4518 case OP_ICONV_TO_R4:
4519 case OP_ICONV_TO_R8:
4520 case OP_LCONV_TO_R4:
4521 case OP_LCONV_TO_R8: {
4523 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4524 ppc_extsw (code, ppc_r0, ins->sreg1);
4529 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4530 ppc_mffgpr (code, ins->dreg, tmp);
4532 ppc_str (code, tmp, -8, ppc_r1);
4533 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4535 ppc_fcfid (code, ins->dreg, ins->dreg);
4536 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4537 ppc_frsp (code, ins->dreg, ins->dreg);
4541 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4544 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4547 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4549 ppc_mfspr (code, ppc_r0, ppc_xer);
4550 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4551 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4553 case OP_COND_EXC_OV:
4554 ppc_mfspr (code, ppc_r0, ppc_xer);
4555 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4556 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4568 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4570 case OP_FCONV_TO_I8:
4571 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4573 case OP_FCONV_TO_U8:
4574 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4576 case OP_STOREI4_MEMBASE_REG:
4577 if (ppc_is_imm16 (ins->inst_offset)) {
4578 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4580 ppc_load (code, ppc_r0, ins->inst_offset);
4581 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4584 case OP_STOREI4_MEMINDEX:
4585 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4588 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4590 case OP_ISHR_UN_IMM:
4591 if (ins->inst_imm & 0x1f)
4592 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4594 ppc_mr (code, ins->dreg, ins->sreg1);
4597 case OP_ICONV_TO_R4:
4598 case OP_ICONV_TO_R8: {
4599 if (cpu_hw_caps & PPC_ISA_64) {
4600 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4601 ppc_stw (code, ppc_r0, -8, ppc_r1);
4602 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4603 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4604 ppc_fcfid (code, ins->dreg, ins->dreg);
4605 if (ins->opcode == OP_ICONV_TO_R4)
4606 ppc_frsp (code, ins->dreg, ins->dreg);
4612 case OP_ATOMIC_ADD_I4:
4613 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4614 int location = ins->inst_basereg;
4615 int addend = ins->sreg2;
4616 guint8 *loop, *branch;
4617 g_assert (ins->inst_offset == 0);
4621 if (ins->opcode == OP_ATOMIC_ADD_I4)
4622 ppc_lwarx (code, ppc_r0, 0, location);
4623 #ifdef __mono_ppc64__
4625 ppc_ldarx (code, ppc_r0, 0, location);
4628 ppc_add (code, ppc_r0, ppc_r0, addend);
4630 if (ins->opcode == OP_ATOMIC_ADD_I4)
4631 ppc_stwcxd (code, ppc_r0, 0, location);
4632 #ifdef __mono_ppc64__
4634 ppc_stdcxd (code, ppc_r0, 0, location);
4638 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4639 ppc_patch (branch, loop);
4642 ppc_mr (code, ins->dreg, ppc_r0);
4645 case OP_ATOMIC_CAS_I4:
4646 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4647 int location = ins->sreg1;
4648 int value = ins->sreg2;
4649 int comparand = ins->sreg3;
4650 guint8 *start, *not_equal, *lost_reservation;
4654 if (ins->opcode == OP_ATOMIC_CAS_I4)
4655 ppc_lwarx (code, ppc_r0, 0, location);
4656 #ifdef __mono_ppc64__
4658 ppc_ldarx (code, ppc_r0, 0, location);
4661 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4663 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4665 if (ins->opcode == OP_ATOMIC_CAS_I4)
4666 ppc_stwcxd (code, value, 0, location);
4667 #ifdef __mono_ppc64__
4669 ppc_stdcxd (code, value, 0, location);
4672 lost_reservation = code;
4673 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4674 ppc_patch (lost_reservation, start);
4675 ppc_patch (not_equal, code);
4678 ppc_mr (code, ins->dreg, ppc_r0);
4681 case OP_GC_SAFE_POINT:
4685 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4686 g_assert_not_reached ();
4689 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4690 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4691 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4692 g_assert_not_reached ();
4698 last_offset = offset;
4701 cfg->code_len = code - cfg->native_code;
4703 #endif /* !DISABLE_JIT */
4706 mono_arch_register_lowlevel_calls (void)
4708 /* The signature doesn't matter */
4709 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4712 #ifdef __mono_ppc64__
4713 #ifdef _LITTLE_ENDIAN
4714 #define patch_load_sequence(ip,val) do {\
4715 guint16 *__load = (guint16*)(ip); \
4716 g_assert (sizeof (val) == sizeof (gsize)); \
4717 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4718 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4719 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4720 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4722 #elif defined _BIG_ENDIAN
4723 #define patch_load_sequence(ip,val) do {\
4724 guint16 *__load = (guint16*)(ip); \
4725 g_assert (sizeof (val) == sizeof (gsize)); \
4726 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4727 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4728 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4729 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4732 #error huh? No endianess defined by compiler
4735 #define patch_load_sequence(ip,val) do {\
4736 guint16 *__lis_ori = (guint16*)(ip); \
4737 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4738 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4744 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4746 MonoJumpInfo *patch_info;
4747 gboolean compile_aot = !run_cctors;
4749 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4750 unsigned char *ip = patch_info->ip.i + code;
4751 unsigned char *target;
4752 gboolean is_fd = FALSE;
4754 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4757 switch (patch_info->type) {
4758 case MONO_PATCH_INFO_BB:
4759 case MONO_PATCH_INFO_LABEL:
4762 /* No need to patch these */
4767 switch (patch_info->type) {
4768 case MONO_PATCH_INFO_IP:
4769 patch_load_sequence (ip, ip);
4771 case MONO_PATCH_INFO_METHOD_REL:
4772 g_assert_not_reached ();
4773 *((gpointer *)(ip)) = code + patch_info->data.offset;
4775 case MONO_PATCH_INFO_SWITCH: {
4776 gpointer *table = (gpointer *)patch_info->data.table->table;
4779 patch_load_sequence (ip, table);
4781 for (i = 0; i < patch_info->data.table->table_size; i++) {
4782 table [i] = (glong)patch_info->data.table->table [i] + code;
4784 /* we put into the table the absolute address, no need for ppc_patch in this case */
4787 case MONO_PATCH_INFO_METHODCONST:
4788 case MONO_PATCH_INFO_CLASS:
4789 case MONO_PATCH_INFO_IMAGE:
4790 case MONO_PATCH_INFO_FIELD:
4791 case MONO_PATCH_INFO_VTABLE:
4792 case MONO_PATCH_INFO_IID:
4793 case MONO_PATCH_INFO_SFLDA:
4794 case MONO_PATCH_INFO_LDSTR:
4795 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4796 case MONO_PATCH_INFO_LDTOKEN:
4797 /* from OP_AOTCONST : lis + ori */
4798 patch_load_sequence (ip, target);
4800 case MONO_PATCH_INFO_R4:
4801 case MONO_PATCH_INFO_R8:
4802 g_assert_not_reached ();
4803 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4805 case MONO_PATCH_INFO_EXC_NAME:
4806 g_assert_not_reached ();
4807 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4809 case MONO_PATCH_INFO_NONE:
4810 case MONO_PATCH_INFO_BB_OVF:
4811 case MONO_PATCH_INFO_EXC_OVF:
4812 /* everything is dealt with at epilog output time */
4814 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4815 case MONO_PATCH_INFO_INTERNAL_METHOD:
4816 case MONO_PATCH_INFO_ABS:
4817 case MONO_PATCH_INFO_RGCTX_FETCH:
4818 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4825 ppc_patch_full (ip, target, is_fd);
4830 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4831 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4832 * the instruction offset immediate for all the registers.
4835 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4839 for (i = 13; i <= 31; i++) {
4840 if (used_int_regs & (1 << i)) {
4841 ppc_str (code, i, pos, base_reg);
4842 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4843 pos += sizeof (mgreg_t);
4847 /* pos is the start of the MonoLMF structure */
4848 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4849 for (i = 13; i <= 31; i++) {
4850 ppc_str (code, i, offset, base_reg);
4851 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4852 offset += sizeof (mgreg_t);
4854 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4855 for (i = 14; i < 32; i++) {
4856 ppc_stfd (code, i, offset, base_reg);
4857 offset += sizeof (gdouble);
4864 * Stack frame layout:
4866 * ------------------- sp
4867 * MonoLMF structure or saved registers
4868 * -------------------
4870 * -------------------
4872 * -------------------
4873 * optional 8 bytes for tracing
4874 * -------------------
4875 * param area size is cfg->param_area
4876 * -------------------
4877 * linkage area size is PPC_STACK_PARAM_OFFSET
4878 * ------------------- sp
4882 mono_arch_emit_prolog (MonoCompile *cfg)
4884 MonoMethod *method = cfg->method;
4886 MonoMethodSignature *sig;
4888 long alloc_size, pos, max_offset, cfa_offset;
4894 int tailcall_struct_index;
4896 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4899 sig = mono_method_signature (method);
4900 cfg->code_size = 512 + sig->param_count * 32;
4901 code = cfg->native_code = g_malloc (cfg->code_size);
4905 /* We currently emit unwind info for aot, but don't use it */
4906 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4908 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4909 ppc_mflr (code, ppc_r0);
4910 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4911 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4914 alloc_size = cfg->stack_offset;
4917 if (!method->save_lmf) {
4918 for (i = 31; i >= 13; --i) {
4919 if (cfg->used_int_regs & (1 << i)) {
4920 pos += sizeof (mgreg_t);
4924 pos += sizeof (MonoLMF);
4928 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4929 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4930 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4931 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4934 cfg->stack_usage = alloc_size;
4935 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4937 if (ppc_is_imm16 (-alloc_size)) {
4938 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4939 cfa_offset = alloc_size;
4940 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4941 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4944 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4945 ppc_load (code, ppc_r0, -alloc_size);
4946 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4947 cfa_offset = alloc_size;
4948 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4949 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4952 if (cfg->frame_reg != ppc_sp) {
4953 ppc_mr (code, cfg->frame_reg, ppc_sp);
4954 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4957 /* store runtime generic context */
4958 if (cfg->rgctx_var) {
4959 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4960 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4962 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4965 /* compute max_offset in order to use short forward jumps
4966 * we always do it on ppc because the immediate displacement
4967 * for jumps is too small
4970 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4972 bb->max_offset = max_offset;
4974 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4977 MONO_BB_FOR_EACH_INS (bb, ins)
4978 max_offset += ins_native_length (cfg, ins);
4981 /* load arguments allocated to register from the stack */
4984 cinfo = get_call_info (sig);
4986 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4987 ArgInfo *ainfo = &cinfo->ret;
4989 inst = cfg->vret_addr;
4992 if (ppc_is_imm16 (inst->inst_offset)) {
4993 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4995 ppc_load (code, ppc_r12, inst->inst_offset);
4996 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5000 tailcall_struct_index = 0;
5001 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5002 ArgInfo *ainfo = cinfo->args + i;
5003 inst = cfg->args [pos];
5005 if (cfg->verbose_level > 2)
5006 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5007 if (inst->opcode == OP_REGVAR) {
5008 if (ainfo->regtype == RegTypeGeneral)
5009 ppc_mr (code, inst->dreg, ainfo->reg);
5010 else if (ainfo->regtype == RegTypeFP)
5011 ppc_fmr (code, inst->dreg, ainfo->reg);
5012 else if (ainfo->regtype == RegTypeBase) {
5013 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5014 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5016 g_assert_not_reached ();
5018 if (cfg->verbose_level > 2)
5019 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5021 /* the argument should be put on the stack: FIXME handle size != word */
5022 if (ainfo->regtype == RegTypeGeneral) {
5023 switch (ainfo->size) {
5025 if (ppc_is_imm16 (inst->inst_offset)) {
5026 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5028 if (ppc_is_imm32 (inst->inst_offset)) {
5029 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5030 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5032 ppc_load (code, ppc_r12, inst->inst_offset);
5033 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5038 if (ppc_is_imm16 (inst->inst_offset)) {
5039 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5041 if (ppc_is_imm32 (inst->inst_offset)) {
5042 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5043 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5045 ppc_load (code, ppc_r12, inst->inst_offset);
5046 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5050 #ifdef __mono_ppc64__
5052 if (ppc_is_imm16 (inst->inst_offset)) {
5053 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5055 if (ppc_is_imm32 (inst->inst_offset)) {
5056 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5057 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5059 ppc_load (code, ppc_r12, inst->inst_offset);
5060 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5065 if (ppc_is_imm16 (inst->inst_offset)) {
5066 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5068 ppc_load (code, ppc_r12, inst->inst_offset);
5069 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5074 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5075 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5076 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5078 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5079 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5080 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5081 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5086 if (ppc_is_imm16 (inst->inst_offset)) {
5087 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5089 if (ppc_is_imm32 (inst->inst_offset)) {
5090 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5091 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5093 ppc_load (code, ppc_r12, inst->inst_offset);
5094 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5099 } else if (ainfo->regtype == RegTypeBase) {
5100 g_assert (ppc_is_imm16 (ainfo->offset));
5101 /* load the previous stack pointer in r12 */
5102 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5103 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5104 switch (ainfo->size) {
5106 if (ppc_is_imm16 (inst->inst_offset)) {
5107 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5109 if (ppc_is_imm32 (inst->inst_offset)) {
5110 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5111 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5113 ppc_load (code, ppc_r12, inst->inst_offset);
5114 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5119 if (ppc_is_imm16 (inst->inst_offset)) {
5120 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5122 if (ppc_is_imm32 (inst->inst_offset)) {
5123 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5124 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5126 ppc_load (code, ppc_r12, inst->inst_offset);
5127 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5131 #ifdef __mono_ppc64__
5133 if (ppc_is_imm16 (inst->inst_offset)) {
5134 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5136 if (ppc_is_imm32 (inst->inst_offset)) {
5137 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5138 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5140 ppc_load (code, ppc_r12, inst->inst_offset);
5141 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5146 if (ppc_is_imm16 (inst->inst_offset)) {
5147 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5149 ppc_load (code, ppc_r12, inst->inst_offset);
5150 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5155 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5156 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5157 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5158 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5159 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5161 /* use r11 to load the 2nd half of the long before we clobber r12. */
5162 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5163 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5164 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5165 ppc_stw (code, ppc_r0, 0, ppc_r12);
5166 ppc_stw (code, ppc_r11, 4, ppc_r12);
5171 if (ppc_is_imm16 (inst->inst_offset)) {
5172 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5174 if (ppc_is_imm32 (inst->inst_offset)) {
5175 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5176 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5178 ppc_load (code, ppc_r12, inst->inst_offset);
5179 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5184 } else if (ainfo->regtype == RegTypeFP) {
5185 g_assert (ppc_is_imm16 (inst->inst_offset));
5186 if (ainfo->size == 8)
5187 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5188 else if (ainfo->size == 4)
5189 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5191 g_assert_not_reached ();
5192 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5193 int doffset = inst->inst_offset;
5197 g_assert (ppc_is_imm16 (inst->inst_offset));
5198 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5199 /* FIXME: what if there is no class? */
5200 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5201 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5202 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5203 if (ainfo->size == 4) {
5204 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5206 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5208 soffset += ainfo->size;
5209 doffset += ainfo->size;
5211 } else if (ainfo->regtype == RegTypeStructByVal) {
5212 int doffset = inst->inst_offset;
5216 g_assert (ppc_is_imm16 (inst->inst_offset));
5217 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5218 /* FIXME: what if there is no class? */
5219 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5220 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5221 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5224 * Darwin handles 1 and 2 byte
5225 * structs specially by
5226 * loading h/b into the arg
5227 * register. Only done for
5231 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5233 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5237 #ifdef __mono_ppc64__
5239 g_assert (cur_reg == 0);
5240 #if G_BYTE_ORDER == G_BIG_ENDIAN
5241 ppc_sldi (code, ppc_r0, ainfo->reg,
5242 (sizeof (gpointer) - ainfo->bytes) * 8);
5243 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5245 if (mono_class_native_size (inst->klass, NULL) == 1) {
5246 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5247 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5248 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5249 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5250 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5252 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5258 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5259 inst->inst_basereg);
5262 soffset += sizeof (gpointer);
5263 doffset += sizeof (gpointer);
5265 if (ainfo->vtsize) {
5266 /* FIXME: we need to do the shifting here, too */
5269 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5270 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5271 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5272 code = emit_memcpy (code, size - soffset,
5273 inst->inst_basereg, doffset,
5274 ppc_r12, ainfo->offset + soffset);
5276 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5277 inst->inst_basereg, doffset,
5278 ppc_r12, ainfo->offset + soffset);
5281 } else if (ainfo->regtype == RegTypeStructByAddr) {
5282 /* if it was originally a RegTypeBase */
5283 if (ainfo->offset) {
5284 /* load the previous stack pointer in r12 */
5285 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5286 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5288 ppc_mr (code, ppc_r12, ainfo->reg);
5291 if (cfg->tailcall_valuetype_addrs) {
5292 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5294 g_assert (ppc_is_imm16 (addr->inst_offset));
5295 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5297 tailcall_struct_index++;
5300 g_assert (ppc_is_imm16 (inst->inst_offset));
5301 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5302 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5304 g_assert_not_reached ();
5309 if (method->save_lmf) {
5310 if (lmf_pthread_key != -1) {
5311 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5312 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5313 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5315 if (cfg->compile_aot) {
5316 /* Compute the got address which is needed by the PLT entry */
5317 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5319 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5320 (gpointer)"mono_get_lmf_addr");
5321 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5322 ppc_load_func (code, PPC_CALL_REG, 0);
5323 ppc_mtlr (code, PPC_CALL_REG);
5329 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5330 /* lmf_offset is the offset from the previous stack pointer,
5331 * alloc_size is the total stack space allocated, so the offset
5332 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5333 * The pointer to the struct is put in ppc_r12 (new_lmf).
5334 * The callee-saved registers are already in the MonoLMF structure
5336 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5337 /* ppc_r3 is the result from mono_get_lmf_addr () */
5338 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5339 /* new_lmf->previous_lmf = *lmf_addr */
5340 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5341 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5342 /* *(lmf_addr) = r12 */
5343 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5344 /* save method info */
5345 if (cfg->compile_aot)
5347 ppc_load (code, ppc_r0, 0);
5349 ppc_load_ptr (code, ppc_r0, method);
5350 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5351 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5352 /* save the current IP */
5353 if (cfg->compile_aot) {
5355 ppc_mflr (code, ppc_r0);
5357 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5358 #ifdef __mono_ppc64__
5359 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5361 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5364 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5368 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5370 cfg->code_len = code - cfg->native_code;
5371 g_assert (cfg->code_len <= cfg->code_size);
5378 mono_arch_emit_epilog (MonoCompile *cfg)
5380 MonoMethod *method = cfg->method;
5382 int max_epilog_size = 16 + 20*4;
5385 if (cfg->method->save_lmf)
5386 max_epilog_size += 128;
5388 if (mono_jit_trace_calls != NULL)
5389 max_epilog_size += 50;
5391 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5392 max_epilog_size += 50;
5394 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5395 cfg->code_size *= 2;
5396 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5397 cfg->stat_code_reallocs++;
5401 * Keep in sync with OP_JMP
5403 code = cfg->native_code + cfg->code_len;
5405 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5406 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5410 if (method->save_lmf) {
5412 pos += sizeof (MonoLMF);
5414 /* save the frame reg in r8 */
5415 ppc_mr (code, ppc_r8, cfg->frame_reg);
5416 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5417 /* r5 = previous_lmf */
5418 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5420 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5421 /* *(lmf_addr) = previous_lmf */
5422 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5423 /* FIXME: speedup: there is no actual need to restore the registers if
5424 * we didn't actually change them (idea from Zoltan).
5427 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5429 /*for (i = 14; i < 32; i++) {
5430 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5432 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5433 /* use the saved copy of the frame reg in r8 */
5434 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5435 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5436 ppc_mtlr (code, ppc_r0);
5438 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5440 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5441 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5442 if (ppc_is_imm16 (return_offset)) {
5443 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5445 ppc_load (code, ppc_r12, return_offset);
5446 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5448 ppc_mtlr (code, ppc_r0);
5450 if (ppc_is_imm16 (cfg->stack_usage)) {
5451 int offset = cfg->stack_usage;
5452 for (i = 13; i <= 31; i++) {
5453 if (cfg->used_int_regs & (1 << i))
5454 offset -= sizeof (mgreg_t);
5456 if (cfg->frame_reg != ppc_sp)
5457 ppc_mr (code, ppc_r12, cfg->frame_reg);
5458 /* note r31 (possibly the frame register) is restored last */
5459 for (i = 13; i <= 31; i++) {
5460 if (cfg->used_int_regs & (1 << i)) {
5461 ppc_ldr (code, i, offset, cfg->frame_reg);
5462 offset += sizeof (mgreg_t);
5465 if (cfg->frame_reg != ppc_sp)
5466 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5468 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5470 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5471 if (cfg->used_int_regs) {
5472 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5473 for (i = 31; i >= 13; --i) {
5474 if (cfg->used_int_regs & (1 << i)) {
5475 pos += sizeof (mgreg_t);
5476 ppc_ldr (code, i, -pos, ppc_r12);
5479 ppc_mr (code, ppc_sp, ppc_r12);
5481 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5488 cfg->code_len = code - cfg->native_code;
5490 g_assert (cfg->code_len < cfg->code_size);
5493 #endif /* ifndef DISABLE_JIT */
5495 /* remove once throw_exception_by_name is eliminated */
5497 exception_id_by_name (const char *name)
5499 if (strcmp (name, "IndexOutOfRangeException") == 0)
5500 return MONO_EXC_INDEX_OUT_OF_RANGE;
5501 if (strcmp (name, "OverflowException") == 0)
5502 return MONO_EXC_OVERFLOW;
5503 if (strcmp (name, "ArithmeticException") == 0)
5504 return MONO_EXC_ARITHMETIC;
5505 if (strcmp (name, "DivideByZeroException") == 0)
5506 return MONO_EXC_DIVIDE_BY_ZERO;
5507 if (strcmp (name, "InvalidCastException") == 0)
5508 return MONO_EXC_INVALID_CAST;
5509 if (strcmp (name, "NullReferenceException") == 0)
5510 return MONO_EXC_NULL_REF;
5511 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5512 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5513 if (strcmp (name, "ArgumentException") == 0)
5514 return MONO_EXC_ARGUMENT;
5515 g_error ("Unknown intrinsic exception %s\n", name);
5521 mono_arch_emit_exceptions (MonoCompile *cfg)
5523 MonoJumpInfo *patch_info;
5526 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5527 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5528 int max_epilog_size = 50;
5530 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5531 exc_throw_pos [i] = NULL;
5532 exc_throw_found [i] = 0;
5535 /* count the number of exception infos */
5538 * make sure we have enough space for exceptions
5540 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5541 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5542 i = exception_id_by_name (patch_info->data.target);
5543 if (!exc_throw_found [i]) {
5544 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5545 exc_throw_found [i] = TRUE;
5547 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5548 max_epilog_size += 12;
5549 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5550 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5551 i = exception_id_by_name (ovfj->data.exception);
5552 if (!exc_throw_found [i]) {
5553 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5554 exc_throw_found [i] = TRUE;
5556 max_epilog_size += 8;
5560 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5561 cfg->code_size *= 2;
5562 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5563 cfg->stat_code_reallocs++;
5566 code = cfg->native_code + cfg->code_len;
5568 /* add code to raise exceptions */
5569 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5570 switch (patch_info->type) {
5571 case MONO_PATCH_INFO_BB_OVF: {
5572 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5573 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5574 /* patch the initial jump */
5575 ppc_patch (ip, code);
5576 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5578 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5579 /* jump back to the true target */
5581 ip = ovfj->data.bb->native_offset + cfg->native_code;
5582 ppc_patch (code - 4, ip);
5583 patch_info->type = MONO_PATCH_INFO_NONE;
5586 case MONO_PATCH_INFO_EXC_OVF: {
5587 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5588 MonoJumpInfo *newji;
5589 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5590 unsigned char *bcl = code;
5591 /* patch the initial jump: we arrived here with a call */
5592 ppc_patch (ip, code);
5593 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5595 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5596 /* patch the conditional jump to the right handler */
5597 /* make it processed next */
5598 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5599 newji->type = MONO_PATCH_INFO_EXC;
5600 newji->ip.i = bcl - cfg->native_code;
5601 newji->data.target = ovfj->data.exception;
5602 newji->next = patch_info->next;
5603 patch_info->next = newji;
5604 patch_info->type = MONO_PATCH_INFO_NONE;
5607 case MONO_PATCH_INFO_EXC: {
5608 MonoClass *exc_class;
5610 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5611 i = exception_id_by_name (patch_info->data.target);
5612 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5613 ppc_patch (ip, exc_throw_pos [i]);
5614 patch_info->type = MONO_PATCH_INFO_NONE;
5617 exc_throw_pos [i] = code;
5620 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5621 g_assert (exc_class);
5623 ppc_patch (ip, code);
5624 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5625 ppc_load (code, ppc_r3, exc_class->type_token);
5626 /* we got here from a conditional call, so the calling ip is set in lr */
5627 ppc_mflr (code, ppc_r4);
5628 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5629 patch_info->data.name = "mono_arch_throw_corlib_exception";
5630 patch_info->ip.i = code - cfg->native_code;
5631 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5632 ppc_load_func (code, PPC_CALL_REG, 0);
5633 ppc_mtctr (code, PPC_CALL_REG);
5634 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5646 cfg->code_len = code - cfg->native_code;
5648 g_assert (cfg->code_len <= cfg->code_size);
5654 try_offset_access (void *value, guint32 idx)
5656 register void* me __asm__ ("r2");
5657 void ***p = (void***)((char*)me + 284);
5658 int idx1 = idx / 32;
5659 int idx2 = idx % 32;
5662 if (value != p[idx1][idx2])
5669 setup_tls_access (void)
5671 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5672 size_t conf_size = 0;
5675 /* FIXME for darwin */
5676 guint32 *ins, *code;
5677 guint32 cmplwi_1023, li_0x48, blr_ins;
5681 tls_mode = TLS_MODE_FAILED;
5684 if (tls_mode == TLS_MODE_FAILED)
5686 if (g_getenv ("MONO_NO_TLS")) {
5687 tls_mode = TLS_MODE_FAILED;
5691 if (tls_mode == TLS_MODE_DETECT) {
5692 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5693 tls_mode = TLS_MODE_DARWIN_G4;
5694 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5695 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5696 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5697 tls_mode = TLS_MODE_NPTL;
5698 #elif !defined(TARGET_PS3)
5699 ins = (guint32*)pthread_getspecific;
5700 /* uncond branch to the real method */
5701 if ((*ins >> 26) == 18) {
5703 val = (*ins & ~3) << 6;
5707 ins = (guint32*)(long)val;
5709 ins = (guint32*) ((char*)ins + val);
5712 code = &cmplwi_1023;
5713 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5715 ppc_li (code, ppc_r4, 0x48);
5718 if (*ins == cmplwi_1023) {
5719 int found_lwz_284 = 0;
5721 for (ptk = 0; ptk < 20; ++ptk) {
5723 if (!*ins || *ins == blr_ins)
5725 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5730 if (!found_lwz_284) {
5731 tls_mode = TLS_MODE_FAILED;
5734 tls_mode = TLS_MODE_LTHREADS;
5735 } else if (*ins == li_0x48) {
5737 /* uncond branch to the real method */
5738 if ((*ins >> 26) == 18) {
5740 val = (*ins & ~3) << 6;
5744 ins = (guint32*)(long)val;
5746 ins = (guint32*) ((char*)ins + val);
5748 code = (guint32*)&val;
5749 ppc_li (code, ppc_r0, 0x7FF2);
5750 if (ins [1] == val) {
5751 /* Darwin on G4, implement */
5752 tls_mode = TLS_MODE_FAILED;
5755 code = (guint32*)&val;
5756 ppc_mfspr (code, ppc_r3, 104);
5757 if (ins [1] != val) {
5758 tls_mode = TLS_MODE_FAILED;
5761 tls_mode = TLS_MODE_DARWIN_G5;
5764 tls_mode = TLS_MODE_FAILED;
5768 tls_mode = TLS_MODE_FAILED;
5774 if (tls_mode == TLS_MODE_DETECT)
5775 tls_mode = TLS_MODE_FAILED;
5776 if (tls_mode == TLS_MODE_FAILED)
5778 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5779 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5783 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5784 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5785 if (lmf_pthread_key == -1) {
5786 guint32 ptk = mono_jit_tls_id;
5788 /*g_print ("MonoLMF at: %d\n", ptk);*/
5789 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5790 init_tls_failed = 1;
5793 lmf_pthread_key = ptk;
5802 mono_arch_finish_init (void)
5804 setup_tls_access ();
5808 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5812 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5814 #define LOADSTORE_SIZE 4
5815 #define JUMP_IMM_SIZE 12
5816 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5817 #define ENABLE_WRONG_METHOD_CHECK 0
5820 * LOCKING: called with the domain lock held
5823 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5824 gpointer fail_tramp)
5828 guint8 *code, *start;
5830 for (i = 0; i < count; ++i) {
5831 MonoIMTCheckItem *item = imt_entries [i];
5832 if (item->is_equals) {
5833 if (item->check_target_idx) {
5834 if (!item->compare_done)
5835 item->chunk_size += CMP_SIZE;
5836 if (item->has_target_code)
5837 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5839 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5842 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5843 if (!item->has_target_code)
5844 item->chunk_size += LOADSTORE_SIZE;
5846 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5847 #if ENABLE_WRONG_METHOD_CHECK
5848 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5853 item->chunk_size += CMP_SIZE + BR_SIZE;
5854 imt_entries [item->check_target_idx]->compare_done = TRUE;
5856 size += item->chunk_size;
5858 /* the initial load of the vtable address */
5859 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5861 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5863 code = mono_domain_code_reserve (domain, size);
5868 * We need to save and restore r12 because it might be
5869 * used by the caller as the vtable register, so
5870 * clobbering it will trip up the magic trampoline.
5872 * FIXME: Get rid of this by making sure that r12 is
5873 * not used as the vtable register in interface calls.
5875 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5876 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5878 for (i = 0; i < count; ++i) {
5879 MonoIMTCheckItem *item = imt_entries [i];
5880 item->code_target = code;
5881 if (item->is_equals) {
5882 if (item->check_target_idx) {
5883 if (!item->compare_done) {
5884 ppc_load (code, ppc_r0, (gsize)item->key);
5885 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5887 item->jmp_code = code;
5888 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5889 if (item->has_target_code) {
5890 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5892 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5893 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5895 ppc_mtctr (code, ppc_r0);
5896 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5899 ppc_load (code, ppc_r0, (gulong)item->key);
5900 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5901 item->jmp_code = code;
5902 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5903 if (item->has_target_code) {
5904 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5907 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5908 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5910 ppc_mtctr (code, ppc_r0);
5911 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5912 ppc_patch (item->jmp_code, code);
5913 ppc_load_ptr (code, ppc_r0, fail_tramp);
5914 ppc_mtctr (code, ppc_r0);
5915 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5916 item->jmp_code = NULL;
5918 /* enable the commented code to assert on wrong method */
5919 #if ENABLE_WRONG_METHOD_CHECK
5920 ppc_load (code, ppc_r0, (guint32)item->key);
5921 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5922 item->jmp_code = code;
5923 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5925 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5926 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5927 ppc_mtctr (code, ppc_r0);
5928 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5929 #if ENABLE_WRONG_METHOD_CHECK
5930 ppc_patch (item->jmp_code, code);
5932 item->jmp_code = NULL;
5937 ppc_load (code, ppc_r0, (gulong)item->key);
5938 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5939 item->jmp_code = code;
5940 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5943 /* patch the branches to get to the target items */
5944 for (i = 0; i < count; ++i) {
5945 MonoIMTCheckItem *item = imt_entries [i];
5946 if (item->jmp_code) {
5947 if (item->check_target_idx) {
5948 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5954 mono_stats.imt_thunks_size += code - start;
5955 g_assert (code - start <= size);
5956 mono_arch_flush_icache (start, size);
5958 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5964 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5966 mgreg_t *r = (mgreg_t*)regs;
5968 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5972 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5974 mgreg_t *r = (mgreg_t*)regs;
5976 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5980 mono_arch_get_cie_program (void)
5984 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5990 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5997 mono_arch_print_tree (MonoInst *tree, int arity)
6003 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6006 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6008 g_assert (reg >= ppc_r13);
6010 return ctx->regs [reg - ppc_r13];
6014 mono_arch_get_patch_offset (guint8 *code)
6020 * mono_aot_emit_load_got_addr:
6022 * Emit code to load the got address.
6023 * On PPC, the result is placed into r30.
6026 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6029 ppc_mflr (code, ppc_r30);
6031 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6033 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6034 /* arch_emit_got_address () patches this */
6035 #if defined(TARGET_POWERPC64)
6041 ppc_load32 (code, ppc_r0, 0);
6042 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6049 * mono_ppc_emit_load_aotconst:
6051 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6052 * TARGET from the mscorlib GOT in full-aot code.
6053 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6057 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6059 /* Load the mscorlib got address */
6060 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6061 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6062 /* arch_emit_got_access () patches this */
6063 ppc_load32 (code, ppc_r0, 0);
6064 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6069 /* Soft Debug support */
6070 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6077 * mono_arch_set_breakpoint:
6079 * See mini-amd64.c for docs.
6082 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6085 guint8 *orig_code = code;
6087 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6088 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6090 g_assert (code - orig_code == BREAKPOINT_SIZE);
6092 mono_arch_flush_icache (orig_code, code - orig_code);
6096 * mono_arch_clear_breakpoint:
6098 * See mini-amd64.c for docs.
6101 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6106 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6109 mono_arch_flush_icache (ip, code - ip);
6113 * mono_arch_is_breakpoint_event:
6115 * See mini-amd64.c for docs.
6118 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6120 siginfo_t* sinfo = (siginfo_t*) info;
6121 /* Sometimes the address is off by 4 */
6122 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6129 * mono_arch_skip_breakpoint:
6131 * See mini-amd64.c for docs.
6134 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6136 /* skip the ldptr */
6137 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6145 * mono_arch_start_single_stepping:
6147 * See mini-amd64.c for docs.
6150 mono_arch_start_single_stepping (void)
6152 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6156 * mono_arch_stop_single_stepping:
6158 * See mini-amd64.c for docs.
6161 mono_arch_stop_single_stepping (void)
6163 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6167 * mono_arch_is_single_step_event:
6169 * See mini-amd64.c for docs.
6172 mono_arch_is_single_step_event (void *info, void *sigctx)
6174 siginfo_t* sinfo = (siginfo_t*) info;
6175 /* Sometimes the address is off by 4 */
6176 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6183 * mono_arch_skip_single_step:
6185 * See mini-amd64.c for docs.
6188 mono_arch_skip_single_step (MonoContext *ctx)
6190 /* skip the ldptr */
6191 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6195 * mono_arch_create_seq_point_info:
6197 * See mini-amd64.c for docs.
6200 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6207 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6209 ext->lmf.previous_lmf = prev_lmf;
6210 /* Mark that this is a MonoLMFExt */
6211 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6212 ext->lmf.ebp = (gssize)ext;
6218 mono_arch_opcode_supported (int opcode)
6221 case OP_ATOMIC_ADD_I4:
6222 case OP_ATOMIC_CAS_I4:
6223 #ifdef TARGET_POWERPC64
6224 case OP_ATOMIC_ADD_I8:
6225 case OP_ATOMIC_CAS_I8:
6235 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6236 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6237 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6240 mono_arch_create_handler_block_trampoline (void)