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_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_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 regiester, 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 (MonoGenericSharingContext *gsctx, 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 (NULL, 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 (gboolean has_target, guint32 param_count, guint32 *code_len, 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 *code_len = code - start;
440 mono_arch_get_delegate_invoke_impls (void)
448 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
449 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
451 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
452 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
453 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
454 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
462 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
464 guint8 *code, *start;
466 /* FIXME: Support more cases */
467 if (MONO_TYPE_ISSTRUCT (sig->ret))
471 static guint8* cached = NULL;
477 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
479 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
481 mono_memory_barrier ();
485 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
488 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
490 for (i = 0; i < sig->param_count; ++i)
491 if (!mono_is_regsize_var (sig->params [i]))
495 code = cache [sig->param_count];
500 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
501 start = mono_aot_get_trampoline (name);
504 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
507 mono_memory_barrier ();
509 cache [sig->param_count] = start;
515 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
521 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
523 mgreg_t *r = (mgreg_t*)regs;
525 return (gpointer)(gsize)r [ppc_r3];
533 #define MAX_AUX_ENTRIES 128
535 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
536 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
538 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
540 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
541 #define ISA_64 0x40000000
543 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
544 #define ISA_MOVE_FPR_GPR 0x00000200
546 * Initialize the cpu to execute managed code.
549 mono_arch_cpu_init (void)
554 * Initialize architecture specific code.
557 mono_arch_init (void)
559 #if defined(MONO_CROSS_COMPILE)
560 #elif defined(__APPLE__)
562 size_t len = sizeof (cachelinesize);
565 mib [1] = HW_CACHELINE;
567 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
571 cachelineinc = cachelinesize;
573 #elif defined(__linux__)
574 AuxVec vec [MAX_AUX_ENTRIES];
575 int i, vec_entries = 0;
576 /* sadly this will work only with 2.6 kernels... */
577 FILE* f = fopen ("/proc/self/auxv", "rb");
580 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
584 for (i = 0; i < vec_entries; i++) {
585 int type = vec [i].type;
587 if (type == 19) { /* AT_DCACHEBSIZE */
588 cachelinesize = vec [i].value;
592 #elif defined(G_COMPILER_CODEWARRIOR)
596 //#error Need a way to get cache line size
599 if (mono_hwcap_ppc_has_icache_snoop)
600 cpu_hw_caps |= PPC_ICACHE_SNOOP;
602 if (mono_hwcap_ppc_is_isa_2x)
603 cpu_hw_caps |= PPC_ISA_2X;
605 if (mono_hwcap_ppc_is_isa_64)
606 cpu_hw_caps |= PPC_ISA_64;
608 if (mono_hwcap_ppc_has_move_fpr_gpr)
609 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
611 if (mono_hwcap_ppc_has_multiple_ls_units)
612 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
618 cachelineinc = cachelinesize;
620 if (mono_cpu_count () > 1)
621 cpu_hw_caps |= PPC_SMP_CAPABLE;
623 mono_mutex_init_recursive (&mini_arch_mutex);
625 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
626 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
627 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
629 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
633 * Cleanup architecture specific code.
636 mono_arch_cleanup (void)
638 mono_mutex_destroy (&mini_arch_mutex);
642 * This function returns the optimizations supported on this cpu.
645 mono_arch_cpu_optimizations (guint32 *exclude_mask)
649 /* no ppc-specific optimizations yet */
655 * This function test for all SIMD functions supported.
657 * Returns a bitmask corresponding to all supported versions.
661 mono_arch_cpu_enumerate_simd_versions (void)
663 /* SIMD is currently unimplemented */
667 #ifdef __mono_ppc64__
668 #define CASE_PPC32(c)
669 #define CASE_PPC64(c) case c:
671 #define CASE_PPC32(c) case c:
672 #define CASE_PPC64(c)
676 is_regsize_var (MonoType *t) {
679 t = mini_type_get_underlying_type (NULL, t);
683 CASE_PPC64 (MONO_TYPE_I8)
684 CASE_PPC64 (MONO_TYPE_U8)
688 case MONO_TYPE_FNPTR:
690 case MONO_TYPE_OBJECT:
691 case MONO_TYPE_STRING:
692 case MONO_TYPE_CLASS:
693 case MONO_TYPE_SZARRAY:
694 case MONO_TYPE_ARRAY:
696 case MONO_TYPE_GENERICINST:
697 if (!mono_type_generic_inst_is_valuetype (t))
700 case MONO_TYPE_VALUETYPE:
708 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
713 for (i = 0; i < cfg->num_varinfo; i++) {
714 MonoInst *ins = cfg->varinfo [i];
715 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
718 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
721 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
724 /* we can only allocate 32 bit values */
725 if (is_regsize_var (ins->inst_vtype)) {
726 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
727 g_assert (i == vmv->idx);
728 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
734 #endif /* ifndef DISABLE_JIT */
737 mono_arch_get_global_int_regs (MonoCompile *cfg)
741 if (cfg->frame_reg != ppc_sp)
743 /* ppc_r13 is used by the system on PPC EABI */
744 for (i = 14; i < top; ++i) {
746 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
747 * since the trampolines can clobber r12.
749 if (!(cfg->compile_aot && i == 29))
750 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
757 * mono_arch_regalloc_cost:
759 * Return the cost, in number of memory references, of the action of
760 * allocating the variable VMV into a register during global register
764 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
771 mono_arch_flush_icache (guint8 *code, gint size)
773 #ifdef MONO_CROSS_COMPILE
776 guint8 *endp, *start;
780 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
781 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
782 #if defined(G_COMPILER_CODEWARRIOR)
783 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
784 for (p = start; p < endp; p += cachelineinc) {
788 for (p = start; p < endp; p += cachelineinc) {
794 for (p = start; p < endp; p += cachelineinc) {
805 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
806 * The sync is required to insure that the store queue is completely empty.
807 * While the icbi performs no cache operations, icbi/isync is required to
808 * kill local prefetch.
810 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
812 asm ("icbi 0,%0;" : : "r"(code) : "memory");
816 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
817 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
818 for (p = start; p < endp; p += cachelineinc) {
819 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
822 for (p = start; p < endp; p += cachelineinc) {
823 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
828 for (p = start; p < endp; p += cachelineinc) {
829 /* for ISA2.0+ implementations we should not need any extra sync between the
830 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
831 * So I am not sure which chip had this problem but its not an issue on
832 * of the ISA V2 chips.
834 if (cpu_hw_caps & PPC_ISA_2X)
835 asm ("icbi 0,%0;" : : "r"(p) : "memory");
837 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
839 if (!(cpu_hw_caps & PPC_ISA_2X))
847 mono_arch_flush_register_windows (void)
852 #define ALWAYS_ON_STACK(s) s
853 #define FP_ALSO_IN_REG(s) s
855 #ifdef __mono_ppc64__
856 #define ALWAYS_ON_STACK(s) s
857 #define FP_ALSO_IN_REG(s) s
859 #define ALWAYS_ON_STACK(s)
860 #define FP_ALSO_IN_REG(s)
862 #define ALIGN_DOUBLES
871 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
876 guint32 vtsize; /* in param area */
878 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
879 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
880 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
881 guint8 bytes : 4; /* size in bytes - only valid for
882 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
883 in one word, otherwise it's 0*/
892 gboolean vtype_retaddr;
901 // Test if a structure completely composed of fields that are all floats XOR doubles and that there are fewer than
903 // Note: If this is true the structure can be returned directly via registers fr1 through fr8 instead of by a hidden parameter
904 // pointing to where the return value should be stored.
905 // This is as per the ELF ABI v2.
907 #if PPC_RETURN_SMALL_FLOAT_STRUCTS_IN_FR_REGS
909 is_float_struct_returnable_via_regs (MonoClass *klass)
911 gboolean has_a_field = FALSE;
914 gpointer iter = NULL;
915 MonoClassField *f = 0;
916 MonoClassField *firstMember = &klass->fields [0];
918 mono_class_setup_fields_locking (klass);
919 firstMember = &klass->fields [0];
924 while ((f = mono_class_get_fields (klass, &iter)) && (member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS)) {
925 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
926 if (!f->type->byref && mono_metadata_type_equal(firstMember->type, f->type) && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8)) {
934 return has_a_field && (member_cnt <= PPC_MOST_FLOAT_STRUCT_MEMBERS_TO_RETURN_VIA_REGISTERS);
940 // Test if a structure is smaller in size than 2 doublewords (PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS) and is
941 // completely composed of fields all of basic types.
942 // Note: If this is true the structure can be returned directly via registers r3/r4 instead of by a hidden parameter
943 // pointing to where the return value should be stored.
944 // This is as per the ELF ABI v2.
946 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
948 is_struct_returnable_via_regs (MonoClass *klass, gboolean is_pinvoke)
950 gboolean has_a_field = FALSE;
953 gpointer iter = NULL;
955 MonoClassField *firstMember = &klass->fields [0];
957 mono_class_setup_fields_locking (klass);
958 firstMember = &klass->fields [0];
964 size = mono_type_native_stack_size (&klass->byval_arg, 0);
966 size = mini_type_stack_size (NULL, &klass->byval_arg, 0);
967 if ((size == 0) || (size > PPC_LARGEST_STRUCT_SIZE_TO_RETURN_VIA_REGISTERS))
969 while ((f = mono_class_get_fields (klass, &iter))) {
970 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
971 // TBD: Is there a better way to check for the basic types?
972 if (!f->type->byref && (f->type->type >= MONO_TYPE_BOOLEAN) && (f->type->type <= MONO_TYPE_R8)) {
984 member_count (MonoClass *klass)
988 gpointer iter = NULL;
990 while ((f = mono_class_get_fields (klass, &iter))) {
991 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1000 float_member_size (MonoClass *klass)
1003 MonoClassField *firstMember = &klass->fields [0];
1004 g_assert (firstMember);
1005 // The class is homogenous so the first member will be the same as all the members
1006 if (firstMember->type->type == MONO_TYPE_R4)
1008 else if (firstMember->type->type == MONO_TYPE_R8)
1011 // Floats should always be 4 or 8 bytes
1012 g_assert_not_reached ();
1019 #if PPC_RETURN_SMALL_STRUCTS_IN_REGS
1020 // If the value is being returned via registers we don't need to allocate a temporary variable for it.
1021 // Note that this can have effects elsewhere (like with the unbox code) that expects there to be a
1024 function_return_value_requires_temporary (MonoMethodSignature *sig) {
1025 MonoType *sig_ret = mini_replace_type (sig->ret);
1026 gboolean is_all_floats = is_float_struct_returnable_via_regs(mono_class_from_mono_type (sig_ret));
1027 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(mono_class_from_mono_type (sig_ret), sig->pinvoke);
1028 DEBUG_ELFABIV2_printf("return_value_requires_temporary: sig_ret: FL? %d non-FL? %d ", (int)is_all_floats, (int)is_returnable_via_regs); DEBUG_ELFABIV2_mono_print_klass(mono_class_from_mono_type (sig_ret));
1030 return (!is_all_floats && !is_returnable_via_regs);
1035 #ifdef MONO_ARCH_RETURN_CAN_USE_MULTIPLE_REGISTERS
1037 mono_arch_handle_multiple_dregs(MonoBasicBlock *bb, MonoCompile *cfg, MonoInst *ins, MonoInst *var) {
1038 if (ins->opcode == OP_LOAD_MEMBASE &&
1039 var->backend.additional_regs) {
1041 DEBUG_ELFABIV2_printf("mono_spill_global_vars Existing non-float load: "); DEBUG_ELFABIV2_mono_print_ins(ins);
1042 DEBUG_ELFABIV2_printf(" klass: "); DEBUG_ELFABIV2_mono_print_klass(var->klass);
1043 MONO_INST_NEW (cfg, tmp, OP_LOAD_MEMBASE);
1046 tmp->inst_offset += 8; // FIXME: use a proper constant here
1047 mono_bblock_insert_after_ins (bb, ins, tmp);
1048 DEBUG_ELFABIV2_printf(" Adding new load: "); DEBUG_ELFABIV2_mono_print_ins(tmp);
1049 } else if (((ins->opcode == OP_LOADR4_MEMBASE) || (ins->opcode == OP_LOADR8_MEMBASE)) &&
1050 var->backend.additional_regs) {
1051 // Return small (<= 8 member) structures entirely made up of either float or double members
1055 int mbr_cnt = member_count(var->klass);
1056 int mbr_size = float_member_size(var->klass);
1057 DEBUG_ELFABIV2_printf("mono_spill_global_vars Existing float/double load: "); DEBUG_ELFABIV2_mono_print_ins(ins);
1058 DEBUG_ELFABIV2_printf(" klass: "); DEBUG_ELFABIV2_mono_print_klass(var->klass);
1059 for (cnt=0; cnt < mbr_cnt; ++cnt) {
1060 MONO_INST_NEW (cfg, tmp, OP_LOAD_MEMBASE);
1063 tmp->inst_offset += mbr_size;
1064 mono_bblock_insert_after_ins (bb, ins, tmp);
1065 DEBUG_ELFABIV2_printf(" Adding new load: "); DEBUG_ELFABIV2_mono_print_ins(tmp);
1073 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
1075 #ifdef __mono_ppc64__
1080 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
1081 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
1082 ainfo->reg = ppc_sp; /* in the caller */
1083 ainfo->regtype = RegTypeBase;
1084 *stack_size += sizeof (gpointer);
1086 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
1090 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
1091 #ifdef ALIGN_DOUBLES
1092 //*stack_size += (*stack_size % 8);
1094 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
1095 ainfo->reg = ppc_sp; /* in the caller */
1096 ainfo->regtype = RegTypeBase;
1099 #ifdef ALIGN_DOUBLES
1103 ALWAYS_ON_STACK (*stack_size += 8);
1111 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1113 has_only_a_r48_field (MonoClass *klass)
1117 gboolean have_field = FALSE;
1119 while ((f = mono_class_get_fields (klass, &iter))) {
1120 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1123 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1134 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
1136 guint i, fr, gr, pstart;
1137 int n = sig->hasthis + sig->param_count;
1138 MonoType *simpletype;
1139 guint32 stack_size = 0;
1140 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1141 gboolean is_pinvoke = sig->pinvoke;
1142 gboolean is_struct = MONO_TYPE_ISSTRUCT (sig->ret);
1143 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1144 gboolean is_all_floats = FALSE;
1145 gboolean is_returnable_via_regs = FALSE;
1147 fr = PPC_FIRST_FPARG_REG;
1148 gr = PPC_FIRST_ARG_REG;
1150 // Handle returning small structs via registers
1151 // This is active for two cases:
1152 // 1) All-float (or double) member structs with 8 or fewer members
1153 // 2) Other structures smaller than 16 bytes
1155 is_all_floats = is_float_struct_returnable_via_regs(klass);
1156 is_returnable_via_regs = is_struct_returnable_via_regs(klass, sig->pinvoke);
1157 if (!is_all_floats && !is_returnable_via_regs) {
1158 cinfo->vtype_retaddr = TRUE;
1165 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1166 * the first argument, allowing 'this' to be always passed in the first arg reg.
1167 * Also do this if the first argument is a reference type, since virtual calls
1168 * are sometimes made using calli without sig->hasthis set, like in the delegate
1171 if (is_struct && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1173 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1176 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1180 if (!is_all_floats && !is_returnable_via_regs) {
1181 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1182 cinfo->struct_ret = cinfo->ret.reg;
1183 cinfo->vret_arg_index = 1;
1185 cinfo->struct_ret = -1; // Just a flag for later
1190 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1195 if (!is_all_floats && !is_returnable_via_regs) {
1196 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1197 cinfo->struct_ret = cinfo->ret.reg;
1199 cinfo->struct_ret = -1; // Just a flag for later
1204 DEBUG(printf("params: %d\n", sig->param_count));
1205 for (i = pstart; i < sig->param_count; ++i) {
1206 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1207 /* Prevent implicit arguments and sig_cookie from
1208 being passed in registers */
1209 gr = PPC_LAST_ARG_REG + 1;
1210 /* FIXME: don't we have to set fr, too? */
1211 /* Emit the signature cookie just before the implicit arguments */
1212 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1214 DEBUG(printf("param %d: ", i));
1215 if (sig->params [i]->byref) {
1216 DEBUG(printf("byref\n"));
1217 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1221 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1222 switch (simpletype->type) {
1223 case MONO_TYPE_BOOLEAN:
1226 cinfo->args [n].size = 1;
1227 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1230 case MONO_TYPE_CHAR:
1233 cinfo->args [n].size = 2;
1234 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1239 cinfo->args [n].size = 4;
1240 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1246 case MONO_TYPE_FNPTR:
1247 case MONO_TYPE_CLASS:
1248 case MONO_TYPE_OBJECT:
1249 case MONO_TYPE_STRING:
1250 case MONO_TYPE_SZARRAY:
1251 case MONO_TYPE_ARRAY:
1252 cinfo->args [n].size = sizeof (gpointer);
1253 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1256 case MONO_TYPE_GENERICINST:
1257 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1258 cinfo->args [n].size = sizeof (gpointer);
1259 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1264 case MONO_TYPE_VALUETYPE:
1265 case MONO_TYPE_TYPEDBYREF: {
1267 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1268 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1269 size = sizeof (MonoTypedRef);
1270 else if (is_pinvoke)
1271 size = mono_class_native_size (klass, NULL);
1273 size = mono_class_value_size (klass, NULL);
1275 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1276 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1277 cinfo->args [n].size = size;
1279 /* It was 7, now it is 8 in LinuxPPC */
1280 if (fr <= PPC_LAST_FPARG_REG) {
1281 cinfo->args [n].regtype = RegTypeFP;
1282 cinfo->args [n].reg = fr;
1284 FP_ALSO_IN_REG (gr ++);
1286 FP_ALSO_IN_REG (gr ++);
1287 ALWAYS_ON_STACK (stack_size += size);
1289 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1290 cinfo->args [n].regtype = RegTypeBase;
1291 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1298 DEBUG(printf ("load %d bytes struct\n",
1299 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1301 #if PPC_PASS_STRUCTS_BY_VALUE
1303 int align_size = size;
1307 int mbr_cnt = member_count (klass);
1308 gboolean is_all_floats = is_float_struct_returnable_via_regs(klass);
1310 if (!is_all_floats) {
1311 rest = PPC_LAST_ARG_REG - gr + 1;
1313 rest = PPC_LAST_FPARG_REG - fr + 1;
1316 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1317 // Pass small (<= 8 member) structures entirely made up of either float or double members
1318 // in FR registers. There have to be at least mbr_cnt registers left.
1319 if (is_all_floats &&
1320 (rest >= mbr_cnt) &&
1322 int mbr_size = float_member_size(klass);
1323 nregs = mbr_cnt; // size / memberSize;
1324 n_in_regs = MIN (rest, nregs);
1325 cinfo->args [n].regtype = RegTypeFPStructByVal;
1326 cinfo->args [n].vtregs = n_in_regs;
1327 cinfo->args [n].size = mbr_size;
1328 cinfo->args [n].vtsize = nregs - n_in_regs;
1329 cinfo->args [n].reg = fr;
1331 if (mbr_size == 4) {
1333 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1336 FP_ALSO_IN_REG (gr += (n_in_regs));
1341 align_size += (sizeof (gpointer) - 1);
1342 align_size &= ~(sizeof (gpointer) - 1);
1343 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1344 n_in_regs = MIN (rest, nregs);
1348 /* FIXME: check this */
1349 if (size >= 3 && size % 4 != 0)
1352 cinfo->args [n].regtype = RegTypeStructByVal;
1353 cinfo->args [n].vtregs = n_in_regs;
1354 cinfo->args [n].size = n_in_regs;
1355 cinfo->args [n].vtsize = nregs - n_in_regs;
1356 cinfo->args [n].reg = gr;
1360 #ifdef __mono_ppc64__
1361 if (nregs == 1 && is_pinvoke)
1362 cinfo->args [n].bytes = size;
1365 cinfo->args [n].bytes = 0;
1366 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1367 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1368 stack_size += nregs * sizeof (gpointer);
1371 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1372 cinfo->args [n].regtype = RegTypeStructByAddr;
1373 cinfo->args [n].vtsize = size;
1380 cinfo->args [n].size = 8;
1381 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1385 cinfo->args [n].size = 4;
1387 /* It was 7, now it is 8 in LinuxPPC */
1388 if (fr <= PPC_LAST_FPARG_REG
1389 #if (_CALL_ELF == 2)
1390 // For non-native vararg calls the parms must go in storage
1391 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1394 cinfo->args [n].regtype = RegTypeFP;
1395 cinfo->args [n].reg = fr;
1397 FP_ALSO_IN_REG (gr ++);
1398 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1400 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1401 cinfo->args [n].regtype = RegTypeBase;
1402 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1403 stack_size += SIZEOF_REGISTER;
1408 cinfo->args [n].size = 8;
1409 /* It was 7, now it is 8 in LinuxPPC */
1410 if (fr <= PPC_LAST_FPARG_REG
1411 #if (_CALL_ELF == 2)
1412 // For non-native vararg calls the parms must go in storage
1413 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1416 cinfo->args [n].regtype = RegTypeFP;
1417 cinfo->args [n].reg = fr;
1419 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1420 ALWAYS_ON_STACK (stack_size += 8);
1422 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1423 cinfo->args [n].regtype = RegTypeBase;
1424 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1430 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1435 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1436 /* Prevent implicit arguments and sig_cookie from
1437 being passed in registers */
1438 gr = PPC_LAST_ARG_REG + 1;
1439 /* Emit the signature cookie just before the implicit arguments */
1440 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1444 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1445 switch (simpletype->type) {
1446 case MONO_TYPE_BOOLEAN:
1451 case MONO_TYPE_CHAR:
1457 case MONO_TYPE_FNPTR:
1458 case MONO_TYPE_CLASS:
1459 case MONO_TYPE_OBJECT:
1460 case MONO_TYPE_SZARRAY:
1461 case MONO_TYPE_ARRAY:
1462 case MONO_TYPE_STRING:
1463 cinfo->ret.reg = ppc_r3;
1467 cinfo->ret.reg = ppc_r3;
1471 cinfo->ret.reg = ppc_f1;
1472 cinfo->ret.regtype = RegTypeFP;
1474 case MONO_TYPE_GENERICINST:
1475 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1476 cinfo->ret.reg = ppc_r3;
1480 case MONO_TYPE_VALUETYPE:
1482 case MONO_TYPE_TYPEDBYREF:
1483 case MONO_TYPE_VOID:
1486 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1490 /* align stack size to 16 */
1491 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1492 stack_size = (stack_size + 15) & ~15;
1494 cinfo->stack_usage = stack_size;
1499 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1505 c1 = get_call_info (NULL, caller_sig);
1506 c2 = get_call_info (NULL, callee_sig);
1507 res = c1->stack_usage >= c2->stack_usage;
1508 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1509 /* An address on the callee's stack is passed as the first argument */
1511 for (i = 0; i < c2->nargs; ++i) {
1512 if (c2->args [i].regtype == RegTypeStructByAddr)
1513 /* An address on the callee's stack is passed as the argument */
1518 if (!mono_debug_count ())
1529 * Set var information according to the calling convention. ppc version.
1530 * The locals var stuff should most likely be split in another method.
1533 mono_arch_allocate_vars (MonoCompile *m)
1535 MonoMethodSignature *sig;
1536 MonoMethodHeader *header;
1538 int i, offset, size, align, curinst;
1539 int frame_reg = ppc_sp;
1541 guint32 locals_stack_size, locals_stack_align;
1543 m->flags |= MONO_CFG_HAS_SPILLUP;
1545 /* allow room for the vararg method args: void* and long/double */
1546 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1547 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1548 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1549 * call convs needs to be handled this way.
1551 if (m->flags & MONO_CFG_HAS_VARARGS)
1552 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1553 /* gtk-sharp and other broken code will dllimport vararg functions even with
1554 * non-varargs signatures. Since there is little hope people will get this right
1555 * we assume they won't.
1557 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1558 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1563 * We use the frame register also for any method that has
1564 * exception clauses. This way, when the handlers are called,
1565 * the code will reference local variables using the frame reg instead of
1566 * the stack pointer: if we had to restore the stack pointer, we'd
1567 * corrupt the method frames that are already on the stack (since
1568 * filters get called before stack unwinding happens) when the filter
1569 * code would call any method (this also applies to finally etc.).
1571 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1572 frame_reg = ppc_r31;
1573 m->frame_reg = frame_reg;
1574 if (frame_reg != ppc_sp) {
1575 m->used_int_regs |= 1 << frame_reg;
1578 sig = mono_method_signature (m->method);
1582 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1584 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1585 gboolean is_all_floats = is_float_struct_returnable_via_regs(klass);
1586 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(klass, sig->pinvoke);
1588 m->ret->backend.additional_regs = 0;
1589 m->ret->opcode = OP_REGVAR;
1590 if (!is_all_floats) {
1591 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1592 DEBUG_ELFABIV2_printf("Changed m->ret->dreg to ppc_r3: "); DEBUG_ELFABIV2_mono_print_ins(m->ret);
1593 if (is_returnable_via_regs) {
1595 size = mono_type_native_stack_size (sig->ret, 0);
1597 size = mini_type_stack_size (NULL, sig->ret, 0);
1598 if (size > 8) { // FIXME: replace "8" with proper constant
1599 m->ret->backend.additional_regs = 1;
1600 DEBUG_ELFABIV2_printf(" and added ppc_r4 for non-floats (later): "); DEBUG_ELFABIV2_mono_print_ins(m->ret);
1603 } else { // is_all_floats
1604 int mbr_cnt = member_count(klass);
1605 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1606 DEBUG_ELFABIV2_printf("Changed m->ret->dreg to ppc_f1: "); DEBUG_ELFABIV2_mono_print_ins(m->ret);
1608 m->ret->backend.additional_regs = 1;
1612 /* FIXME: handle long values? */
1613 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1614 case MONO_TYPE_VOID:
1618 m->ret->opcode = OP_REGVAR;
1619 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1622 m->ret->opcode = OP_REGVAR;
1623 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1627 /* local vars are at a positive offset from the stack pointer */
1629 * also note that if the function uses alloca, we use ppc_r31
1630 * to point at the local variables.
1632 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1633 /* align the offset to 16 bytes: not sure this is needed here */
1635 //offset &= ~(16 - 1);
1637 /* add parameter area size for called functions */
1638 offset += m->param_area;
1640 offset &= ~(16 - 1);
1642 /* allow room to save the return value */
1643 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1646 /* the MonoLMF structure is stored just below the stack pointer */
1649 /* this stuff should not be needed on ppc and the new jit,
1650 * because a call on ppc to the handlers doesn't change the
1651 * stack pointer and the jist doesn't manipulate the stack pointer
1652 * for operations involving valuetypes.
1654 /* reserve space to store the esp */
1655 offset += sizeof (gpointer);
1657 /* this is a global constant */
1658 mono_exc_esp_offset = offset;
1661 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1662 // The return value for a structure may either be returned via address or via registers depending on its size
1663 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1664 gboolean is_all_floats = is_float_struct_returnable_via_regs(klass);
1665 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(klass, sig->pinvoke);
1667 if (!is_all_floats && !is_returnable_via_regs) {
1668 // function value will be returned indirectly
1669 offset += sizeof(gpointer) - 1;
1670 offset &= ~(sizeof(gpointer) - 1);
1672 m->vret_addr->opcode = OP_REGOFFSET;
1673 m->vret_addr->inst_basereg = frame_reg;
1674 m->vret_addr->inst_offset = offset;
1676 if (G_UNLIKELY (m->verbose_level > 1)) {
1677 printf ("vret_addr =");
1678 mono_print_ins (m->vret_addr);
1681 offset += sizeof(gpointer);
1684 // function return value will be returned via registers
1685 // Anything to do here?
1689 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1690 if (locals_stack_align) {
1691 offset += (locals_stack_align - 1);
1692 offset &= ~(locals_stack_align - 1);
1694 for (i = m->locals_start; i < m->num_varinfo; i++) {
1695 if (offsets [i] != -1) {
1696 MonoInst *inst = m->varinfo [i];
1697 inst->opcode = OP_REGOFFSET;
1698 inst->inst_basereg = frame_reg;
1699 inst->inst_offset = offset + offsets [i];
1701 g_print ("allocating local %d (%s) to %d\n",
1702 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1706 offset += locals_stack_size;
1710 inst = m->args [curinst];
1711 if (inst->opcode != OP_REGVAR) {
1712 inst->opcode = OP_REGOFFSET;
1713 inst->inst_basereg = frame_reg;
1714 offset += sizeof (gpointer) - 1;
1715 offset &= ~(sizeof (gpointer) - 1);
1716 inst->inst_offset = offset;
1717 offset += sizeof (gpointer);
1722 for (i = 0; i < sig->param_count; ++i) {
1723 inst = m->args [curinst];
1724 if (inst->opcode != OP_REGVAR) {
1725 inst->opcode = OP_REGOFFSET;
1726 inst->inst_basereg = frame_reg;
1728 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1729 inst->backend.is_pinvoke = 1;
1731 size = mono_type_size (sig->params [i], &align);
1733 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1734 size = align = sizeof (gpointer);
1736 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1737 * they are saved using std in the prolog.
1739 align = sizeof (gpointer);
1740 offset += align - 1;
1741 offset &= ~(align - 1);
1742 inst->inst_offset = offset;
1748 /* some storage for fp conversions */
1751 m->arch.fp_conv_var_offset = offset;
1754 /* align the offset to 16 bytes */
1756 offset &= ~(16 - 1);
1759 m->stack_offset = offset;
1761 if (sig->call_convention == MONO_CALL_VARARG) {
1762 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1764 m->sig_cookie = cinfo->sig_cookie.offset;
1771 mono_arch_create_vars (MonoCompile *cfg)
1773 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1775 // The return value for a structure may either be returned via address or via registers depending on its size
1776 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1777 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1778 gboolean is_all_floats = is_float_struct_returnable_via_regs(klass);
1779 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(klass, sig->pinvoke);
1781 if (!is_all_floats && !is_returnable_via_regs) {
1782 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1787 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1788 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1792 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1794 int sig_reg = mono_alloc_ireg (cfg);
1796 /* FIXME: Add support for signature tokens to AOT */
1797 cfg->disable_aot = TRUE;
1799 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1801 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1805 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1808 MonoMethodSignature *sig;
1812 sig = call->signature;
1813 n = sig->param_count + sig->hasthis;
1815 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1817 for (i = 0; i < n; ++i) {
1818 ArgInfo *ainfo = cinfo->args + i;
1821 if (i >= sig->hasthis)
1822 t = sig->params [i - sig->hasthis];
1824 t = &mono_defaults.int_class->byval_arg;
1825 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1827 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1828 emit_sig_cookie (cfg, call, cinfo);
1830 in = call->args [i];
1832 if (ainfo->regtype == RegTypeGeneral) {
1833 #ifndef __mono_ppc64__
1834 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1835 MONO_INST_NEW (cfg, ins, OP_MOVE);
1836 ins->dreg = mono_alloc_ireg (cfg);
1837 ins->sreg1 = in->dreg + 1;
1838 MONO_ADD_INS (cfg->cbb, ins);
1839 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1841 MONO_INST_NEW (cfg, ins, OP_MOVE);
1842 ins->dreg = mono_alloc_ireg (cfg);
1843 ins->sreg1 = in->dreg + 2;
1844 MONO_ADD_INS (cfg->cbb, ins);
1845 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1849 MONO_INST_NEW (cfg, ins, OP_MOVE);
1850 ins->dreg = mono_alloc_ireg (cfg);
1851 ins->sreg1 = in->dreg;
1852 MONO_ADD_INS (cfg->cbb, ins);
1854 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1856 } else if (ainfo->regtype == RegTypeStructByAddr) {
1857 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1858 ins->opcode = OP_OUTARG_VT;
1859 ins->sreg1 = in->dreg;
1860 ins->klass = in->klass;
1861 ins->inst_p0 = call;
1862 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1863 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1864 MONO_ADD_INS (cfg->cbb, ins);
1865 } else if (ainfo->regtype == RegTypeStructByVal) {
1866 /* this is further handled in mono_arch_emit_outarg_vt () */
1867 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1868 ins->opcode = OP_OUTARG_VT;
1869 ins->sreg1 = in->dreg;
1870 ins->klass = in->klass;
1871 ins->inst_p0 = call;
1872 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1873 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1874 MONO_ADD_INS (cfg->cbb, ins);
1875 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1876 /* this is further handled in mono_arch_emit_outarg_vt () */
1877 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1878 ins->opcode = OP_OUTARG_VT;
1879 ins->sreg1 = in->dreg;
1880 ins->klass = in->klass;
1881 ins->inst_p0 = call;
1882 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1883 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1884 MONO_ADD_INS (cfg->cbb, ins);
1885 cfg->flags |= MONO_CFG_HAS_FPOUT;
1886 } else if (ainfo->regtype == RegTypeBase) {
1887 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1888 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1889 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1890 if (t->type == MONO_TYPE_R8)
1891 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1893 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1895 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1897 } else if (ainfo->regtype == RegTypeFP) {
1898 if (t->type == MONO_TYPE_VALUETYPE) {
1899 /* this is further handled in mono_arch_emit_outarg_vt () */
1900 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1901 ins->opcode = OP_OUTARG_VT;
1902 ins->sreg1 = in->dreg;
1903 ins->klass = in->klass;
1904 ins->inst_p0 = call;
1905 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1906 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1907 MONO_ADD_INS (cfg->cbb, ins);
1909 cfg->flags |= MONO_CFG_HAS_FPOUT;
1911 int dreg = mono_alloc_freg (cfg);
1913 if (ainfo->size == 4) {
1914 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1916 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1918 ins->sreg1 = in->dreg;
1919 MONO_ADD_INS (cfg->cbb, ins);
1922 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1923 cfg->flags |= MONO_CFG_HAS_FPOUT;
1926 g_assert_not_reached ();
1930 /* Emit the signature cookie in the case that there is no
1931 additional argument */
1932 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1933 emit_sig_cookie (cfg, call, cinfo);
1935 if (cinfo->struct_ret) {
1936 // Handle returning small structs via registers
1937 // This is active for two cases:
1938 // 1) All-float (or double) member structs with 8 or fewer members
1939 // 2) Other non-float structures 16 bytes or smaller
1940 gboolean is_all_floats = is_float_struct_returnable_via_regs(((MonoInst*)call)->klass); // Also verifies <= 8 members
1941 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(((MonoInst*)call)->klass, sig->pinvoke); // Also verifies <= 8 members
1943 if (!is_all_floats && !is_returnable_via_regs) {
1946 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1947 vtarg->sreg1 = call->vret_var->dreg;
1948 vtarg->dreg = mono_alloc_preg (cfg);
1949 MONO_ADD_INS (cfg->cbb, vtarg);
1951 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1953 // structure will be returned via registers
1954 DEBUG_ELFABIV2_printf("mono_arch_emit_call call->vret_in_reg = TRUE! for "); DEBUG_ELFABIV2_mono_print_ins((MonoInst*)call);
1955 call->vret_in_reg = TRUE;
1959 call->stack_usage = cinfo->stack_usage;
1960 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1961 cfg->flags |= MONO_CFG_HAS_CALLS;
1969 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1971 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1972 ArgInfo *ainfo = ins->inst_p1;
1973 int ovf_size = ainfo->vtsize;
1974 int doffset = ainfo->offset;
1975 int i, soffset, dreg;
1977 if (ainfo->regtype == RegTypeStructByVal) {
1984 * Darwin pinvokes needs some special handling for 1
1985 * and 2 byte arguments
1987 g_assert (ins->klass);
1988 if (call->signature->pinvoke)
1989 size = mono_class_native_size (ins->klass, NULL);
1990 if (size == 2 || size == 1) {
1991 int tmpr = mono_alloc_ireg (cfg);
1993 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1995 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1996 dreg = mono_alloc_ireg (cfg);
1997 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1998 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
2001 for (i = 0; i < ainfo->vtregs; ++i) {
2002 dreg = mono_alloc_ireg (cfg);
2003 if (ainfo->bytes && mono_class_native_size (ins->klass, NULL) == 1) {
2004 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
2005 } else if (ainfo->bytes && mono_class_native_size (ins->klass, NULL) == 2) {
2006 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, dreg, src->dreg, soffset);
2007 } else if (ainfo->bytes && mono_class_native_size (ins->klass, NULL) == 4) { // FIXME -- Maybe <= 4?
2008 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, dreg, src->dreg, soffset);
2010 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
2012 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
2013 soffset += sizeof (gpointer);
2016 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
2017 } else if (ainfo->regtype == RegTypeFPStructByVal) {
2019 for (i = 0; i < ainfo->vtregs; ++i) {
2020 int tmpr = mono_alloc_freg (cfg);
2021 if (ainfo->size == 4)
2022 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
2024 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
2025 dreg = mono_alloc_freg (cfg);
2026 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
2027 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
2028 soffset += ainfo->size;
2031 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
2032 } else if (ainfo->regtype == RegTypeFP) {
2033 int tmpr = mono_alloc_freg (cfg);
2034 if (ainfo->size == 4)
2035 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
2037 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
2038 dreg = mono_alloc_freg (cfg);
2039 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
2040 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
2042 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
2046 /* FIXME: alignment? */
2047 if (call->signature->pinvoke) {
2048 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
2049 vtcopy->backend.is_pinvoke = 1;
2051 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
2054 g_assert (ovf_size > 0);
2056 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
2057 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
2060 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
2062 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
2067 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2069 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
2070 mono_method_signature (method)->ret);
2073 #ifndef __mono_ppc64__
2074 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
2077 MONO_INST_NEW (cfg, ins, OP_SETLRET);
2078 ins->sreg1 = val->dreg + 1;
2079 ins->sreg2 = val->dreg + 2;
2080 MONO_ADD_INS (cfg->cbb, ins);
2084 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
2085 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
2089 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2092 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
2094 mono_arch_is_inst_imm (gint64 imm)
2099 #endif /* DISABLE_JIT */
2102 * Allow tracing to work with this interface (with an optional argument)
2106 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2110 ppc_load_ptr (code, ppc_r3, cfg->method);
2111 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
2112 ppc_load_func (code, PPC_CALL_REG, func);
2113 ppc_mtlr (code, PPC_CALL_REG);
2127 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
2130 int save_mode = SAVE_NONE;
2132 MonoMethod *method = cfg->method;
2133 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
2134 mono_method_signature (method)->ret)->type;
2135 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
2139 offset = code - cfg->native_code;
2140 /* we need about 16 instructions */
2141 if (offset > (cfg->code_size - 16 * 4)) {
2142 cfg->code_size *= 2;
2143 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2144 code = cfg->native_code + offset;
2148 case MONO_TYPE_VOID:
2149 /* special case string .ctor icall */
2150 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
2151 save_mode = SAVE_ONE;
2153 save_mode = SAVE_NONE;
2155 #ifndef __mono_ppc64__
2158 save_mode = SAVE_TWO;
2163 save_mode = SAVE_FP;
2165 case MONO_TYPE_VALUETYPE:
2166 save_mode = SAVE_STRUCT;
2169 save_mode = SAVE_ONE;
2173 switch (save_mode) {
2175 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
2176 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2177 if (enable_arguments) {
2178 ppc_mr (code, ppc_r5, ppc_r4);
2179 ppc_mr (code, ppc_r4, ppc_r3);
2183 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
2184 if (enable_arguments) {
2185 ppc_mr (code, ppc_r4, ppc_r3);
2189 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
2190 if (enable_arguments) {
2191 /* FIXME: what reg? */
2192 ppc_fmr (code, ppc_f3, ppc_f1);
2193 /* FIXME: use 8 byte load on PPC64 */
2194 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
2195 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
2199 if (enable_arguments) {
2200 /* FIXME: get the actual address */
2201 ppc_mr (code, ppc_r4, ppc_r3);
2202 // FIXME: Support the new v2 ABI!
2210 ppc_load_ptr (code, ppc_r3, cfg->method);
2211 ppc_load_func (code, PPC_CALL_REG, func);
2212 ppc_mtlr (code, PPC_CALL_REG);
2215 switch (save_mode) {
2217 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
2218 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
2221 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
2224 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
2234 * Conditional branches have a small offset, so if it is likely overflowed,
2235 * we do a branch to the end of the method (uncond branches have much larger
2236 * offsets) where we perform the conditional and jump back unconditionally.
2237 * It's slightly slower, since we add two uncond branches, but it's very simple
2238 * with the current patch implementation and such large methods are likely not
2239 * going to be perf critical anyway.
2244 const char *exception;
2251 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
2252 if (0 && ins->inst_true_bb->native_offset) { \
2253 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
2255 int br_disp = ins->inst_true_bb->max_offset - offset; \
2256 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2257 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2258 ovfj->data.bb = ins->inst_true_bb; \
2259 ovfj->ip_offset = 0; \
2260 ovfj->b0_cond = (b0); \
2261 ovfj->b1_cond = (b1); \
2262 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
2265 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2266 ppc_bc (code, (b0), (b1), 0); \
2270 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
2272 /* emit an exception if condition is fail
2274 * We assign the extra code used to throw the implicit exceptions
2275 * to cfg->bb_exit as far as the big branch handling is concerned
2277 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2279 int br_disp = cfg->bb_exit->max_offset - offset; \
2280 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2281 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2282 ovfj->data.exception = (exc_name); \
2283 ovfj->ip_offset = code - cfg->native_code; \
2284 ovfj->b0_cond = (b0); \
2285 ovfj->b1_cond = (b1); \
2286 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2288 cfg->bb_exit->max_offset += 24; \
2290 mono_add_patch_info (cfg, code - cfg->native_code, \
2291 MONO_PATCH_INFO_EXC, exc_name); \
2292 ppc_bcl (code, (b0), (b1), 0); \
2296 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2299 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2304 normalize_opcode (int opcode)
2307 #ifndef __mono_ilp32__
2308 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2309 return OP_LOAD_MEMBASE;
2310 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2311 return OP_LOAD_MEMINDEX;
2312 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2313 return OP_STORE_MEMBASE_REG;
2314 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2315 return OP_STORE_MEMBASE_IMM;
2316 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2317 return OP_STORE_MEMINDEX;
2319 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2321 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2322 return OP_SHR_UN_IMM;
2329 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2331 MonoInst *ins, *n, *last_ins = NULL;
2333 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2334 switch (normalize_opcode (ins->opcode)) {
2336 /* remove unnecessary multiplication with 1 */
2337 if (ins->inst_imm == 1) {
2338 if (ins->dreg != ins->sreg1) {
2339 ins->opcode = OP_MOVE;
2341 MONO_DELETE_INS (bb, ins);
2345 int power2 = mono_is_power_of_two (ins->inst_imm);
2347 ins->opcode = OP_SHL_IMM;
2348 ins->inst_imm = power2;
2352 case OP_LOAD_MEMBASE:
2354 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2355 * OP_LOAD_MEMBASE offset(basereg), reg
2357 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2358 ins->inst_basereg == last_ins->inst_destbasereg &&
2359 ins->inst_offset == last_ins->inst_offset) {
2360 if (ins->dreg == last_ins->sreg1) {
2361 MONO_DELETE_INS (bb, ins);
2364 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2365 ins->opcode = OP_MOVE;
2366 ins->sreg1 = last_ins->sreg1;
2370 * Note: reg1 must be different from the basereg in the second load
2371 * OP_LOAD_MEMBASE offset(basereg), reg1
2372 * OP_LOAD_MEMBASE offset(basereg), reg2
2374 * OP_LOAD_MEMBASE offset(basereg), reg1
2375 * OP_MOVE reg1, reg2
2377 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2378 ins->inst_basereg != last_ins->dreg &&
2379 ins->inst_basereg == last_ins->inst_basereg &&
2380 ins->inst_offset == last_ins->inst_offset) {
2382 if (ins->dreg == last_ins->dreg) {
2383 MONO_DELETE_INS (bb, ins);
2386 ins->opcode = OP_MOVE;
2387 ins->sreg1 = last_ins->dreg;
2390 //g_assert_not_reached ();
2394 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2395 * OP_LOAD_MEMBASE offset(basereg), reg
2397 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2398 * OP_ICONST reg, imm
2400 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2401 ins->inst_basereg == last_ins->inst_destbasereg &&
2402 ins->inst_offset == last_ins->inst_offset) {
2403 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2404 ins->opcode = OP_ICONST;
2405 ins->inst_c0 = last_ins->inst_imm;
2406 g_assert_not_reached (); // check this rule
2410 case OP_LOADU1_MEMBASE:
2411 case OP_LOADI1_MEMBASE:
2412 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2413 ins->inst_basereg == last_ins->inst_destbasereg &&
2414 ins->inst_offset == last_ins->inst_offset) {
2415 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2416 ins->sreg1 = last_ins->sreg1;
2419 case OP_LOADU2_MEMBASE:
2420 case OP_LOADI2_MEMBASE:
2421 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2422 ins->inst_basereg == last_ins->inst_destbasereg &&
2423 ins->inst_offset == last_ins->inst_offset) {
2424 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2425 ins->sreg1 = last_ins->sreg1;
2428 #ifdef __mono_ppc64__
2429 case OP_LOADU4_MEMBASE:
2430 case OP_LOADI4_MEMBASE:
2431 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2432 ins->inst_basereg == last_ins->inst_destbasereg &&
2433 ins->inst_offset == last_ins->inst_offset) {
2434 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2435 ins->sreg1 = last_ins->sreg1;
2440 ins->opcode = OP_MOVE;
2444 if (ins->dreg == ins->sreg1) {
2445 MONO_DELETE_INS (bb, ins);
2449 * OP_MOVE sreg, dreg
2450 * OP_MOVE dreg, sreg
2452 if (last_ins && last_ins->opcode == OP_MOVE &&
2453 ins->sreg1 == last_ins->dreg &&
2454 ins->dreg == last_ins->sreg1) {
2455 MONO_DELETE_INS (bb, ins);
2463 bb->last_ins = last_ins;
2467 #ifdef MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS
2469 mono_arch_decompose_vtype_opts (MonoCompile *cfg, MonoInst *ins, MonoBasicBlock *bb)
2471 MonoInst *dest_var=0, *src=0, *dest=0;
2472 gboolean is_all_floats = FALSE;
2473 gboolean is_returnable_via_regs = FALSE;
2476 int return_value_size = 0;
2478 switch (ins->opcode) {
2480 MonoInst *src_var=0;
2481 // For now this code only handles small structures returned from functions. Everything else is handled by the "generic" code.
2482 MonoMethodSignature *sig = mono_method_signature (cfg->method);
2483 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
2487 is_all_floats = is_float_struct_returnable_via_regs(ins->klass);
2488 is_returnable_via_regs = is_struct_returnable_via_regs(ins->klass, sig->pinvoke);
2490 if (!is_all_floats && !is_returnable_via_regs) {
2494 DEBUG_ELFABIV2_printf("mono_arch_decompose_vtype_opts OP_VMOVE, ins->dreg: %d, ins->klass: ", (int)ins->dreg); DEBUG_ELFABIV2_mono_print_klass(ins->klass);
2496 src_var = get_vreg_to_inst (cfg, ins->sreg1);
2498 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
2501 dest_var = get_vreg_to_inst (cfg, ins->dreg);
2503 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
2505 DEBUG_ELFABIV2_printf(" src_var: "); DEBUG_ELFABIV2_mono_print_ins(src_var);
2506 DEBUG_ELFABIV2_printf(" dest_var: "); DEBUG_ELFABIV2_mono_print_ins(dest_var);
2507 DEBUG_ELFABIV2_printf(" cfg->ret: "); if (is_all_floats) DEBUG_ELFABIV2_printf("all_floats ");DEBUG_ELFABIV2_mono_print_ins(cfg->ret);
2508 DEBUG_ELFABIV2_printf(" ins: "); DEBUG_ELFABIV2_mono_print_ins(ins);
2509 if (!src_var || !dest_var || (dest_var != cfg->ret)) {
2513 g_assert (ins->klass);
2514 DEBUG_ELFABIV2_printf("Converting OP_VMOVE for returning value via registers\n");
2517 if (src_var->backend.is_pinvoke)
2518 dest_var->backend.is_pinvoke = 1;
2520 // return of structure via registers
2521 g_assert(src_var->klass);
2522 if (is_all_floats) {
2523 // Pass small (<= 8 member) structures entirely made up of either float or double members
2524 // in FR registers. There have to be at least 8 registers left.
2525 mbr_cnt = member_count(ins->klass);
2526 mbr_size = float_member_size(ins->klass);
2527 DEBUG_ELFABIV2_printf("is_float_struct_returnable_via_regs with length %d, %d members, member size %d\n", return_value_size, mbr_cnt, mbr_size);
2528 if (mbr_size == 4) {
2529 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
2530 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, ins->dreg, src->dreg, 0);
2532 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
2533 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, ins->dreg, src->dreg, 0);
2536 // Not a homogenous float structure
2538 return_value_size = mono_type_native_stack_size (sig->ret, 0);
2540 return_value_size = mini_type_stack_size (NULL, sig->ret, 0);
2541 DEBUG_ELFABIV2_printf("is_struct_returnable_via_regs with length %d\n", return_value_size);
2542 g_assert(is_returnable_via_regs);
2543 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
2544 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ins->dreg, src->dreg, 0);
2550 int return_value_size = 0;
2552 // For now this code only handles small structures returned from functions. Everything else is handled by the "generic" code.
2553 MonoMethodSignature *sig = mono_method_signature (cfg->method);
2554 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
2558 return_value_size = mono_type_native_stack_size (sig->ret, 0);
2560 return_value_size = mini_type_stack_size (NULL, sig->ret, 0);
2561 is_all_floats = is_float_struct_returnable_via_regs(ins->klass);
2562 is_returnable_via_regs = is_struct_returnable_via_regs(ins->klass, sig->pinvoke);
2564 if (!is_all_floats && !is_returnable_via_regs) {
2567 if (is_all_floats) {
2568 mbr_cnt = member_count(ins->klass);
2569 mbr_size = float_member_size(ins->klass);
2571 DEBUG_ELFABIV2_printf("mono_arch_decompose_vtype_opts OP_VZERO\n");
2573 dest_var = get_vreg_to_inst (cfg, ins->dreg);
2575 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
2576 DEBUG_ELFABIV2_printf("TMP creating dest_var\n");
2578 if (!dest_var || (dest_var != cfg->ret)) {
2581 DEBUG_ELFABIV2_printf("OP_VZERO of return value!\n");
2582 DEBUG_ELFABIV2_printf("ins "); DEBUG_ELFABIV2_mono_print_ins(ins);
2583 DEBUG_ELFABIV2_printf("cfg->ret "); DEBUG_ELFABIV2_mono_print_ins(cfg->ret);
2584 DEBUG_ELFABIV2_printf("dest_var "); DEBUG_ELFABIV2_mono_print_ins(dest_var);
2585 // The destination will become a REGVAR
2586 if (SIZEOF_REGISTER == 8)
2587 MONO_EMIT_NEW_I8CONST (cfg, dest_var->dreg, 0);
2589 MONO_EMIT_NEW_ICONST (cfg, dest_var->dreg, 0);
2590 if (return_value_size == 16) {
2591 // FIXME: Potential problem here?
2592 if (SIZEOF_REGISTER == 8)
2593 MONO_EMIT_NEW_I8CONST (cfg, dest_var->dreg+1, 0);
2595 MONO_EMIT_NEW_ICONST (cfg, dest_var->dreg+1, 0);
2598 if (cfg->compute_gc_maps) {
2602 * Tell the GC map code that the vtype is considered live after
2603 * the initialization.
2605 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
2606 tmp->inst_c1 = ins->dreg;
2607 MONO_ADD_INS (cfg->cbb, tmp);
2612 case OP_LOADV_MEMBASE: {
2613 int return_value_size = 0;
2617 // For now this code only handles small structures returned from functions. Everything else is handled by the "generic" code.
2618 MonoMethodSignature *sig = mono_method_signature (cfg->method);
2619 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
2623 dest_var = get_vreg_to_inst (cfg, ins->dreg);
2625 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
2627 if (! dest_var || (dest_var != cfg->ret)) {
2631 return_value_size = mono_type_native_stack_size (sig->ret, 0);
2633 return_value_size = mini_type_stack_size (NULL, sig->ret, 0);
2634 is_all_floats = is_float_struct_returnable_via_regs(ins->klass);
2635 is_returnable_via_regs = is_struct_returnable_via_regs(ins->klass, sig->pinvoke);
2637 if (!is_all_floats && !is_returnable_via_regs) {
2640 DEBUG_ELFABIV2_printf("mono_arch_decompose_vtype_opts DS OP_LOADV_MEMBASE ins: "); DEBUG_ELFABIV2_mono_print_ins(ins);
2642 // Allocate a temp to hold the value we will be returning
2643 temp = mono_compile_create_var (cfg, &dest_var->klass->byval_arg, OP_LOCAL);
2644 dreg = alloc_preg (cfg);
2645 temp->backend.is_pinvoke = dest_var->backend.is_pinvoke;
2646 DEBUG_ELFABIV2_printf(" temp: "); DEBUG_ELFABIV2_mono_print_ins(temp);
2647 dest_var = get_vreg_to_inst (cfg, temp->dreg);
2649 dest_var = mono_compile_create_var_for_vreg (cfg, &temp->klass->byval_arg, OP_LOCAL, temp->dreg);
2652 // This is a very clumsy way of handling this. See if this can be done in a better way.
2654 // Store the value being returned in the temp
2655 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
2656 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
2657 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
2659 if (is_all_floats) {
2660 mbr_cnt = member_count(ins->klass);
2661 mbr_size = float_member_size(ins->klass);
2662 if (mbr_size == 4) {
2663 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, ins->dreg, dest->dreg, 0);
2665 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, ins->dreg, dest->dreg, 0);
2668 // Load the temp for the return via register(s)
2669 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ins->dreg, dest->dreg, 0);
2676 case OP_VCALL_MEMBASE: {
2677 MonoCallInst *call = (MonoCallInst*)ins;
2678 MonoCallInst *call2 = 0;
2679 int return_value_size = 0;
2680 DEBUG_ELFABIV2_printf("mono_arch_decompose_vtype_opts OP_VCALL vret_in_reg: %d, ins: ", call->vret_in_reg); DEBUG_ELFABIV2_mono_print_ins(ins);
2681 DEBUG_ELFABIV2_printf(" ins->klass: "); DEBUG_ELFABIV2_mono_print_klass(ins->klass);
2683 if (!call->vret_in_reg) {
2684 DEBUG_ELFABIV2_printf(" !call->vret_in_reg\n");
2688 /* Compute the vtype location */
2689 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
2691 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
2692 if (!dest_var || (!MONO_TYPE_ISSTRUCT(dest_var->inst_vtype))) {
2693 DEBUG_ELFABIV2_printf(" !dest_var || (!MONO_TYPE_ISSTRUCT(dest_var->inst_vtype))\n");
2697 if (dest_var->backend.is_pinvoke)
2698 return_value_size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
2700 return_value_size = mono_type_size (dest_var->inst_vtype, NULL);
2701 is_all_floats = is_float_struct_returnable_via_regs(dest_var->klass);
2702 is_returnable_via_regs = is_struct_returnable_via_regs(dest_var->klass, dest_var->backend.is_pinvoke);
2704 if (!is_all_floats && !is_returnable_via_regs) {
2705 DEBUG_ELFABIV2_printf(" (!is_all_floats && !is_returnable_via_regs)\n");
2709 DEBUG_ELFABIV2_printf(" dest_var: "); DEBUG_ELFABIV2_mono_print_ins(dest_var);
2710 /* Replace the vcall with an integer call */
2711 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
2712 memcpy (call2, call, sizeof (MonoCallInst));
2713 switch (ins->opcode) {
2715 call2->inst.opcode = OP_CALL;
2718 call2->inst.opcode = OP_CALL_REG;
2720 case OP_VCALL_MEMBASE:
2721 call2->inst.opcode = OP_CALL_MEMBASE;
2724 // Note: mono_arch_allocate_vars in ppc-mini.c will set this to ppc_r3
2725 call2->inst.dreg = alloc_preg (cfg); //ppc_r3; //-1; //alloc_preg (cfg);
2726 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
2728 DEBUG_ELFABIV2_printf(" call: "); DEBUG_ELFABIV2_mono_print_ins((MonoInst*)call);
2729 DEBUG_ELFABIV2_printf(" call2: "); DEBUG_ELFABIV2_mono_print_ins((MonoInst*)call2);
2730 DEBUG_ELFABIV2_printf(" cfg->ret: "); DEBUG_ELFABIV2_mono_print_ins(cfg->ret);
2731 // If the dest_var of this call is the return var of this (the calling) function we do not need to store
2732 // the returned value because it will be returned via the same registers.
2733 if (dest_var == cfg->ret) {
2734 DEBUG_ELFABIV2_printf("returning function value directly (already in the right registers from call on return)\n");
2736 if ((ins->next) && (ins->next->opcode == OP_DUMMY_USE)) {
2737 // If a call is followed by a DUMMY_USE it can cause ppc_r3 to be erroneously reloaded with an earlier saved value. Just remove the DUMMY_USE.
2738 // TBD: A better solution would be to not insert the DUMMY_USE but that might not be possible. The test case
2739 // appdomain1 demonstrates this problem.
2740 ins->next->opcode = OP_NOP;
2742 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
2744 g_assert(ins->klass);
2745 /* Save the result */
2746 if (is_all_floats) {
2747 // Small structures entirely made up of either float or double members
2748 // are returned in FR registers.
2749 int mbr_size = float_member_size(ins->klass);
2750 int mbr_cnt = member_count(ins->klass);
2752 DEBUG_ELFABIV2_printf("storing function result, is_float_struct_returnable_via_regs(ins->klass) with length %d, %d members, member size %d\n", return_value_size, mbr_cnt, mbr_size);
2754 for (cnt=0; cnt < mbr_cnt; ++cnt) {
2755 if (mbr_size == 4) {
2756 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, cnt*mbr_size, ppc_f1+cnt);
2758 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, cnt*mbr_size, ppc_f1+cnt);
2762 MonoInst *dummy_use3=0;
2763 //MonoInst *dummy_use4=0;
2764 DEBUG_ELFABIV2_printf("storing function result, is_struct_returnable_via_regs(ins->klass) with length %d\n", return_value_size);
2765 DEBUG_ELFABIV2_printf(" ins->next: "); DEBUG_ELFABIV2_mono_print_ins(ins->next);
2766 g_assert(is_returnable_via_regs);
2767 // TBD: Improve the following code...
2768 // Emit a store (or stores) of the values that are in ppc_r3/ppc_r4. Also emit a DUMMY_USE to
2769 // prevent the register spilling code from overwriting ppc_r3.
2770 // TBD: See if this can happen for ppc_r4 as well.
2771 switch (return_value_size) {
2773 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2774 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2777 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2778 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2782 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2783 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2789 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2790 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2793 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2794 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 8, ppc_r4);
2795 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2796 // What about ppc_r4?
2800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2801 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 8, ppc_r4);
2802 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2803 // What about ppc_r4?
2808 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2809 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 8, ppc_r4);
2810 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2811 // What about ppc_r4?
2818 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
2819 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 8, ppc_r4);
2820 EMIT_NEW_DUMMY_USE (cfg, dummy_use3, &call2->inst);
2821 // What about ppc_r4?
2825 DEBUG_ELFABIV2_printf("Bad size? %d\n", return_value_size);
2826 g_assert_not_reached ();
2837 } // switch ins->opcode
2844 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2846 switch (ins->opcode) {
2847 case OP_ICONV_TO_R_UN: {
2848 // This value is OK as-is for both big and little endian because of how it is stored
2849 static const guint64 adjust_val = 0x4330000000000000ULL;
2850 int msw_reg = mono_alloc_ireg (cfg);
2851 int adj_reg = mono_alloc_freg (cfg);
2852 int tmp_reg = mono_alloc_freg (cfg);
2853 int basereg = ppc_sp;
2855 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2856 if (!ppc_is_imm16 (offset + 4)) {
2857 basereg = mono_alloc_ireg (cfg);
2858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2860 #if G_BYTE_ORDER == G_BIG_ENDIAN
2861 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2862 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2864 // For little endian the words are reversed
2865 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2866 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2868 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2869 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2870 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2871 ins->opcode = OP_NOP;
2874 #ifndef __mono_ppc64__
2875 case OP_ICONV_TO_R4:
2876 case OP_ICONV_TO_R8: {
2877 /* If we have a PPC_FEATURE_64 machine we can avoid
2878 this and use the fcfid instruction. Otherwise
2879 on an old 32-bit chip and we have to do this the
2881 if (!(cpu_hw_caps & PPC_ISA_64)) {
2882 /* FIXME: change precision for CEE_CONV_R4 */
2883 static const guint64 adjust_val = 0x4330000080000000ULL;
2884 int msw_reg = mono_alloc_ireg (cfg);
2885 int xored = mono_alloc_ireg (cfg);
2886 int adj_reg = mono_alloc_freg (cfg);
2887 int tmp_reg = mono_alloc_freg (cfg);
2888 int basereg = ppc_sp;
2890 if (!ppc_is_imm16 (offset + 4)) {
2891 basereg = mono_alloc_ireg (cfg);
2892 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2894 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2895 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2896 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2897 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2898 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2899 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2900 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2901 if (ins->opcode == OP_ICONV_TO_R4)
2902 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2903 ins->opcode = OP_NOP;
2909 int msw_reg = mono_alloc_ireg (cfg);
2910 int basereg = ppc_sp;
2912 if (!ppc_is_imm16 (offset + 4)) {
2913 basereg = mono_alloc_ireg (cfg);
2914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2916 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2917 #if G_BYTE_ORDER == G_BIG_ENDIAN
2918 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2920 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2922 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2923 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2924 ins->opcode = OP_NOP;
2927 #ifdef __mono_ppc64__
2929 case OP_IADD_OVF_UN:
2931 int shifted1_reg = mono_alloc_ireg (cfg);
2932 int shifted2_reg = mono_alloc_ireg (cfg);
2933 int result_shifted_reg = mono_alloc_ireg (cfg);
2935 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2937 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2938 if (ins->opcode == OP_IADD_OVF_UN)
2939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2942 ins->opcode = OP_NOP;
2952 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2954 switch (ins->opcode) {
2956 /* ADC sets the condition code */
2957 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2958 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2961 case OP_LADD_OVF_UN:
2962 /* ADC sets the condition code */
2963 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2964 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2968 /* SBB sets the condition code */
2969 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2970 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2973 case OP_LSUB_OVF_UN:
2974 /* SBB sets the condition code */
2975 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2976 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2980 /* From gcc generated code */
2981 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2982 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2991 * the branch_b0_table should maintain the order of these
3005 branch_b0_table [] = {
3020 branch_b1_table [] = {
3034 #define NEW_INS(cfg,dest,op) do { \
3035 MONO_INST_NEW((cfg), (dest), (op)); \
3036 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
3040 map_to_reg_reg_op (int op)
3049 case OP_COMPARE_IMM:
3051 case OP_ICOMPARE_IMM:
3053 case OP_LCOMPARE_IMM:
3069 case OP_LOAD_MEMBASE:
3070 return OP_LOAD_MEMINDEX;
3071 case OP_LOADI4_MEMBASE:
3072 return OP_LOADI4_MEMINDEX;
3073 case OP_LOADU4_MEMBASE:
3074 return OP_LOADU4_MEMINDEX;
3075 case OP_LOADI8_MEMBASE:
3076 return OP_LOADI8_MEMINDEX;
3077 case OP_LOADU1_MEMBASE:
3078 return OP_LOADU1_MEMINDEX;
3079 case OP_LOADI2_MEMBASE:
3080 return OP_LOADI2_MEMINDEX;
3081 case OP_LOADU2_MEMBASE:
3082 return OP_LOADU2_MEMINDEX;
3083 case OP_LOADI1_MEMBASE:
3084 return OP_LOADI1_MEMINDEX;
3085 case OP_LOADR4_MEMBASE:
3086 return OP_LOADR4_MEMINDEX;
3087 case OP_LOADR8_MEMBASE:
3088 return OP_LOADR8_MEMINDEX;
3089 case OP_STOREI1_MEMBASE_REG:
3090 return OP_STOREI1_MEMINDEX;
3091 case OP_STOREI2_MEMBASE_REG:
3092 return OP_STOREI2_MEMINDEX;
3093 case OP_STOREI4_MEMBASE_REG:
3094 return OP_STOREI4_MEMINDEX;
3095 case OP_STOREI8_MEMBASE_REG:
3096 return OP_STOREI8_MEMINDEX;
3097 case OP_STORE_MEMBASE_REG:
3098 return OP_STORE_MEMINDEX;
3099 case OP_STORER4_MEMBASE_REG:
3100 return OP_STORER4_MEMINDEX;
3101 case OP_STORER8_MEMBASE_REG:
3102 return OP_STORER8_MEMINDEX;
3103 case OP_STORE_MEMBASE_IMM:
3104 return OP_STORE_MEMBASE_REG;
3105 case OP_STOREI1_MEMBASE_IMM:
3106 return OP_STOREI1_MEMBASE_REG;
3107 case OP_STOREI2_MEMBASE_IMM:
3108 return OP_STOREI2_MEMBASE_REG;
3109 case OP_STOREI4_MEMBASE_IMM:
3110 return OP_STOREI4_MEMBASE_REG;
3111 case OP_STOREI8_MEMBASE_IMM:
3112 return OP_STOREI8_MEMBASE_REG;
3114 return mono_op_imm_to_op (op);
3117 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
3119 #define compare_opcode_is_unsigned(opcode) \
3120 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
3121 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
3122 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
3123 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
3124 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
3125 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
3126 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
3127 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
3130 * Remove from the instruction list the instructions that can't be
3131 * represented with very simple instructions with no register
3135 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
3137 MonoInst *ins, *next, *temp, *last_ins = NULL;
3140 MONO_BB_FOR_EACH_INS (bb, ins) {
3142 switch (ins->opcode) {
3143 case OP_IDIV_UN_IMM:
3146 case OP_IREM_UN_IMM:
3147 CASE_PPC64 (OP_LREM_IMM) {
3148 NEW_INS (cfg, temp, OP_ICONST);
3149 temp->inst_c0 = ins->inst_imm;
3150 temp->dreg = mono_alloc_ireg (cfg);
3151 ins->sreg2 = temp->dreg;
3152 if (ins->opcode == OP_IDIV_IMM)
3153 ins->opcode = OP_IDIV;
3154 else if (ins->opcode == OP_IREM_IMM)
3155 ins->opcode = OP_IREM;
3156 else if (ins->opcode == OP_IDIV_UN_IMM)
3157 ins->opcode = OP_IDIV_UN;
3158 else if (ins->opcode == OP_IREM_UN_IMM)
3159 ins->opcode = OP_IREM_UN;
3160 else if (ins->opcode == OP_LREM_IMM)
3161 ins->opcode = OP_LREM;
3163 /* handle rem separately */
3168 CASE_PPC64 (OP_LREM)
3169 CASE_PPC64 (OP_LREM_UN) {
3171 /* we change a rem dest, src1, src2 to
3172 * div temp1, src1, src2
3173 * mul temp2, temp1, src2
3174 * sub dest, src1, temp2
3176 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
3177 NEW_INS (cfg, mul, OP_IMUL);
3178 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
3179 ins->opcode = OP_ISUB;
3181 NEW_INS (cfg, mul, OP_LMUL);
3182 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
3183 ins->opcode = OP_LSUB;
3185 temp->sreg1 = ins->sreg1;
3186 temp->sreg2 = ins->sreg2;
3187 temp->dreg = mono_alloc_ireg (cfg);
3188 mul->sreg1 = temp->dreg;
3189 mul->sreg2 = ins->sreg2;
3190 mul->dreg = mono_alloc_ireg (cfg);
3191 ins->sreg2 = mul->dreg;
3195 CASE_PPC64 (OP_LADD_IMM)
3198 if (!ppc_is_imm16 (ins->inst_imm)) {
3199 NEW_INS (cfg, temp, OP_ICONST);
3200 temp->inst_c0 = ins->inst_imm;
3201 temp->dreg = mono_alloc_ireg (cfg);
3202 ins->sreg2 = temp->dreg;
3203 ins->opcode = map_to_reg_reg_op (ins->opcode);
3207 CASE_PPC64 (OP_LSUB_IMM)
3209 if (!ppc_is_imm16 (-ins->inst_imm)) {
3210 NEW_INS (cfg, temp, OP_ICONST);
3211 temp->inst_c0 = ins->inst_imm;
3212 temp->dreg = mono_alloc_ireg (cfg);
3213 ins->sreg2 = temp->dreg;
3214 ins->opcode = map_to_reg_reg_op (ins->opcode);
3226 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
3227 #ifdef __mono_ppc64__
3228 if (ins->inst_imm & 0xffffffff00000000ULL)
3232 NEW_INS (cfg, temp, OP_ICONST);
3233 temp->inst_c0 = ins->inst_imm;
3234 temp->dreg = mono_alloc_ireg (cfg);
3235 ins->sreg2 = temp->dreg;
3236 ins->opcode = map_to_reg_reg_op (ins->opcode);
3245 NEW_INS (cfg, temp, OP_ICONST);
3246 temp->inst_c0 = ins->inst_imm;
3247 temp->dreg = mono_alloc_ireg (cfg);
3248 ins->sreg2 = temp->dreg;
3249 ins->opcode = map_to_reg_reg_op (ins->opcode);
3251 case OP_COMPARE_IMM:
3252 case OP_ICOMPARE_IMM:
3253 CASE_PPC64 (OP_LCOMPARE_IMM)
3255 /* Branch opts can eliminate the branch */
3256 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
3257 ins->opcode = OP_NOP;
3261 if (compare_opcode_is_unsigned (next->opcode)) {
3262 if (!ppc_is_uimm16 (ins->inst_imm)) {
3263 NEW_INS (cfg, temp, OP_ICONST);
3264 temp->inst_c0 = ins->inst_imm;
3265 temp->dreg = mono_alloc_ireg (cfg);
3266 ins->sreg2 = temp->dreg;
3267 ins->opcode = map_to_reg_reg_op (ins->opcode);
3270 if (!ppc_is_imm16 (ins->inst_imm)) {
3271 NEW_INS (cfg, temp, OP_ICONST);
3272 temp->inst_c0 = ins->inst_imm;
3273 temp->dreg = mono_alloc_ireg (cfg);
3274 ins->sreg2 = temp->dreg;
3275 ins->opcode = map_to_reg_reg_op (ins->opcode);
3281 if (ins->inst_imm == 1) {
3282 ins->opcode = OP_MOVE;
3285 if (ins->inst_imm == 0) {
3286 ins->opcode = OP_ICONST;
3290 imm = mono_is_power_of_two (ins->inst_imm);
3292 ins->opcode = OP_SHL_IMM;
3293 ins->inst_imm = imm;
3296 if (!ppc_is_imm16 (ins->inst_imm)) {
3297 NEW_INS (cfg, temp, OP_ICONST);
3298 temp->inst_c0 = ins->inst_imm;
3299 temp->dreg = mono_alloc_ireg (cfg);
3300 ins->sreg2 = temp->dreg;
3301 ins->opcode = map_to_reg_reg_op (ins->opcode);
3304 case OP_LOCALLOC_IMM:
3305 NEW_INS (cfg, temp, OP_ICONST);
3306 temp->inst_c0 = ins->inst_imm;
3307 temp->dreg = mono_alloc_ireg (cfg);
3308 ins->sreg1 = temp->dreg;
3309 ins->opcode = OP_LOCALLOC;
3311 case OP_LOAD_MEMBASE:
3312 case OP_LOADI4_MEMBASE:
3313 CASE_PPC64 (OP_LOADI8_MEMBASE)
3314 case OP_LOADU4_MEMBASE:
3315 case OP_LOADI2_MEMBASE:
3316 case OP_LOADU2_MEMBASE:
3317 case OP_LOADI1_MEMBASE:
3318 case OP_LOADU1_MEMBASE:
3319 case OP_LOADR4_MEMBASE:
3320 case OP_LOADR8_MEMBASE:
3321 case OP_STORE_MEMBASE_REG:
3322 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
3323 case OP_STOREI4_MEMBASE_REG:
3324 case OP_STOREI2_MEMBASE_REG:
3325 case OP_STOREI1_MEMBASE_REG:
3326 case OP_STORER4_MEMBASE_REG:
3327 case OP_STORER8_MEMBASE_REG:
3328 /* we can do two things: load the immed in a register
3329 * and use an indexed load, or see if the immed can be
3330 * represented as an ad_imm + a load with a smaller offset
3331 * that fits. We just do the first for now, optimize later.
3333 if (ppc_is_imm16 (ins->inst_offset))
3335 NEW_INS (cfg, temp, OP_ICONST);
3336 temp->inst_c0 = ins->inst_offset;
3337 temp->dreg = mono_alloc_ireg (cfg);
3338 ins->sreg2 = temp->dreg;
3339 ins->opcode = map_to_reg_reg_op (ins->opcode);
3341 case OP_STORE_MEMBASE_IMM:
3342 case OP_STOREI1_MEMBASE_IMM:
3343 case OP_STOREI2_MEMBASE_IMM:
3344 case OP_STOREI4_MEMBASE_IMM:
3345 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
3346 NEW_INS (cfg, temp, OP_ICONST);
3347 temp->inst_c0 = ins->inst_imm;
3348 temp->dreg = mono_alloc_ireg (cfg);
3349 ins->sreg1 = temp->dreg;
3350 ins->opcode = map_to_reg_reg_op (ins->opcode);
3352 goto loop_start; /* make it handle the possibly big ins->inst_offset */
3355 if (cfg->compile_aot) {
3356 /* Keep these in the aot case */
3359 NEW_INS (cfg, temp, OP_ICONST);
3360 temp->inst_c0 = (gulong)ins->inst_p0;
3361 temp->dreg = mono_alloc_ireg (cfg);
3362 ins->inst_basereg = temp->dreg;
3363 ins->inst_offset = 0;
3364 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
3366 /* make it handle the possibly big ins->inst_offset
3367 * later optimize to use lis + load_membase
3373 bb->last_ins = last_ins;
3374 bb->max_vreg = cfg->next_vreg;
3378 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3380 long offset = cfg->arch.fp_conv_var_offset;
3382 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
3383 #ifdef __mono_ppc64__
3385 ppc_fctidz (code, ppc_f0, sreg);
3390 ppc_fctiwz (code, ppc_f0, sreg);
3393 if (ppc_is_imm16 (offset + sub_offset)) {
3394 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
3396 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
3398 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
3400 ppc_load (code, dreg, offset);
3401 ppc_add (code, dreg, dreg, cfg->frame_reg);
3402 ppc_stfd (code, ppc_f0, 0, dreg);
3404 ppc_ldr (code, dreg, sub_offset, dreg);
3406 ppc_lwz (code, dreg, sub_offset, dreg);
3410 ppc_andid (code, dreg, dreg, 0xff);
3412 ppc_andid (code, dreg, dreg, 0xffff);
3413 #ifdef __mono_ppc64__
3415 ppc_clrldi (code, dreg, dreg, 32);
3419 ppc_extsb (code, dreg, dreg);
3421 ppc_extsh (code, dreg, dreg);
3422 #ifdef __mono_ppc64__
3424 ppc_extsw (code, dreg, dreg);
3432 const guchar *target;
3437 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
3440 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
3441 #ifdef __mono_ppc64__
3442 g_assert_not_reached ();
3444 PatchData *pdata = (PatchData*)user_data;
3445 guchar *code = data;
3446 guint32 *thunks = data;
3447 guint32 *endthunks = (guint32*)(code + bsize);
3451 int difflow, diffhigh;
3453 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
3454 difflow = (char*)pdata->code - (char*)thunks;
3455 diffhigh = (char*)pdata->code - (char*)endthunks;
3456 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
3459 templ = (guchar*)load;
3460 ppc_load_sequence (templ, ppc_r0, pdata->target);
3462 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
3463 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
3464 while (thunks < endthunks) {
3465 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
3466 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
3467 ppc_patch (pdata->code, (guchar*)thunks);
3470 static int num_thunks = 0;
3472 if ((num_thunks % 20) == 0)
3473 g_print ("num_thunks lookup: %d\n", num_thunks);
3476 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
3477 /* found a free slot instead: emit thunk */
3478 code = (guchar*)thunks;
3479 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
3480 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
3481 ppc_mtctr (code, ppc_r0);
3482 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3483 mono_arch_flush_icache ((guchar*)thunks, 16);
3485 ppc_patch (pdata->code, (guchar*)thunks);
3488 static int num_thunks = 0;
3490 if ((num_thunks % 20) == 0)
3491 g_print ("num_thunks: %d\n", num_thunks);
3495 /* skip 16 bytes, the size of the thunk */
3499 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
3506 handle_thunk (int absolute, guchar *code, const guchar *target) {
3507 MonoDomain *domain = mono_domain_get ();
3511 pdata.target = target;
3512 pdata.absolute = absolute;
3515 mono_domain_lock (domain);
3516 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
3519 /* this uses the first available slot */
3521 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
3523 mono_domain_unlock (domain);
3525 if (pdata.found != 1)
3526 g_print ("thunk failed for %p from %p\n", target, code);
3527 g_assert (pdata.found == 1);
3531 patch_ins (guint8 *code, guint32 ins)
3533 *(guint32*)code = ins;
3534 mono_arch_flush_icache (code, 4);
3538 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
3540 guint32 ins = *(guint32*)code;
3541 guint32 prim = ins >> 26;
3544 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3546 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
3547 gint diff = target - code;
3550 if (diff <= 33554431){
3551 ins = (18 << 26) | (diff) | (ins & 1);
3552 patch_ins (code, ins);
3556 /* diff between 0 and -33554432 */
3557 if (diff >= -33554432){
3558 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
3559 patch_ins (code, ins);
3564 if ((glong)target >= 0){
3565 if ((glong)target <= 33554431){
3566 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
3567 patch_ins (code, ins);
3571 if ((glong)target >= -33554432){
3572 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
3573 patch_ins (code, ins);
3578 handle_thunk (TRUE, code, target);
3581 g_assert_not_reached ();
3589 guint32 li = (gulong)target;
3590 ins = (ins & 0xffff0000) | (ins & 3);
3591 ovf = li & 0xffff0000;
3592 if (ovf != 0 && ovf != 0xffff0000)
3593 g_assert_not_reached ();
3596 // FIXME: assert the top bits of li are 0
3598 gint diff = target - code;
3599 ins = (ins & 0xffff0000) | (ins & 3);
3600 ovf = diff & 0xffff0000;
3601 if (ovf != 0 && ovf != 0xffff0000)
3602 g_assert_not_reached ();
3606 patch_ins (code, ins);
3610 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3611 #ifdef __mono_ppc64__
3612 guint32 *seq = (guint32*)code;
3613 guint32 *branch_ins;
3615 /* the trampoline code will try to patch the blrl, blr, bcctr */
3616 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3618 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
3623 if (ppc_is_load_op (seq [5])
3624 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3625 /* With function descs we need to do more careful
3627 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3630 branch_ins = seq + 8;
3632 branch_ins = seq + 6;
3635 seq = (guint32*)code;
3636 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3637 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3639 if (ppc_is_load_op (seq [5])) {
3640 g_assert (ppc_is_load_op (seq [6]));
3643 guint8 *buf = (guint8*)&seq [5];
3644 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3649 target = mono_get_addr_from_ftnptr ((gpointer)target);
3652 /* FIXME: make this thread safe */
3653 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3654 /* FIXME: we're assuming we're using r12 here */
3655 ppc_load_ptr_sequence (code, ppc_r12, target);
3657 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3659 mono_arch_flush_icache ((guint8*)seq, 28);
3662 /* the trampoline code will try to patch the blrl, blr, bcctr */
3663 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3666 /* this is the lis/ori/mtlr/blrl sequence */
3667 seq = (guint32*)code;
3668 g_assert ((seq [0] >> 26) == 15);
3669 g_assert ((seq [1] >> 26) == 24);
3670 g_assert ((seq [2] >> 26) == 31);
3671 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3672 /* FIXME: make this thread safe */
3673 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3674 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3675 mono_arch_flush_icache (code - 8, 8);
3678 g_assert_not_reached ();
3680 // g_print ("patched with 0x%08x\n", ins);
3684 ppc_patch (guchar *code, const guchar *target)
3686 ppc_patch_full (code, target, FALSE);
3690 mono_ppc_patch (guchar *code, const guchar *target)
3692 ppc_patch (code, target);
3696 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3698 switch (ins->opcode) {
3701 case OP_FCALL_MEMBASE:
3702 if (ins->dreg != ppc_f1)
3703 ppc_fmr (code, ins->dreg, ppc_f1);
3711 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3713 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3717 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3719 long size = cfg->param_area;
3721 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3722 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3727 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3728 if (ppc_is_imm16 (-size)) {
3729 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3731 ppc_load (code, ppc_r12, -size);
3732 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3739 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3741 long size = cfg->param_area;
3743 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3744 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3749 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3750 if (ppc_is_imm16 (size)) {
3751 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3753 ppc_load (code, ppc_r12, size);
3754 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3760 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3764 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3766 MonoInst *ins, *next;
3769 guint8 *code = cfg->native_code + cfg->code_len;
3770 MonoInst *last_ins = NULL;
3771 guint last_offset = 0;
3775 /* we don't align basic blocks of loops on ppc */
3777 if (cfg->verbose_level > 2)
3778 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3780 cpos = bb->max_offset;
3782 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3783 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3784 //g_assert (!mono_compile_aot);
3787 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3788 /* this is not thread save, but good enough */
3789 /* fixme: howto handle overflows? */
3790 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3793 MONO_BB_FOR_EACH_INS (bb, ins) {
3794 offset = code - cfg->native_code;
3796 max_len = ins_native_length (cfg, ins);
3798 if (offset > (cfg->code_size - max_len - 16)) {
3799 cfg->code_size *= 2;
3800 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3801 code = cfg->native_code + offset;
3803 // if (ins->cil_code)
3804 // g_print ("cil code\n");
3805 mono_debug_record_line_number (cfg, ins, offset);
3807 switch (normalize_opcode (ins->opcode)) {
3808 case OP_RELAXED_NOP:
3811 case OP_DUMMY_STORE:
3812 case OP_NOT_REACHED:
3815 case OP_SEQ_POINT: {
3818 if (cfg->compile_aot)
3822 * Read from the single stepping trigger page. This will cause a
3823 * SIGSEGV when single stepping is enabled.
3824 * We do this _before_ the breakpoint, so single stepping after
3825 * a breakpoint is hit will step to the next IL offset.
3827 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3828 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3829 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3832 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3835 * A placeholder for a possible breakpoint inserted by
3836 * mono_arch_set_breakpoint ().
3838 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3843 emit_tls_access (code, ins->dreg, ins->inst_offset);
3846 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3847 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3848 ppc_mr (code, ppc_r4, ppc_r0);
3851 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3852 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3853 ppc_mr (code, ppc_r4, ppc_r0);
3855 case OP_MEMORY_BARRIER:
3858 case OP_STOREI1_MEMBASE_REG:
3859 if (ppc_is_imm16 (ins->inst_offset)) {
3860 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3862 if (ppc_is_imm32 (ins->inst_offset)) {
3863 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3864 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3866 ppc_load (code, ppc_r0, ins->inst_offset);
3867 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3871 case OP_STOREI2_MEMBASE_REG:
3872 if (ppc_is_imm16 (ins->inst_offset)) {
3873 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3875 if (ppc_is_imm32 (ins->inst_offset)) {
3876 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3877 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3879 ppc_load (code, ppc_r0, ins->inst_offset);
3880 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3884 case OP_STORE_MEMBASE_REG:
3885 if (ppc_is_imm16 (ins->inst_offset)) {
3886 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3888 if (ppc_is_imm32 (ins->inst_offset)) {
3889 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3890 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3892 ppc_load (code, ppc_r0, ins->inst_offset);
3893 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3897 #ifdef __mono_ilp32__
3898 case OP_STOREI8_MEMBASE_REG:
3899 if (ppc_is_imm16 (ins->inst_offset)) {
3900 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3902 ppc_load (code, ppc_r0, ins->inst_offset);
3903 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3907 case OP_STOREI1_MEMINDEX:
3908 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3910 case OP_STOREI2_MEMINDEX:
3911 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3913 case OP_STORE_MEMINDEX:
3914 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3917 g_assert_not_reached ();
3919 case OP_LOAD_MEMBASE:
3920 if (ppc_is_imm16 (ins->inst_offset)) {
3921 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3923 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3924 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3925 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3927 ppc_load (code, ppc_r0, ins->inst_offset);
3928 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3931 g_assert(ins->dreg > 0);
3933 case OP_LOADI4_MEMBASE:
3934 #ifdef __mono_ppc64__
3935 if (ppc_is_imm16 (ins->inst_offset)) {
3936 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3938 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3939 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3940 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3942 ppc_load (code, ppc_r0, ins->inst_offset);
3943 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3948 case OP_LOADU4_MEMBASE:
3949 if (ppc_is_imm16 (ins->inst_offset)) {
3950 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3952 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3953 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3954 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3956 ppc_load (code, ppc_r0, ins->inst_offset);
3957 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3961 case OP_LOADI1_MEMBASE:
3962 case OP_LOADU1_MEMBASE:
3963 if (ppc_is_imm16 (ins->inst_offset)) {
3964 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3966 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3967 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3968 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3970 ppc_load (code, ppc_r0, ins->inst_offset);
3971 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3974 if (ins->opcode == OP_LOADI1_MEMBASE)
3975 ppc_extsb (code, ins->dreg, ins->dreg);
3977 case OP_LOADU2_MEMBASE:
3978 if (ppc_is_imm16 (ins->inst_offset)) {
3979 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3981 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3982 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3983 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3985 ppc_load (code, ppc_r0, ins->inst_offset);
3986 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3990 case OP_LOADI2_MEMBASE:
3991 if (ppc_is_imm16 (ins->inst_offset)) {
3992 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3994 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3995 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3996 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3998 ppc_load (code, ppc_r0, ins->inst_offset);
3999 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
4003 #ifdef __mono_ilp32__
4004 case OP_LOADI8_MEMBASE:
4005 if (ppc_is_imm16 (ins->inst_offset)) {
4006 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4008 ppc_load (code, ppc_r0, ins->inst_offset);
4009 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
4013 case OP_LOAD_MEMINDEX:
4014 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4016 case OP_LOADI4_MEMINDEX:
4017 #ifdef __mono_ppc64__
4018 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4021 case OP_LOADU4_MEMINDEX:
4022 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4024 case OP_LOADU2_MEMINDEX:
4025 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4027 case OP_LOADI2_MEMINDEX:
4028 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4030 case OP_LOADU1_MEMINDEX:
4031 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4033 case OP_LOADI1_MEMINDEX:
4034 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4035 ppc_extsb (code, ins->dreg, ins->dreg);
4037 case OP_ICONV_TO_I1:
4038 CASE_PPC64 (OP_LCONV_TO_I1)
4039 ppc_extsb (code, ins->dreg, ins->sreg1);
4041 case OP_ICONV_TO_I2:
4042 CASE_PPC64 (OP_LCONV_TO_I2)
4043 ppc_extsh (code, ins->dreg, ins->sreg1);
4045 case OP_ICONV_TO_U1:
4046 CASE_PPC64 (OP_LCONV_TO_U1)
4047 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
4049 case OP_ICONV_TO_U2:
4050 CASE_PPC64 (OP_LCONV_TO_U2)
4051 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
4055 CASE_PPC64 (OP_LCOMPARE)
4056 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
4058 if (next && compare_opcode_is_unsigned (next->opcode))
4059 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
4061 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
4063 case OP_COMPARE_IMM:
4064 case OP_ICOMPARE_IMM:
4065 CASE_PPC64 (OP_LCOMPARE_IMM)
4066 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
4068 if (next && compare_opcode_is_unsigned (next->opcode)) {
4069 if (ppc_is_uimm16 (ins->inst_imm)) {
4070 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
4072 g_assert_not_reached ();
4075 if (ppc_is_imm16 (ins->inst_imm)) {
4076 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
4078 g_assert_not_reached ();
4084 * gdb does not like encountering a trap in the debugged code. So
4085 * instead of emitting a trap, we emit a call a C function and place a
4089 ppc_mr (code, ppc_r3, ins->sreg1);
4090 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4091 (gpointer)"mono_break");
4092 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4093 ppc_load_func (code, PPC_CALL_REG, 0);
4094 ppc_mtlr (code, PPC_CALL_REG);
4102 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
4105 CASE_PPC64 (OP_LADD)
4106 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
4110 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
4113 if (ppc_is_imm16 (ins->inst_imm)) {
4114 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
4116 g_assert_not_reached ();
4121 CASE_PPC64 (OP_LADD_IMM)
4122 if (ppc_is_imm16 (ins->inst_imm)) {
4123 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
4125 g_assert_not_reached ();
4129 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4131 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
4132 ppc_mfspr (code, ppc_r0, ppc_xer);
4133 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4134 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4136 case OP_IADD_OVF_UN:
4137 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4139 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
4140 ppc_mfspr (code, ppc_r0, ppc_xer);
4141 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
4142 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4145 CASE_PPC64 (OP_LSUB_OVF)
4146 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4148 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
4149 ppc_mfspr (code, ppc_r0, ppc_xer);
4150 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4151 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4153 case OP_ISUB_OVF_UN:
4154 CASE_PPC64 (OP_LSUB_OVF_UN)
4155 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4157 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
4158 ppc_mfspr (code, ppc_r0, ppc_xer);
4159 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
4160 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4162 case OP_ADD_OVF_CARRY:
4163 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4165 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
4166 ppc_mfspr (code, ppc_r0, ppc_xer);
4167 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4168 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4170 case OP_ADD_OVF_UN_CARRY:
4171 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4173 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
4174 ppc_mfspr (code, ppc_r0, ppc_xer);
4175 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
4176 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4178 case OP_SUB_OVF_CARRY:
4179 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4181 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
4182 ppc_mfspr (code, ppc_r0, ppc_xer);
4183 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4184 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4186 case OP_SUB_OVF_UN_CARRY:
4187 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4189 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
4190 ppc_mfspr (code, ppc_r0, ppc_xer);
4191 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
4192 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4196 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
4199 CASE_PPC64 (OP_LSUB)
4200 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
4204 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
4208 CASE_PPC64 (OP_LSUB_IMM)
4209 // we add the negated value
4210 if (ppc_is_imm16 (-ins->inst_imm))
4211 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
4213 g_assert_not_reached ();
4217 g_assert (ppc_is_imm16 (ins->inst_imm));
4218 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
4221 ppc_subfze (code, ins->dreg, ins->sreg1);
4224 CASE_PPC64 (OP_LAND)
4225 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
4226 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
4230 CASE_PPC64 (OP_LAND_IMM)
4231 if (!(ins->inst_imm & 0xffff0000)) {
4232 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
4233 } else if (!(ins->inst_imm & 0xffff)) {
4234 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
4236 g_assert_not_reached ();
4240 CASE_PPC64 (OP_LDIV) {
4241 guint8 *divisor_is_m1;
4242 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
4244 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
4245 divisor_is_m1 = code;
4246 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
4247 ppc_lis (code, ppc_r0, 0x8000);
4248 #ifdef __mono_ppc64__
4249 if (ins->opcode == OP_LDIV)
4250 ppc_sldi (code, ppc_r0, ppc_r0, 32);
4252 ppc_compare (code, 0, ins->sreg1, ppc_r0);
4253 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4254 ppc_patch (divisor_is_m1, code);
4255 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
4257 if (ins->opcode == OP_IDIV)
4258 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
4259 #ifdef __mono_ppc64__
4261 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
4263 ppc_mfspr (code, ppc_r0, ppc_xer);
4264 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4265 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
4269 CASE_PPC64 (OP_LDIV_UN)
4270 if (ins->opcode == OP_IDIV_UN)
4271 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
4272 #ifdef __mono_ppc64__
4274 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
4276 ppc_mfspr (code, ppc_r0, ppc_xer);
4277 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4278 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
4284 g_assert_not_reached ();
4287 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
4291 CASE_PPC64 (OP_LOR_IMM)
4292 if (!(ins->inst_imm & 0xffff0000)) {
4293 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
4294 } else if (!(ins->inst_imm & 0xffff)) {
4295 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
4297 g_assert_not_reached ();
4301 CASE_PPC64 (OP_LXOR)
4302 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
4306 CASE_PPC64 (OP_LXOR_IMM)
4307 if (!(ins->inst_imm & 0xffff0000)) {
4308 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
4309 } else if (!(ins->inst_imm & 0xffff)) {
4310 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
4312 g_assert_not_reached ();
4316 CASE_PPC64 (OP_LSHL)
4317 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
4321 CASE_PPC64 (OP_LSHL_IMM)
4322 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
4325 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
4328 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
4331 if (MASK_SHIFT_IMM (ins->inst_imm))
4332 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
4334 ppc_mr (code, ins->dreg, ins->sreg1);
4337 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
4340 CASE_PPC64 (OP_LNOT)
4341 ppc_not (code, ins->dreg, ins->sreg1);
4344 CASE_PPC64 (OP_LNEG)
4345 ppc_neg (code, ins->dreg, ins->sreg1);
4348 CASE_PPC64 (OP_LMUL)
4349 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
4353 CASE_PPC64 (OP_LMUL_IMM)
4354 if (ppc_is_imm16 (ins->inst_imm)) {
4355 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
4357 g_assert_not_reached ();
4361 CASE_PPC64 (OP_LMUL_OVF)
4362 /* we annot use mcrxr, since it's not implemented on some processors
4363 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
4365 if (ins->opcode == OP_IMUL_OVF)
4366 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
4367 #ifdef __mono_ppc64__
4369 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
4371 ppc_mfspr (code, ppc_r0, ppc_xer);
4372 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
4373 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4375 case OP_IMUL_OVF_UN:
4376 CASE_PPC64 (OP_LMUL_OVF_UN)
4377 /* we first multiply to get the high word and compare to 0
4378 * to set the flags, then the result is discarded and then
4379 * we multiply to get the lower * bits result
4381 if (ins->opcode == OP_IMUL_OVF_UN)
4382 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
4383 #ifdef __mono_ppc64__
4385 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
4387 ppc_cmpi (code, 0, 0, ppc_r0, 0);
4388 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
4389 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
4392 ppc_load (code, ins->dreg, ins->inst_c0);
4395 ppc_load (code, ins->dreg, ins->inst_l);
4398 case OP_LOAD_GOTADDR:
4399 /* The PLT implementation depends on this */
4400 g_assert (ins->dreg == ppc_r30);
4402 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
4405 // FIXME: Fix max instruction length
4406 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
4407 /* arch_emit_got_access () patches this */
4408 ppc_load32 (code, ppc_r0, 0);
4409 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
4412 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4413 ppc_load_sequence (code, ins->dreg, 0);
4415 CASE_PPC32 (OP_ICONV_TO_I4)
4416 CASE_PPC32 (OP_ICONV_TO_U4)
4418 ppc_mr (code, ins->dreg, ins->sreg1);
4421 int saved = ins->sreg1;
4422 if (ins->sreg1 == ppc_r3) {
4423 ppc_mr (code, ppc_r0, ins->sreg1);
4426 if (ins->sreg2 != ppc_r3)
4427 ppc_mr (code, ppc_r3, ins->sreg2);
4428 if (saved != ppc_r4)
4429 ppc_mr (code, ppc_r4, saved);
4433 ppc_fmr (code, ins->dreg, ins->sreg1);
4435 case OP_FCONV_TO_R4:
4436 ppc_frsp (code, ins->dreg, ins->sreg1);
4440 MonoCallInst *call = (MonoCallInst*)ins;
4443 * Keep in sync with mono_arch_emit_epilog
4445 g_assert (!cfg->method->save_lmf);
4447 * Note: we can use ppc_r12 here because it is dead anyway:
4448 * we're leaving the method.
4450 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4451 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
4452 if (ppc_is_imm16 (ret_offset)) {
4453 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
4455 ppc_load (code, ppc_r12, ret_offset);
4456 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
4458 ppc_mtlr (code, ppc_r0);
4461 if (ppc_is_imm16 (cfg->stack_usage)) {
4462 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
4464 /* cfg->stack_usage is an int, so we can use
4465 * an addis/addi sequence here even in 64-bit. */
4466 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
4467 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
4469 if (!cfg->method->save_lmf) {
4471 for (i = 31; i >= 13; --i) {
4472 if (cfg->used_int_regs & (1 << i)) {
4473 pos += sizeof (gpointer);
4474 ppc_ldptr (code, i, -pos, ppc_r12);
4478 /* FIXME restore from MonoLMF: though this can't happen yet */
4481 /* Copy arguments on the stack to our argument area */
4482 if (call->stack_usage) {
4483 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
4484 /* r12 was clobbered */
4485 g_assert (cfg->frame_reg == ppc_sp);
4486 if (ppc_is_imm16 (cfg->stack_usage)) {
4487 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
4489 /* cfg->stack_usage is an int, so we can use
4490 * an addis/addi sequence here even in 64-bit. */
4491 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
4492 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
4496 ppc_mr (code, ppc_sp, ppc_r12);
4497 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
4498 if (cfg->compile_aot) {
4499 /* arch_emit_got_access () patches this */
4500 ppc_load32 (code, ppc_r0, 0);
4501 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4502 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
4503 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
4505 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
4507 ppc_mtctr (code, ppc_r0);
4508 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4515 /* ensure ins->sreg1 is not NULL */
4516 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4519 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
4520 if (ppc_is_imm16 (cookie_offset)) {
4521 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
4523 ppc_load (code, ppc_r0, cookie_offset);
4524 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
4526 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
4535 call = (MonoCallInst*)ins;
4536 if (ins->flags & MONO_INST_HAS_METHOD)
4537 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4539 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4540 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4541 ppc_load_func (code, PPC_CALL_REG, 0);
4542 ppc_mtlr (code, PPC_CALL_REG);
4547 /* FIXME: this should be handled somewhere else in the new jit */
4548 code = emit_move_return_value (cfg, ins, code);
4554 case OP_VOIDCALL_REG:
4556 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4557 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4558 /* FIXME: if we know that this is a method, we
4559 can omit this load */
4560 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4561 ppc_mtlr (code, ppc_r0);
4563 #if (_CALL_ELF == 2)
4564 if (ins->flags & MONO_INST_HAS_METHOD) {
4565 // Not a global entry point
4567 // Need to set up r12 with function entry address for global entry point
4568 if (ppc_r12 != ins->sreg1) {
4569 ppc_mr(code,ppc_r12,ins->sreg1);
4573 ppc_mtlr (code, ins->sreg1);
4576 /* FIXME: this should be handled somewhere else in the new jit */
4577 code = emit_move_return_value (cfg, ins, code);
4579 case OP_FCALL_MEMBASE:
4580 case OP_LCALL_MEMBASE:
4581 case OP_VCALL_MEMBASE:
4582 case OP_VCALL2_MEMBASE:
4583 case OP_VOIDCALL_MEMBASE:
4584 case OP_CALL_MEMBASE:
4585 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
4586 /* The trampolines clobber this */
4587 ppc_mr (code, ppc_r29, ins->sreg1);
4588 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4590 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4592 ppc_mtlr (code, ppc_r0);
4594 /* FIXME: this should be handled somewhere else in the new jit */
4595 code = emit_move_return_value (cfg, ins, code);
4598 guint8 * zero_loop_jump, * zero_loop_start;
4599 /* keep alignment */
4600 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4601 int area_offset = alloca_waste;
4603 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4604 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4605 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4606 /* use ctr to store the number of words to 0 if needed */
4607 if (ins->flags & MONO_INST_INIT) {
4608 /* we zero 4 bytes at a time:
4609 * we add 7 instead of 3 so that we set the counter to
4610 * at least 1, otherwise the bdnz instruction will make
4611 * it negative and iterate billions of times.
4613 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4614 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4615 ppc_mtctr (code, ppc_r0);
4617 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4618 ppc_neg (code, ppc_r12, ppc_r12);
4619 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4621 /* FIXME: make this loop work in 8 byte
4622 increments on PPC64 */
4623 if (ins->flags & MONO_INST_INIT) {
4624 /* adjust the dest reg by -4 so we can use stwu */
4625 /* we actually adjust -8 because we let the loop
4628 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4629 ppc_li (code, ppc_r12, 0);
4630 zero_loop_start = code;
4631 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4632 zero_loop_jump = code;
4633 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4634 ppc_patch (zero_loop_jump, zero_loop_start);
4636 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4641 ppc_mr (code, ppc_r3, ins->sreg1);
4642 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4643 (gpointer)"mono_arch_throw_exception");
4644 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4645 ppc_load_func (code, PPC_CALL_REG, 0);
4646 ppc_mtlr (code, PPC_CALL_REG);
4655 ppc_mr (code, ppc_r3, ins->sreg1);
4656 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4657 (gpointer)"mono_arch_rethrow_exception");
4658 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4659 ppc_load_func (code, PPC_CALL_REG, 0);
4660 ppc_mtlr (code, PPC_CALL_REG);
4667 case OP_START_HANDLER: {
4668 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4669 g_assert (spvar->inst_basereg != ppc_sp);
4670 code = emit_reserve_param_area (cfg, code);
4671 ppc_mflr (code, ppc_r0);
4672 if (ppc_is_imm16 (spvar->inst_offset)) {
4673 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4675 ppc_load (code, ppc_r12, spvar->inst_offset);
4676 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4680 case OP_ENDFILTER: {
4681 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4682 g_assert (spvar->inst_basereg != ppc_sp);
4683 code = emit_unreserve_param_area (cfg, code);
4684 if (ins->sreg1 != ppc_r3)
4685 ppc_mr (code, ppc_r3, ins->sreg1);
4686 if (ppc_is_imm16 (spvar->inst_offset)) {
4687 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4689 ppc_load (code, ppc_r12, spvar->inst_offset);
4690 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4692 ppc_mtlr (code, ppc_r0);
4696 case OP_ENDFINALLY: {
4697 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4698 g_assert (spvar->inst_basereg != ppc_sp);
4699 code = emit_unreserve_param_area (cfg, code);
4700 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4701 ppc_mtlr (code, ppc_r0);
4705 case OP_CALL_HANDLER:
4706 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4708 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4711 ins->inst_c0 = code - cfg->native_code;
4714 /*if (ins->inst_target_bb->native_offset) {
4716 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4718 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4723 ppc_mtctr (code, ins->sreg1);
4724 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4728 CASE_PPC64 (OP_LCEQ)
4729 ppc_li (code, ins->dreg, 0);
4730 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4731 ppc_li (code, ins->dreg, 1);
4737 CASE_PPC64 (OP_LCLT)
4738 CASE_PPC64 (OP_LCLT_UN)
4739 ppc_li (code, ins->dreg, 1);
4740 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4741 ppc_li (code, ins->dreg, 0);
4747 CASE_PPC64 (OP_LCGT)
4748 CASE_PPC64 (OP_LCGT_UN)
4749 ppc_li (code, ins->dreg, 1);
4750 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4751 ppc_li (code, ins->dreg, 0);
4753 case OP_COND_EXC_EQ:
4754 case OP_COND_EXC_NE_UN:
4755 case OP_COND_EXC_LT:
4756 case OP_COND_EXC_LT_UN:
4757 case OP_COND_EXC_GT:
4758 case OP_COND_EXC_GT_UN:
4759 case OP_COND_EXC_GE:
4760 case OP_COND_EXC_GE_UN:
4761 case OP_COND_EXC_LE:
4762 case OP_COND_EXC_LE_UN:
4763 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4765 case OP_COND_EXC_IEQ:
4766 case OP_COND_EXC_INE_UN:
4767 case OP_COND_EXC_ILT:
4768 case OP_COND_EXC_ILT_UN:
4769 case OP_COND_EXC_IGT:
4770 case OP_COND_EXC_IGT_UN:
4771 case OP_COND_EXC_IGE:
4772 case OP_COND_EXC_IGE_UN:
4773 case OP_COND_EXC_ILE:
4774 case OP_COND_EXC_ILE_UN:
4775 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4787 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4790 /* floating point opcodes */
4792 g_assert (cfg->compile_aot);
4794 /* FIXME: Optimize this */
4796 ppc_mflr (code, ppc_r12);
4798 *(double*)code = *(double*)ins->inst_p0;
4800 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4803 g_assert_not_reached ();
4805 case OP_STORER8_MEMBASE_REG:
4806 if (ppc_is_imm16 (ins->inst_offset)) {
4807 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4809 if (ppc_is_imm32 (ins->inst_offset)) {
4810 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4811 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4813 ppc_load (code, ppc_r0, ins->inst_offset);
4814 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4818 case OP_LOADR8_MEMBASE:
4819 if (ppc_is_imm16 (ins->inst_offset)) {
4820 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4822 if (ppc_is_imm32 (ins->inst_offset)) {
4823 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4824 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4826 ppc_load (code, ppc_r0, ins->inst_offset);
4827 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4831 case OP_STORER4_MEMBASE_REG:
4832 ppc_frsp (code, ins->sreg1, ins->sreg1);
4833 if (ppc_is_imm16 (ins->inst_offset)) {
4834 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4836 if (ppc_is_imm32 (ins->inst_offset)) {
4837 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4838 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4840 ppc_load (code, ppc_r0, ins->inst_offset);
4841 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4845 case OP_LOADR4_MEMBASE:
4846 if (ppc_is_imm16 (ins->inst_offset)) {
4847 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4849 if (ppc_is_imm32 (ins->inst_offset)) {
4850 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4851 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4853 ppc_load (code, ppc_r0, ins->inst_offset);
4854 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4858 case OP_LOADR4_MEMINDEX:
4859 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4861 case OP_LOADR8_MEMINDEX:
4862 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4864 case OP_STORER4_MEMINDEX:
4865 ppc_frsp (code, ins->sreg1, ins->sreg1);
4866 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4868 case OP_STORER8_MEMINDEX:
4869 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4872 case CEE_CONV_R4: /* FIXME: change precision */
4874 g_assert_not_reached ();
4875 case OP_FCONV_TO_I1:
4876 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4878 case OP_FCONV_TO_U1:
4879 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4881 case OP_FCONV_TO_I2:
4882 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4884 case OP_FCONV_TO_U2:
4885 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4887 case OP_FCONV_TO_I4:
4889 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4891 case OP_FCONV_TO_U4:
4893 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4895 case OP_LCONV_TO_R_UN:
4896 g_assert_not_reached ();
4897 /* Implemented as helper calls */
4899 case OP_LCONV_TO_OVF_I4_2:
4900 case OP_LCONV_TO_OVF_I: {
4901 #ifdef __mono_ppc64__
4904 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4905 // Check if its negative
4906 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4907 negative_branch = code;
4908 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4909 // Its positive msword == 0
4910 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4911 msword_positive_branch = code;
4912 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4914 ovf_ex_target = code;
4915 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4917 ppc_patch (negative_branch, code);
4918 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4919 msword_negative_branch = code;
4920 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4921 ppc_patch (msword_negative_branch, ovf_ex_target);
4923 ppc_patch (msword_positive_branch, code);
4924 if (ins->dreg != ins->sreg1)
4925 ppc_mr (code, ins->dreg, ins->sreg1);
4930 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4933 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4936 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4939 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4942 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4945 ppc_fneg (code, ins->dreg, ins->sreg1);
4949 g_assert_not_reached ();
4952 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4955 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4956 ppc_li (code, ins->dreg, 0);
4957 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4958 ppc_li (code, ins->dreg, 1);
4961 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4962 ppc_li (code, ins->dreg, 1);
4963 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4964 ppc_li (code, ins->dreg, 0);
4967 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4968 ppc_li (code, ins->dreg, 1);
4969 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4970 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4971 ppc_li (code, ins->dreg, 0);
4974 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4975 ppc_li (code, ins->dreg, 1);
4976 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4977 ppc_li (code, ins->dreg, 0);
4980 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4981 ppc_li (code, ins->dreg, 1);
4982 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4983 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4984 ppc_li (code, ins->dreg, 0);
4987 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4990 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4993 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4994 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4997 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4998 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
5001 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
5002 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
5005 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
5006 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
5009 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
5010 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
5013 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
5016 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
5017 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
5020 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
5023 g_assert_not_reached ();
5024 case OP_CHECK_FINITE: {
5025 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
5026 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
5027 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
5028 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
5031 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
5032 #ifdef __mono_ppc64__
5033 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
5035 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
5040 #ifdef __mono_ppc64__
5041 case OP_ICONV_TO_I4:
5043 ppc_extsw (code, ins->dreg, ins->sreg1);
5045 case OP_ICONV_TO_U4:
5047 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
5049 case OP_ICONV_TO_R4:
5050 case OP_ICONV_TO_R8:
5051 case OP_LCONV_TO_R4:
5052 case OP_LCONV_TO_R8: {
5054 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
5055 ppc_extsw (code, ppc_r0, ins->sreg1);
5060 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
5061 ppc_mffgpr (code, ins->dreg, tmp);
5063 ppc_str (code, tmp, -8, ppc_r1);
5064 ppc_lfd (code, ins->dreg, -8, ppc_r1);
5066 ppc_fcfid (code, ins->dreg, ins->dreg);
5067 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
5068 ppc_frsp (code, ins->dreg, ins->dreg);
5072 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
5075 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
5078 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
5080 ppc_mfspr (code, ppc_r0, ppc_xer);
5081 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
5082 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
5084 case OP_COND_EXC_OV:
5085 ppc_mfspr (code, ppc_r0, ppc_xer);
5086 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
5087 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
5099 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
5101 case OP_FCONV_TO_I8:
5102 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
5104 case OP_FCONV_TO_U8:
5105 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
5107 case OP_STOREI4_MEMBASE_REG:
5108 if (ppc_is_imm16 (ins->inst_offset)) {
5109 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
5111 ppc_load (code, ppc_r0, ins->inst_offset);
5112 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
5115 case OP_STOREI4_MEMINDEX:
5116 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
5119 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
5121 case OP_ISHR_UN_IMM:
5122 if (ins->inst_imm & 0x1f)
5123 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
5125 ppc_mr (code, ins->dreg, ins->sreg1);
5127 case OP_ATOMIC_ADD_I4:
5128 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
5129 int location = ins->inst_basereg;
5130 int addend = ins->sreg2;
5131 guint8 *loop, *branch;
5132 g_assert (ins->inst_offset == 0);
5136 if (ins->opcode == OP_ATOMIC_ADD_I4)
5137 ppc_lwarx (code, ppc_r0, 0, location);
5138 #ifdef __mono_ppc64__
5140 ppc_ldarx (code, ppc_r0, 0, location);
5143 ppc_add (code, ppc_r0, ppc_r0, addend);
5145 if (ins->opcode == OP_ATOMIC_ADD_I4)
5146 ppc_stwcxd (code, ppc_r0, 0, location);
5147 #ifdef __mono_ppc64__
5149 ppc_stdcxd (code, ppc_r0, 0, location);
5153 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5154 ppc_patch (branch, loop);
5157 ppc_mr (code, ins->dreg, ppc_r0);
5161 case OP_ICONV_TO_R4:
5162 case OP_ICONV_TO_R8: {
5163 if (cpu_hw_caps & PPC_ISA_64) {
5164 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
5165 ppc_stw (code, ppc_r0, -8, ppc_r1);
5166 ppc_stw (code, ins->sreg1, -4, ppc_r1);
5167 ppc_lfd (code, ins->dreg, -8, ppc_r1);
5168 ppc_fcfid (code, ins->dreg, ins->dreg);
5169 if (ins->opcode == OP_ICONV_TO_R4)
5170 ppc_frsp (code, ins->dreg, ins->dreg);
5175 case OP_ATOMIC_CAS_I4:
5176 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
5177 int location = ins->sreg1;
5178 int value = ins->sreg2;
5179 int comparand = ins->sreg3;
5180 guint8 *start, *not_equal, *lost_reservation;
5184 if (ins->opcode == OP_ATOMIC_CAS_I4)
5185 ppc_lwarx (code, ppc_r0, 0, location);
5186 #ifdef __mono_ppc64__
5188 ppc_ldarx (code, ppc_r0, 0, location);
5191 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
5193 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5195 if (ins->opcode == OP_ATOMIC_CAS_I4)
5196 ppc_stwcxd (code, value, 0, location);
5197 #ifdef __mono_ppc64__
5199 ppc_stdcxd (code, value, 0, location);
5202 lost_reservation = code;
5203 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5204 ppc_patch (lost_reservation, start);
5205 ppc_patch (not_equal, code);
5208 ppc_mr (code, ins->dreg, ppc_r0);
5213 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
5214 g_assert_not_reached ();
5217 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
5218 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
5219 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
5220 g_assert_not_reached ();
5226 last_offset = offset;
5229 cfg->code_len = code - cfg->native_code;
5231 #endif /* !DISABLE_JIT */
5234 mono_arch_register_lowlevel_calls (void)
5236 /* The signature doesn't matter */
5237 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
5240 #ifdef __mono_ppc64__
5241 #ifdef _LITTLE_ENDIAN
5242 #define patch_load_sequence(ip,val) do {\
5243 guint16 *__load = (guint16*)(ip); \
5244 g_assert (sizeof (val) == sizeof (gsize)); \
5245 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
5246 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
5247 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
5248 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
5250 #elif defined _BIG_ENDIAN
5251 #define patch_load_sequence(ip,val) do {\
5252 guint16 *__load = (guint16*)(ip); \
5253 g_assert (sizeof (val) == sizeof (gsize)); \
5254 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
5255 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
5256 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
5257 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
5260 #error huh? No endianess defined by compiler
5263 #define patch_load_sequence(ip,val) do {\
5264 guint16 *__lis_ori = (guint16*)(ip); \
5265 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
5266 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
5272 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
5274 MonoJumpInfo *patch_info;
5275 gboolean compile_aot = !run_cctors;
5277 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5278 unsigned char *ip = patch_info->ip.i + code;
5279 unsigned char *target;
5280 gboolean is_fd = FALSE;
5282 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
5285 switch (patch_info->type) {
5286 case MONO_PATCH_INFO_BB:
5287 case MONO_PATCH_INFO_LABEL:
5290 /* No need to patch these */
5295 switch (patch_info->type) {
5296 case MONO_PATCH_INFO_IP:
5297 patch_load_sequence (ip, ip);
5299 case MONO_PATCH_INFO_METHOD_REL:
5300 g_assert_not_reached ();
5301 *((gpointer *)(ip)) = code + patch_info->data.offset;
5303 case MONO_PATCH_INFO_SWITCH: {
5304 gpointer *table = (gpointer *)patch_info->data.table->table;
5307 patch_load_sequence (ip, table);
5309 for (i = 0; i < patch_info->data.table->table_size; i++) {
5310 table [i] = (glong)patch_info->data.table->table [i] + code;
5312 /* we put into the table the absolute address, no need for ppc_patch in this case */
5315 case MONO_PATCH_INFO_METHODCONST:
5316 case MONO_PATCH_INFO_CLASS:
5317 case MONO_PATCH_INFO_IMAGE:
5318 case MONO_PATCH_INFO_FIELD:
5319 case MONO_PATCH_INFO_VTABLE:
5320 case MONO_PATCH_INFO_IID:
5321 case MONO_PATCH_INFO_SFLDA:
5322 case MONO_PATCH_INFO_LDSTR:
5323 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5324 case MONO_PATCH_INFO_LDTOKEN:
5325 /* from OP_AOTCONST : lis + ori */
5326 patch_load_sequence (ip, target);
5328 case MONO_PATCH_INFO_R4:
5329 case MONO_PATCH_INFO_R8:
5330 g_assert_not_reached ();
5331 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
5333 case MONO_PATCH_INFO_EXC_NAME:
5334 g_assert_not_reached ();
5335 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
5337 case MONO_PATCH_INFO_NONE:
5338 case MONO_PATCH_INFO_BB_OVF:
5339 case MONO_PATCH_INFO_EXC_OVF:
5340 /* everything is dealt with at epilog output time */
5342 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
5343 case MONO_PATCH_INFO_INTERNAL_METHOD:
5344 case MONO_PATCH_INFO_ABS:
5345 case MONO_PATCH_INFO_CLASS_INIT:
5346 case MONO_PATCH_INFO_RGCTX_FETCH:
5347 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5354 ppc_patch_full (ip, target, is_fd);
5359 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
5360 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
5361 * the instruction offset immediate for all the registers.
5364 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
5368 for (i = 13; i <= 31; i++) {
5369 if (used_int_regs & (1 << i)) {
5370 ppc_str (code, i, pos, base_reg);
5371 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5372 pos += sizeof (mgreg_t);
5376 /* pos is the start of the MonoLMF structure */
5377 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
5378 for (i = 13; i <= 31; i++) {
5379 ppc_str (code, i, offset, base_reg);
5380 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
5381 offset += sizeof (mgreg_t);
5383 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
5384 for (i = 14; i < 32; i++) {
5385 ppc_stfd (code, i, offset, base_reg);
5386 offset += sizeof (gdouble);
5393 * Stack frame layout:
5395 * ------------------- sp
5396 * MonoLMF structure or saved registers
5397 * -------------------
5399 * -------------------
5401 * -------------------
5402 * optional 8 bytes for tracing
5403 * -------------------
5404 * param area size is cfg->param_area
5405 * -------------------
5406 * linkage area size is PPC_STACK_PARAM_OFFSET
5407 * ------------------- sp
5411 mono_arch_emit_prolog (MonoCompile *cfg)
5413 MonoMethod *method = cfg->method;
5415 MonoMethodSignature *sig;
5417 long alloc_size, pos, max_offset, cfa_offset;
5423 int tailcall_struct_index;
5425 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5428 sig = mono_method_signature (method);
5429 cfg->code_size = 512 + sig->param_count * 32;
5430 code = cfg->native_code = g_malloc (cfg->code_size);
5434 /* We currently emit unwind info for aot, but don't use it */
5435 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
5437 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5438 ppc_mflr (code, ppc_r0);
5439 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
5440 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
5443 alloc_size = cfg->stack_offset;
5446 if (!method->save_lmf) {
5447 for (i = 31; i >= 13; --i) {
5448 if (cfg->used_int_regs & (1 << i)) {
5449 pos += sizeof (mgreg_t);
5453 pos += sizeof (MonoLMF);
5457 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
5458 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
5459 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
5460 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
5463 cfg->stack_usage = alloc_size;
5464 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
5466 if (ppc_is_imm16 (-alloc_size)) {
5467 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
5468 cfa_offset = alloc_size;
5469 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
5470 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
5473 ppc_addi (code, ppc_r12, ppc_sp, -pos);
5474 ppc_load (code, ppc_r0, -alloc_size);
5475 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
5476 cfa_offset = alloc_size;
5477 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
5478 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
5481 if (cfg->frame_reg != ppc_sp) {
5482 ppc_mr (code, cfg->frame_reg, ppc_sp);
5483 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
5486 /* store runtime generic context */
5487 if (cfg->rgctx_var) {
5488 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
5489 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
5491 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
5494 /* compute max_offset in order to use short forward jumps
5495 * we always do it on ppc because the immediate displacement
5496 * for jumps is too small
5499 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5501 bb->max_offset = max_offset;
5503 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
5506 MONO_BB_FOR_EACH_INS (bb, ins)
5507 max_offset += ins_native_length (cfg, ins);
5510 /* load arguments allocated to register from the stack */
5513 cinfo = get_call_info (cfg->generic_sharing_context, sig);
5515 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5516 // The return value for a structure may either be returned via address or via registers depending on its size
5517 MonoClass *klass = mono_class_from_mono_type (sig->ret);
5518 gboolean is_all_floats = is_float_struct_returnable_via_regs(klass);
5519 gboolean is_returnable_via_regs = is_struct_returnable_via_regs(klass, sig->pinvoke);
5521 DEBUG_ELFABIV2_printf("mono_arch_emit_prolog for struct "); DEBUG_ELFABIV2_mono_print_klass(klass);
5522 if (!is_all_floats && !is_returnable_via_regs) {
5523 ArgInfo *ainfo = &cinfo->ret;
5525 inst = cfg->vret_addr;
5528 if (ppc_is_imm16 (inst->inst_offset)) {
5529 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5531 ppc_load (code, ppc_r12, inst->inst_offset);
5532 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5535 DEBUG_ELFABIV2_printf("mono_arch_emit_prolog extra parm for return value\n");
5538 DEBUG_ELFABIV2_printf("mono_arch_emit_prolog NO extra parm for return value\n");
5542 tailcall_struct_index = 0;
5543 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5544 ArgInfo *ainfo = cinfo->args + i;
5545 inst = cfg->args [pos];
5547 if (cfg->verbose_level > 2)
5548 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5549 if (inst->opcode == OP_REGVAR) {
5550 if (ainfo->regtype == RegTypeGeneral)
5551 ppc_mr (code, inst->dreg, ainfo->reg);
5552 else if (ainfo->regtype == RegTypeFP)
5553 ppc_fmr (code, inst->dreg, ainfo->reg);
5554 else if (ainfo->regtype == RegTypeBase) {
5555 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5556 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5558 g_assert_not_reached ();
5560 if (cfg->verbose_level > 2)
5561 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5563 /* the argument should be put on the stack: FIXME handle size != word */
5564 if (ainfo->regtype == RegTypeGeneral) {
5565 switch (ainfo->size) {
5567 if (ppc_is_imm16 (inst->inst_offset)) {
5568 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5570 if (ppc_is_imm32 (inst->inst_offset)) {
5571 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5572 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5574 ppc_load (code, ppc_r12, inst->inst_offset);
5575 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5580 if (ppc_is_imm16 (inst->inst_offset)) {
5581 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5583 if (ppc_is_imm32 (inst->inst_offset)) {
5584 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5585 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5587 ppc_load (code, ppc_r12, inst->inst_offset);
5588 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5592 #ifdef __mono_ppc64__
5594 if (ppc_is_imm16 (inst->inst_offset)) {
5595 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5597 if (ppc_is_imm32 (inst->inst_offset)) {
5598 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5599 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5601 ppc_load (code, ppc_r12, inst->inst_offset);
5602 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5607 if (ppc_is_imm16 (inst->inst_offset)) {
5608 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5610 ppc_load (code, ppc_r12, inst->inst_offset);
5611 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5616 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5617 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5618 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5620 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5621 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5622 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5623 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5628 if (ppc_is_imm16 (inst->inst_offset)) {
5629 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5631 if (ppc_is_imm32 (inst->inst_offset)) {
5632 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5633 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5635 ppc_load (code, ppc_r12, inst->inst_offset);
5636 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5641 } else if (ainfo->regtype == RegTypeBase) {
5642 g_assert (ppc_is_imm16 (ainfo->offset));
5643 /* load the previous stack pointer in r12 */
5644 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5645 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5646 switch (ainfo->size) {
5648 if (ppc_is_imm16 (inst->inst_offset)) {
5649 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5651 if (ppc_is_imm32 (inst->inst_offset)) {
5652 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5653 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5655 ppc_load (code, ppc_r12, inst->inst_offset);
5656 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5661 if (ppc_is_imm16 (inst->inst_offset)) {
5662 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5664 if (ppc_is_imm32 (inst->inst_offset)) {
5665 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5666 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5668 ppc_load (code, ppc_r12, inst->inst_offset);
5669 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5673 #ifdef __mono_ppc64__
5675 if (ppc_is_imm16 (inst->inst_offset)) {
5676 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5678 if (ppc_is_imm32 (inst->inst_offset)) {
5679 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5680 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5682 ppc_load (code, ppc_r12, inst->inst_offset);
5683 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5688 if (ppc_is_imm16 (inst->inst_offset)) {
5689 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5691 ppc_load (code, ppc_r12, inst->inst_offset);
5692 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5697 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5698 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5699 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5700 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5701 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5703 /* use r11 to load the 2nd half of the long before we clobber r12. */
5704 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5705 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5706 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5707 ppc_stw (code, ppc_r0, 0, ppc_r12);
5708 ppc_stw (code, ppc_r11, 4, ppc_r12);
5713 if (ppc_is_imm16 (inst->inst_offset)) {
5714 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5716 if (ppc_is_imm32 (inst->inst_offset)) {
5717 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5718 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5720 ppc_load (code, ppc_r12, inst->inst_offset);
5721 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5726 } else if (ainfo->regtype == RegTypeFP) {
5727 g_assert (ppc_is_imm16 (inst->inst_offset));
5728 if (ainfo->size == 8)
5729 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5730 else if (ainfo->size == 4)
5731 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5733 g_assert_not_reached ();
5734 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5735 int doffset = inst->inst_offset;
5739 g_assert (ppc_is_imm16 (inst->inst_offset));
5740 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5741 /* FIXME: what if there is no class? */
5742 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5743 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5744 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5745 if (ainfo->size == 4) {
5746 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5748 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5750 soffset += ainfo->size;
5751 doffset += ainfo->size;
5753 } else if (ainfo->regtype == RegTypeStructByVal) {
5754 int doffset = inst->inst_offset;
5758 g_assert (ppc_is_imm16 (inst->inst_offset));
5759 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5760 /* FIXME: what if there is no class? */
5761 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5762 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5763 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5766 * Darwin handles 1 and 2 byte
5767 * structs specially by
5768 * loading h/b into the arg
5769 * register. Only done for
5773 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5775 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5779 #ifdef __mono_ppc64__
5781 g_assert (cur_reg == 0);
5782 if (mono_class_native_size (inst->klass, NULL) == 1) {
5783 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5784 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5785 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5786 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // FIXME -- maybe <=4?
5787 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5789 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // FIXME -- Better way?
5794 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5795 inst->inst_basereg);
5798 soffset += sizeof (gpointer);
5799 doffset += sizeof (gpointer);
5801 if (ainfo->vtsize) {
5802 /* FIXME: we need to do the shifting here, too */
5805 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5806 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5807 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5808 code = emit_memcpy (code, size - soffset,
5809 inst->inst_basereg, doffset,
5810 ppc_r12, ainfo->offset + soffset);
5812 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5813 inst->inst_basereg, doffset,
5814 ppc_r12, ainfo->offset + soffset);
5817 } else if (ainfo->regtype == RegTypeStructByAddr) {
5818 /* if it was originally a RegTypeBase */
5819 if (ainfo->offset) {
5820 /* load the previous stack pointer in r12 */
5821 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5822 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5824 ppc_mr (code, ppc_r12, ainfo->reg);
5827 if (cfg->tailcall_valuetype_addrs) {
5828 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5830 g_assert (ppc_is_imm16 (addr->inst_offset));
5831 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5833 tailcall_struct_index++;
5836 g_assert (ppc_is_imm16 (inst->inst_offset));
5837 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5838 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5840 g_assert_not_reached ();
5845 if (method->save_lmf) {
5846 if (lmf_pthread_key != -1) {
5847 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5848 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5849 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5851 if (cfg->compile_aot) {
5852 /* Compute the got address which is needed by the PLT entry */
5853 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5855 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5856 (gpointer)"mono_get_lmf_addr");
5857 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5858 ppc_load_func (code, PPC_CALL_REG, 0);
5859 ppc_mtlr (code, PPC_CALL_REG);
5865 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5866 /* lmf_offset is the offset from the previous stack pointer,
5867 * alloc_size is the total stack space allocated, so the offset
5868 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5869 * The pointer to the struct is put in ppc_r12 (new_lmf).
5870 * The callee-saved registers are already in the MonoLMF structure
5872 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5873 /* ppc_r3 is the result from mono_get_lmf_addr () */
5874 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5875 /* new_lmf->previous_lmf = *lmf_addr */
5876 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5877 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5878 /* *(lmf_addr) = r12 */
5879 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5880 /* save method info */
5881 if (cfg->compile_aot)
5883 ppc_load (code, ppc_r0, 0);
5885 ppc_load_ptr (code, ppc_r0, method);
5886 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5887 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5888 /* save the current IP */
5889 if (cfg->compile_aot) {
5891 ppc_mflr (code, ppc_r0);
5893 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5894 #ifdef __mono_ppc64__
5895 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5897 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5900 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5904 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5906 cfg->code_len = code - cfg->native_code;
5907 g_assert (cfg->code_len <= cfg->code_size);
5914 mono_arch_emit_epilog (MonoCompile *cfg)
5916 MonoMethod *method = cfg->method;
5918 int max_epilog_size = 16 + 20*4;
5921 if (cfg->method->save_lmf)
5922 max_epilog_size += 128;
5924 if (mono_jit_trace_calls != NULL)
5925 max_epilog_size += 50;
5927 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5928 max_epilog_size += 50;
5930 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5931 cfg->code_size *= 2;
5932 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5933 cfg->stat_code_reallocs++;
5937 * Keep in sync with OP_JMP
5939 code = cfg->native_code + cfg->code_len;
5941 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5942 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5946 if (method->save_lmf) {
5948 pos += sizeof (MonoLMF);
5950 /* save the frame reg in r8 */
5951 ppc_mr (code, ppc_r8, cfg->frame_reg);
5952 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5953 /* r5 = previous_lmf */
5954 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5956 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5957 /* *(lmf_addr) = previous_lmf */
5958 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5959 /* FIXME: speedup: there is no actual need to restore the registers if
5960 * we didn't actually change them (idea from Zoltan).
5963 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5965 /*for (i = 14; i < 32; i++) {
5966 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5968 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5969 /* use the saved copy of the frame reg in r8 */
5970 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5971 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5972 ppc_mtlr (code, ppc_r0);
5974 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5976 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5977 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5978 if (ppc_is_imm16 (return_offset)) {
5979 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5981 ppc_load (code, ppc_r12, return_offset);
5982 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5984 ppc_mtlr (code, ppc_r0);
5986 if (ppc_is_imm16 (cfg->stack_usage)) {
5987 int offset = cfg->stack_usage;
5988 for (i = 13; i <= 31; i++) {
5989 if (cfg->used_int_regs & (1 << i))
5990 offset -= sizeof (mgreg_t);
5992 if (cfg->frame_reg != ppc_sp)
5993 ppc_mr (code, ppc_r12, cfg->frame_reg);
5994 /* note r31 (possibly the frame register) is restored last */
5995 for (i = 13; i <= 31; i++) {
5996 if (cfg->used_int_regs & (1 << i)) {
5997 ppc_ldr (code, i, offset, cfg->frame_reg);
5998 offset += sizeof (mgreg_t);
6001 if (cfg->frame_reg != ppc_sp)
6002 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
6004 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
6006 ppc_load32 (code, ppc_r12, cfg->stack_usage);
6007 if (cfg->used_int_regs) {
6008 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
6009 for (i = 31; i >= 13; --i) {
6010 if (cfg->used_int_regs & (1 << i)) {
6011 pos += sizeof (mgreg_t);
6012 ppc_ldr (code, i, -pos, ppc_r12);
6015 ppc_mr (code, ppc_sp, ppc_r12);
6017 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
6024 cfg->code_len = code - cfg->native_code;
6026 g_assert (cfg->code_len < cfg->code_size);
6029 #endif /* ifndef DISABLE_JIT */
6031 /* remove once throw_exception_by_name is eliminated */
6033 exception_id_by_name (const char *name)
6035 if (strcmp (name, "IndexOutOfRangeException") == 0)
6036 return MONO_EXC_INDEX_OUT_OF_RANGE;
6037 if (strcmp (name, "OverflowException") == 0)
6038 return MONO_EXC_OVERFLOW;
6039 if (strcmp (name, "ArithmeticException") == 0)
6040 return MONO_EXC_ARITHMETIC;
6041 if (strcmp (name, "DivideByZeroException") == 0)
6042 return MONO_EXC_DIVIDE_BY_ZERO;
6043 if (strcmp (name, "InvalidCastException") == 0)
6044 return MONO_EXC_INVALID_CAST;
6045 if (strcmp (name, "NullReferenceException") == 0)
6046 return MONO_EXC_NULL_REF;
6047 if (strcmp (name, "ArrayTypeMismatchException") == 0)
6048 return MONO_EXC_ARRAY_TYPE_MISMATCH;
6049 if (strcmp (name, "ArgumentException") == 0)
6050 return MONO_EXC_ARGUMENT;
6051 g_error ("Unknown intrinsic exception %s\n", name);
6057 mono_arch_emit_exceptions (MonoCompile *cfg)
6059 MonoJumpInfo *patch_info;
6062 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
6063 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
6064 int max_epilog_size = 50;
6066 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
6067 exc_throw_pos [i] = NULL;
6068 exc_throw_found [i] = 0;
6071 /* count the number of exception infos */
6074 * make sure we have enough space for exceptions
6076 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6077 if (patch_info->type == MONO_PATCH_INFO_EXC) {
6078 i = exception_id_by_name (patch_info->data.target);
6079 if (!exc_throw_found [i]) {
6080 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
6081 exc_throw_found [i] = TRUE;
6083 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
6084 max_epilog_size += 12;
6085 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
6086 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
6087 i = exception_id_by_name (ovfj->data.exception);
6088 if (!exc_throw_found [i]) {
6089 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
6090 exc_throw_found [i] = TRUE;
6092 max_epilog_size += 8;
6096 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
6097 cfg->code_size *= 2;
6098 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
6099 cfg->stat_code_reallocs++;
6102 code = cfg->native_code + cfg->code_len;
6104 /* add code to raise exceptions */
6105 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6106 switch (patch_info->type) {
6107 case MONO_PATCH_INFO_BB_OVF: {
6108 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
6109 unsigned char *ip = patch_info->ip.i + cfg->native_code;
6110 /* patch the initial jump */
6111 ppc_patch (ip, code);
6112 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
6114 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
6115 /* jump back to the true target */
6117 ip = ovfj->data.bb->native_offset + cfg->native_code;
6118 ppc_patch (code - 4, ip);
6119 patch_info->type = MONO_PATCH_INFO_NONE;
6122 case MONO_PATCH_INFO_EXC_OVF: {
6123 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
6124 MonoJumpInfo *newji;
6125 unsigned char *ip = patch_info->ip.i + cfg->native_code;
6126 unsigned char *bcl = code;
6127 /* patch the initial jump: we arrived here with a call */
6128 ppc_patch (ip, code);
6129 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
6131 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
6132 /* patch the conditional jump to the right handler */
6133 /* make it processed next */
6134 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
6135 newji->type = MONO_PATCH_INFO_EXC;
6136 newji->ip.i = bcl - cfg->native_code;
6137 newji->data.target = ovfj->data.exception;
6138 newji->next = patch_info->next;
6139 patch_info->next = newji;
6140 patch_info->type = MONO_PATCH_INFO_NONE;
6143 case MONO_PATCH_INFO_EXC: {
6144 MonoClass *exc_class;
6146 unsigned char *ip = patch_info->ip.i + cfg->native_code;
6147 i = exception_id_by_name (patch_info->data.target);
6148 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
6149 ppc_patch (ip, exc_throw_pos [i]);
6150 patch_info->type = MONO_PATCH_INFO_NONE;
6153 exc_throw_pos [i] = code;
6156 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
6157 g_assert (exc_class);
6159 ppc_patch (ip, code);
6160 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
6161 ppc_load (code, ppc_r3, exc_class->type_token);
6162 /* we got here from a conditional call, so the calling ip is set in lr */
6163 ppc_mflr (code, ppc_r4);
6164 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6165 patch_info->data.name = "mono_arch_throw_corlib_exception";
6166 patch_info->ip.i = code - cfg->native_code;
6167 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
6168 ppc_load_func (code, PPC_CALL_REG, 0);
6169 ppc_mtctr (code, PPC_CALL_REG);
6170 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
6182 cfg->code_len = code - cfg->native_code;
6184 g_assert (cfg->code_len <= cfg->code_size);
6190 try_offset_access (void *value, guint32 idx)
6192 register void* me __asm__ ("r2");
6193 void ***p = (void***)((char*)me + 284);
6194 int idx1 = idx / 32;
6195 int idx2 = idx % 32;
6198 if (value != p[idx1][idx2])
6205 setup_tls_access (void)
6207 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
6208 size_t conf_size = 0;
6211 /* FIXME for darwin */
6212 guint32 *ins, *code;
6213 guint32 cmplwi_1023, li_0x48, blr_ins;
6217 tls_mode = TLS_MODE_FAILED;
6220 if (tls_mode == TLS_MODE_FAILED)
6222 if (g_getenv ("MONO_NO_TLS")) {
6223 tls_mode = TLS_MODE_FAILED;
6227 if (tls_mode == TLS_MODE_DETECT) {
6228 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
6229 tls_mode = TLS_MODE_DARWIN_G4;
6230 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
6231 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
6232 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
6233 tls_mode = TLS_MODE_NPTL;
6234 #elif !defined(TARGET_PS3)
6235 ins = (guint32*)pthread_getspecific;
6236 /* uncond branch to the real method */
6237 if ((*ins >> 26) == 18) {
6239 val = (*ins & ~3) << 6;
6243 ins = (guint32*)(long)val;
6245 ins = (guint32*) ((char*)ins + val);
6248 code = &cmplwi_1023;
6249 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
6251 ppc_li (code, ppc_r4, 0x48);
6254 if (*ins == cmplwi_1023) {
6255 int found_lwz_284 = 0;
6257 for (ptk = 0; ptk < 20; ++ptk) {
6259 if (!*ins || *ins == blr_ins)
6261 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
6266 if (!found_lwz_284) {
6267 tls_mode = TLS_MODE_FAILED;
6270 tls_mode = TLS_MODE_LTHREADS;
6271 } else if (*ins == li_0x48) {
6273 /* uncond branch to the real method */
6274 if ((*ins >> 26) == 18) {
6276 val = (*ins & ~3) << 6;
6280 ins = (guint32*)(long)val;
6282 ins = (guint32*) ((char*)ins + val);
6284 code = (guint32*)&val;
6285 ppc_li (code, ppc_r0, 0x7FF2);
6286 if (ins [1] == val) {
6287 /* Darwin on G4, implement */
6288 tls_mode = TLS_MODE_FAILED;
6291 code = (guint32*)&val;
6292 ppc_mfspr (code, ppc_r3, 104);
6293 if (ins [1] != val) {
6294 tls_mode = TLS_MODE_FAILED;
6297 tls_mode = TLS_MODE_DARWIN_G5;
6300 tls_mode = TLS_MODE_FAILED;
6304 tls_mode = TLS_MODE_FAILED;
6310 if (tls_mode == TLS_MODE_DETECT)
6311 tls_mode = TLS_MODE_FAILED;
6312 if (tls_mode == TLS_MODE_FAILED)
6314 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
6315 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
6319 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
6320 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
6321 if (lmf_pthread_key == -1) {
6322 guint32 ptk = mono_jit_tls_id;
6324 /*g_print ("MonoLMF at: %d\n", ptk);*/
6325 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
6326 init_tls_failed = 1;
6329 lmf_pthread_key = ptk;
6338 mono_arch_finish_init (void)
6340 setup_tls_access ();
6344 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
6348 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
6350 #define LOADSTORE_SIZE 4
6351 #define JUMP_IMM_SIZE 12
6352 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
6353 #define ENABLE_WRONG_METHOD_CHECK 0
6356 * LOCKING: called with the domain lock held
6359 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
6360 gpointer fail_tramp)
6364 guint8 *code, *start;
6366 for (i = 0; i < count; ++i) {
6367 MonoIMTCheckItem *item = imt_entries [i];
6368 if (item->is_equals) {
6369 if (item->check_target_idx) {
6370 if (!item->compare_done)
6371 item->chunk_size += CMP_SIZE;
6372 if (item->has_target_code)
6373 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
6375 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
6378 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
6379 if (!item->has_target_code)
6380 item->chunk_size += LOADSTORE_SIZE;
6382 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
6383 #if ENABLE_WRONG_METHOD_CHECK
6384 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
6389 item->chunk_size += CMP_SIZE + BR_SIZE;
6390 imt_entries [item->check_target_idx]->compare_done = TRUE;
6392 size += item->chunk_size;
6394 /* the initial load of the vtable address */
6395 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
6397 code = mono_method_alloc_generic_virtual_thunk (domain, size);
6399 code = mono_domain_code_reserve (domain, size);
6404 * We need to save and restore r12 because it might be
6405 * used by the caller as the vtable register, so
6406 * clobbering it will trip up the magic trampoline.
6408 * FIXME: Get rid of this by making sure that r12 is
6409 * not used as the vtable register in interface calls.
6411 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
6412 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
6414 for (i = 0; i < count; ++i) {
6415 MonoIMTCheckItem *item = imt_entries [i];
6416 item->code_target = code;
6417 if (item->is_equals) {
6418 if (item->check_target_idx) {
6419 if (!item->compare_done) {
6420 ppc_load (code, ppc_r0, (gsize)item->key);
6421 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
6423 item->jmp_code = code;
6424 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
6425 if (item->has_target_code) {
6426 ppc_load_ptr (code, ppc_r0, item->value.target_code);
6428 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
6429 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
6431 ppc_mtctr (code, ppc_r0);
6432 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
6435 ppc_load (code, ppc_r0, (gulong)item->key);
6436 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
6437 item->jmp_code = code;
6438 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
6439 if (item->has_target_code) {
6440 ppc_load_ptr (code, ppc_r0, item->value.target_code);
6443 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
6444 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
6446 ppc_mtctr (code, ppc_r0);
6447 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
6448 ppc_patch (item->jmp_code, code);
6449 ppc_load_ptr (code, ppc_r0, fail_tramp);
6450 ppc_mtctr (code, ppc_r0);
6451 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
6452 item->jmp_code = NULL;
6454 /* enable the commented code to assert on wrong method */
6455 #if ENABLE_WRONG_METHOD_CHECK
6456 ppc_load (code, ppc_r0, (guint32)item->key);
6457 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
6458 item->jmp_code = code;
6459 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
6461 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
6462 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
6463 ppc_mtctr (code, ppc_r0);
6464 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
6465 #if ENABLE_WRONG_METHOD_CHECK
6466 ppc_patch (item->jmp_code, code);
6468 item->jmp_code = NULL;
6473 ppc_load (code, ppc_r0, (gulong)item->key);
6474 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
6475 item->jmp_code = code;
6476 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
6479 /* patch the branches to get to the target items */
6480 for (i = 0; i < count; ++i) {
6481 MonoIMTCheckItem *item = imt_entries [i];
6482 if (item->jmp_code) {
6483 if (item->check_target_idx) {
6484 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
6490 mono_stats.imt_thunks_size += code - start;
6491 g_assert (code - start <= size);
6492 mono_arch_flush_icache (start, size);
6497 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6499 mgreg_t *r = (mgreg_t*)regs;
6501 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
6505 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6507 mgreg_t *r = (mgreg_t*)regs;
6509 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
6513 mono_arch_get_cie_program (void)
6517 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
6523 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
6530 mono_arch_print_tree (MonoInst *tree, int arity)
6536 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6539 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6541 g_assert (reg >= ppc_r13);
6543 return ctx->regs [reg - ppc_r13];
6547 mono_arch_get_patch_offset (guint8 *code)
6553 * mono_aot_emit_load_got_addr:
6555 * Emit code to load the got address.
6556 * On PPC, the result is placed into r30.
6559 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6562 ppc_mflr (code, ppc_r30);
6564 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6566 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6567 /* arch_emit_got_address () patches this */
6568 #if defined(TARGET_POWERPC64)
6574 ppc_load32 (code, ppc_r0, 0);
6575 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6582 * mono_ppc_emit_load_aotconst:
6584 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6585 * TARGET from the mscorlib GOT in full-aot code.
6586 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6590 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6592 /* Load the mscorlib got address */
6593 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6594 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6595 /* arch_emit_got_access () patches this */
6596 ppc_load32 (code, ppc_r0, 0);
6597 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6602 /* Soft Debug support */
6603 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6610 * mono_arch_set_breakpoint:
6612 * See mini-amd64.c for docs.
6615 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6618 guint8 *orig_code = code;
6620 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6621 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6623 g_assert (code - orig_code == BREAKPOINT_SIZE);
6625 mono_arch_flush_icache (orig_code, code - orig_code);
6629 * mono_arch_clear_breakpoint:
6631 * See mini-amd64.c for docs.
6634 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6639 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6642 mono_arch_flush_icache (ip, code - ip);
6646 * mono_arch_is_breakpoint_event:
6648 * See mini-amd64.c for docs.
6651 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6653 siginfo_t* sinfo = (siginfo_t*) info;
6654 /* Sometimes the address is off by 4 */
6655 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6662 * mono_arch_skip_breakpoint:
6664 * See mini-amd64.c for docs.
6667 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6669 /* skip the ldptr */
6670 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6678 * mono_arch_start_single_stepping:
6680 * See mini-amd64.c for docs.
6683 mono_arch_start_single_stepping (void)
6685 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6689 * mono_arch_stop_single_stepping:
6691 * See mini-amd64.c for docs.
6694 mono_arch_stop_single_stepping (void)
6696 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6700 * mono_arch_is_single_step_event:
6702 * See mini-amd64.c for docs.
6705 mono_arch_is_single_step_event (void *info, void *sigctx)
6707 siginfo_t* sinfo = (siginfo_t*) info;
6708 /* Sometimes the address is off by 4 */
6709 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6716 * mono_arch_skip_single_step:
6718 * See mini-amd64.c for docs.
6721 mono_arch_skip_single_step (MonoContext *ctx)
6723 /* skip the ldptr */
6724 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6728 * mono_arch_create_seq_point_info:
6730 * See mini-amd64.c for docs.
6733 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6740 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6742 ext->lmf.previous_lmf = prev_lmf;
6743 /* Mark that this is a MonoLMFExt */
6744 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6745 ext->lmf.ebp = (gssize)ext;
6750 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6751 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6752 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6755 mono_arch_create_handler_block_trampoline (void)
6765 mono_arch_opcode_supported (int opcode)
6768 case OP_ATOMIC_ADD_I4:
6769 case OP_ATOMIC_CAS_I4:
6770 #ifdef TARGET_POWERPC64
6771 case OP_ATOMIC_ADD_I8:
6772 case OP_ATOMIC_CAS_I8: