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 (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
284 int k, frame_size = 0;
285 int size, align, pad;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
293 arg_info [0].offset = offset;
296 frame_size += sizeof (gpointer);
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
307 size = mini_type_stack_size (csig->params [k], &align);
309 /* ignore alignment for now */
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
318 arg_info [k + 1].offset = offset;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
330 #ifdef __mono_ppc64__
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
367 return is_load_sequence (&code [-6]);
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
380 #define MAX_ARCH_DELEGATE_PARAMS 7
383 get_delegate_invoke_impl (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_get_underlying_type (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
875 guint32 vtsize; /* in param area */
877 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
878 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
879 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
880 guint8 bytes : 4; /* size in bytes - only valid for
881 RegTypeStructByVal if the struct fits
882 in one word, otherwise it's 0*/
891 gboolean vtype_retaddr;
899 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
901 #ifdef __mono_ppc64__
906 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
907 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
908 ainfo->reg = ppc_sp; /* in the caller */
909 ainfo->regtype = RegTypeBase;
910 *stack_size += sizeof (gpointer);
912 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
916 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
918 //*stack_size += (*stack_size % 8);
920 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
921 ainfo->reg = ppc_sp; /* in the caller */
922 ainfo->regtype = RegTypeBase;
929 ALWAYS_ON_STACK (*stack_size += 8);
937 #if defined(__APPLE__) || defined(__mono_ppc64__)
939 has_only_a_r48_field (MonoClass *klass)
943 gboolean have_field = FALSE;
945 while ((f = mono_class_get_fields (klass, &iter))) {
946 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
949 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
960 get_call_info (MonoMethodSignature *sig)
962 guint i, fr, gr, pstart;
963 int n = sig->hasthis + sig->param_count;
964 MonoType *simpletype;
965 guint32 stack_size = 0;
966 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
967 gboolean is_pinvoke = sig->pinvoke;
969 fr = PPC_FIRST_FPARG_REG;
970 gr = PPC_FIRST_ARG_REG;
972 /* FIXME: handle returning a struct */
973 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
974 cinfo->vtype_retaddr = TRUE;
980 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
981 * the first argument, allowing 'this' to be always passed in the first arg reg.
982 * Also do this if the first argument is a reference type, since virtual calls
983 * are sometimes made using calli without sig->hasthis set, like in the delegate
986 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
988 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
991 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
995 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
996 cinfo->struct_ret = cinfo->ret.reg;
997 cinfo->vret_arg_index = 1;
1001 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1005 if (cinfo->vtype_retaddr) {
1006 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1007 cinfo->struct_ret = cinfo->ret.reg;
1011 DEBUG(printf("params: %d\n", sig->param_count));
1012 for (i = pstart; i < sig->param_count; ++i) {
1013 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1014 /* Prevent implicit arguments and sig_cookie from
1015 being passed in registers */
1016 gr = PPC_LAST_ARG_REG + 1;
1017 /* FIXME: don't we have to set fr, too? */
1018 /* Emit the signature cookie just before the implicit arguments */
1019 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1021 DEBUG(printf("param %d: ", i));
1022 if (sig->params [i]->byref) {
1023 DEBUG(printf("byref\n"));
1024 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1028 simpletype = mini_get_underlying_type (sig->params [i]);
1029 switch (simpletype->type) {
1030 case MONO_TYPE_BOOLEAN:
1033 cinfo->args [n].size = 1;
1034 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1037 case MONO_TYPE_CHAR:
1040 cinfo->args [n].size = 2;
1041 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1046 cinfo->args [n].size = 4;
1047 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1053 case MONO_TYPE_FNPTR:
1054 case MONO_TYPE_CLASS:
1055 case MONO_TYPE_OBJECT:
1056 case MONO_TYPE_STRING:
1057 case MONO_TYPE_SZARRAY:
1058 case MONO_TYPE_ARRAY:
1059 cinfo->args [n].size = sizeof (gpointer);
1060 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1063 case MONO_TYPE_GENERICINST:
1064 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1065 cinfo->args [n].size = sizeof (gpointer);
1066 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1071 case MONO_TYPE_VALUETYPE:
1072 case MONO_TYPE_TYPEDBYREF: {
1076 klass = mono_class_from_mono_type (sig->params [i]);
1077 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1078 size = sizeof (MonoTypedRef);
1079 else if (is_pinvoke)
1080 size = mono_class_native_size (klass, NULL);
1082 size = mono_class_value_size (klass, NULL);
1084 #if defined(__APPLE__) || defined(__mono_ppc64__)
1085 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1086 cinfo->args [n].size = size;
1088 /* It was 7, now it is 8 in LinuxPPC */
1089 if (fr <= PPC_LAST_FPARG_REG) {
1090 cinfo->args [n].regtype = RegTypeFP;
1091 cinfo->args [n].reg = fr;
1093 FP_ALSO_IN_REG (gr ++);
1095 FP_ALSO_IN_REG (gr ++);
1096 ALWAYS_ON_STACK (stack_size += size);
1098 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1099 cinfo->args [n].regtype = RegTypeBase;
1100 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1107 DEBUG(printf ("load %d bytes struct\n",
1108 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1110 #if PPC_PASS_STRUCTS_BY_VALUE
1112 int align_size = size;
1114 int rest = PPC_LAST_ARG_REG - gr + 1;
1117 align_size += (sizeof (gpointer) - 1);
1118 align_size &= ~(sizeof (gpointer) - 1);
1119 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1120 n_in_regs = MIN (rest, nregs);
1124 /* FIXME: check this */
1125 if (size >= 3 && size % 4 != 0)
1128 cinfo->args [n].regtype = RegTypeStructByVal;
1129 cinfo->args [n].vtregs = n_in_regs;
1130 cinfo->args [n].size = n_in_regs;
1131 cinfo->args [n].vtsize = nregs - n_in_regs;
1132 cinfo->args [n].reg = gr;
1134 #ifdef __mono_ppc64__
1135 if (nregs == 1 && is_pinvoke)
1136 cinfo->args [n].bytes = size;
1139 cinfo->args [n].bytes = 0;
1141 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1142 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1143 stack_size += nregs * sizeof (gpointer);
1146 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1147 cinfo->args [n].regtype = RegTypeStructByAddr;
1148 cinfo->args [n].vtsize = size;
1155 cinfo->args [n].size = 8;
1156 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1160 cinfo->args [n].size = 4;
1162 /* It was 7, now it is 8 in LinuxPPC */
1163 if (fr <= PPC_LAST_FPARG_REG) {
1164 cinfo->args [n].regtype = RegTypeFP;
1165 cinfo->args [n].reg = fr;
1167 FP_ALSO_IN_REG (gr ++);
1168 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1170 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1171 cinfo->args [n].regtype = RegTypeBase;
1172 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1173 stack_size += SIZEOF_REGISTER;
1178 cinfo->args [n].size = 8;
1179 /* It was 7, now it is 8 in LinuxPPC */
1180 if (fr <= PPC_LAST_FPARG_REG) {
1181 cinfo->args [n].regtype = RegTypeFP;
1182 cinfo->args [n].reg = fr;
1184 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1185 ALWAYS_ON_STACK (stack_size += 8);
1187 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1188 cinfo->args [n].regtype = RegTypeBase;
1189 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1195 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1200 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1201 /* Prevent implicit arguments and sig_cookie from
1202 being passed in registers */
1203 gr = PPC_LAST_ARG_REG + 1;
1204 /* Emit the signature cookie just before the implicit arguments */
1205 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1209 simpletype = mini_get_underlying_type (sig->ret);
1210 switch (simpletype->type) {
1211 case MONO_TYPE_BOOLEAN:
1216 case MONO_TYPE_CHAR:
1222 case MONO_TYPE_FNPTR:
1223 case MONO_TYPE_CLASS:
1224 case MONO_TYPE_OBJECT:
1225 case MONO_TYPE_SZARRAY:
1226 case MONO_TYPE_ARRAY:
1227 case MONO_TYPE_STRING:
1228 cinfo->ret.reg = ppc_r3;
1232 cinfo->ret.reg = ppc_r3;
1236 cinfo->ret.reg = ppc_f1;
1237 cinfo->ret.regtype = RegTypeFP;
1239 case MONO_TYPE_GENERICINST:
1240 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1241 cinfo->ret.reg = ppc_r3;
1245 case MONO_TYPE_VALUETYPE:
1247 case MONO_TYPE_TYPEDBYREF:
1248 case MONO_TYPE_VOID:
1251 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1255 /* align stack size to 16 */
1256 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1257 stack_size = (stack_size + 15) & ~15;
1259 cinfo->stack_usage = stack_size;
1264 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1270 c1 = get_call_info (caller_sig);
1271 c2 = get_call_info (callee_sig);
1272 res = c1->stack_usage >= c2->stack_usage;
1273 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1274 /* An address on the callee's stack is passed as the first argument */
1276 for (i = 0; i < c2->nargs; ++i) {
1277 if (c2->args [i].regtype == RegTypeStructByAddr)
1278 /* An address on the callee's stack is passed as the argument */
1283 if (!mono_debug_count ())
1294 * Set var information according to the calling convention. ppc version.
1295 * The locals var stuff should most likely be split in another method.
1298 mono_arch_allocate_vars (MonoCompile *m)
1300 MonoMethodSignature *sig;
1301 MonoMethodHeader *header;
1303 int i, offset, size, align, curinst;
1304 int frame_reg = ppc_sp;
1306 guint32 locals_stack_size, locals_stack_align;
1308 m->flags |= MONO_CFG_HAS_SPILLUP;
1310 /* allow room for the vararg method args: void* and long/double */
1311 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1312 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1313 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1314 * call convs needs to be handled this way.
1316 if (m->flags & MONO_CFG_HAS_VARARGS)
1317 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1318 /* gtk-sharp and other broken code will dllimport vararg functions even with
1319 * non-varargs signatures. Since there is little hope people will get this right
1320 * we assume they won't.
1322 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1323 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1328 * We use the frame register also for any method that has
1329 * exception clauses. This way, when the handlers are called,
1330 * the code will reference local variables using the frame reg instead of
1331 * the stack pointer: if we had to restore the stack pointer, we'd
1332 * corrupt the method frames that are already on the stack (since
1333 * filters get called before stack unwinding happens) when the filter
1334 * code would call any method (this also applies to finally etc.).
1336 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1337 frame_reg = ppc_r31;
1338 m->frame_reg = frame_reg;
1339 if (frame_reg != ppc_sp) {
1340 m->used_int_regs |= 1 << frame_reg;
1343 sig = mono_method_signature (m->method);
1347 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1348 m->ret->opcode = OP_REGVAR;
1349 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1351 /* FIXME: handle long values? */
1352 switch (mini_get_underlying_type (m, sig->ret)->type) {
1353 case MONO_TYPE_VOID:
1357 m->ret->opcode = OP_REGVAR;
1358 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1361 m->ret->opcode = OP_REGVAR;
1362 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1366 /* local vars are at a positive offset from the stack pointer */
1368 * also note that if the function uses alloca, we use ppc_r31
1369 * to point at the local variables.
1371 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1372 /* align the offset to 16 bytes: not sure this is needed here */
1374 //offset &= ~(16 - 1);
1376 /* add parameter area size for called functions */
1377 offset += m->param_area;
1379 offset &= ~(16 - 1);
1381 /* allow room to save the return value */
1382 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1385 /* the MonoLMF structure is stored just below the stack pointer */
1388 /* this stuff should not be needed on ppc and the new jit,
1389 * because a call on ppc to the handlers doesn't change the
1390 * stack pointer and the jist doesn't manipulate the stack pointer
1391 * for operations involving valuetypes.
1393 /* reserve space to store the esp */
1394 offset += sizeof (gpointer);
1396 /* this is a global constant */
1397 mono_exc_esp_offset = offset;
1400 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1401 offset += sizeof(gpointer) - 1;
1402 offset &= ~(sizeof(gpointer) - 1);
1404 m->vret_addr->opcode = OP_REGOFFSET;
1405 m->vret_addr->inst_basereg = frame_reg;
1406 m->vret_addr->inst_offset = offset;
1408 if (G_UNLIKELY (m->verbose_level > 1)) {
1409 printf ("vret_addr =");
1410 mono_print_ins (m->vret_addr);
1413 offset += sizeof(gpointer);
1416 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1417 if (locals_stack_align) {
1418 offset += (locals_stack_align - 1);
1419 offset &= ~(locals_stack_align - 1);
1421 for (i = m->locals_start; i < m->num_varinfo; i++) {
1422 if (offsets [i] != -1) {
1423 MonoInst *inst = m->varinfo [i];
1424 inst->opcode = OP_REGOFFSET;
1425 inst->inst_basereg = frame_reg;
1426 inst->inst_offset = offset + offsets [i];
1428 g_print ("allocating local %d (%s) to %d\n",
1429 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1433 offset += locals_stack_size;
1437 inst = m->args [curinst];
1438 if (inst->opcode != OP_REGVAR) {
1439 inst->opcode = OP_REGOFFSET;
1440 inst->inst_basereg = frame_reg;
1441 offset += sizeof (gpointer) - 1;
1442 offset &= ~(sizeof (gpointer) - 1);
1443 inst->inst_offset = offset;
1444 offset += sizeof (gpointer);
1449 for (i = 0; i < sig->param_count; ++i) {
1450 inst = m->args [curinst];
1451 if (inst->opcode != OP_REGVAR) {
1452 inst->opcode = OP_REGOFFSET;
1453 inst->inst_basereg = frame_reg;
1455 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1456 inst->backend.is_pinvoke = 1;
1458 size = mono_type_size (sig->params [i], &align);
1460 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1461 size = align = sizeof (gpointer);
1463 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1464 * they are saved using std in the prolog.
1466 align = sizeof (gpointer);
1467 offset += align - 1;
1468 offset &= ~(align - 1);
1469 inst->inst_offset = offset;
1475 /* some storage for fp conversions */
1478 m->arch.fp_conv_var_offset = offset;
1481 /* align the offset to 16 bytes */
1483 offset &= ~(16 - 1);
1486 m->stack_offset = offset;
1488 if (sig->call_convention == MONO_CALL_VARARG) {
1489 CallInfo *cinfo = get_call_info (m->method->signature);
1491 m->sig_cookie = cinfo->sig_cookie.offset;
1498 mono_arch_create_vars (MonoCompile *cfg)
1500 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1502 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1503 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1507 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1508 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1512 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1514 int sig_reg = mono_alloc_ireg (cfg);
1516 /* FIXME: Add support for signature tokens to AOT */
1517 cfg->disable_aot = TRUE;
1519 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1520 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1521 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1525 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1528 MonoMethodSignature *sig;
1532 sig = call->signature;
1533 n = sig->param_count + sig->hasthis;
1535 cinfo = get_call_info (sig);
1537 for (i = 0; i < n; ++i) {
1538 ArgInfo *ainfo = cinfo->args + i;
1541 if (i >= sig->hasthis)
1542 t = sig->params [i - sig->hasthis];
1544 t = &mono_defaults.int_class->byval_arg;
1545 t = mini_get_underlying_type (t);
1547 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1548 emit_sig_cookie (cfg, call, cinfo);
1550 in = call->args [i];
1552 if (ainfo->regtype == RegTypeGeneral) {
1553 #ifndef __mono_ppc64__
1554 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1555 MONO_INST_NEW (cfg, ins, OP_MOVE);
1556 ins->dreg = mono_alloc_ireg (cfg);
1557 ins->sreg1 = in->dreg + 1;
1558 MONO_ADD_INS (cfg->cbb, ins);
1559 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1561 MONO_INST_NEW (cfg, ins, OP_MOVE);
1562 ins->dreg = mono_alloc_ireg (cfg);
1563 ins->sreg1 = in->dreg + 2;
1564 MONO_ADD_INS (cfg->cbb, ins);
1565 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1569 MONO_INST_NEW (cfg, ins, OP_MOVE);
1570 ins->dreg = mono_alloc_ireg (cfg);
1571 ins->sreg1 = in->dreg;
1572 MONO_ADD_INS (cfg->cbb, ins);
1574 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1576 } else if (ainfo->regtype == RegTypeStructByAddr) {
1577 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1578 ins->opcode = OP_OUTARG_VT;
1579 ins->sreg1 = in->dreg;
1580 ins->klass = in->klass;
1581 ins->inst_p0 = call;
1582 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1583 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1584 MONO_ADD_INS (cfg->cbb, ins);
1585 } else if (ainfo->regtype == RegTypeStructByVal) {
1586 /* this is further handled in mono_arch_emit_outarg_vt () */
1587 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1588 ins->opcode = OP_OUTARG_VT;
1589 ins->sreg1 = in->dreg;
1590 ins->klass = in->klass;
1591 ins->inst_p0 = call;
1592 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1593 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1594 MONO_ADD_INS (cfg->cbb, ins);
1595 } else if (ainfo->regtype == RegTypeBase) {
1596 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1597 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1598 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1599 if (t->type == MONO_TYPE_R8)
1600 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1602 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1604 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1606 } else if (ainfo->regtype == RegTypeFP) {
1607 if (t->type == MONO_TYPE_VALUETYPE) {
1608 /* this is further handled in mono_arch_emit_outarg_vt () */
1609 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1610 ins->opcode = OP_OUTARG_VT;
1611 ins->sreg1 = in->dreg;
1612 ins->klass = in->klass;
1613 ins->inst_p0 = call;
1614 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1615 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1616 MONO_ADD_INS (cfg->cbb, ins);
1618 cfg->flags |= MONO_CFG_HAS_FPOUT;
1620 int dreg = mono_alloc_freg (cfg);
1622 if (ainfo->size == 4) {
1623 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1625 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1627 ins->sreg1 = in->dreg;
1628 MONO_ADD_INS (cfg->cbb, ins);
1631 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1632 cfg->flags |= MONO_CFG_HAS_FPOUT;
1635 g_assert_not_reached ();
1639 /* Emit the signature cookie in the case that there is no
1640 additional argument */
1641 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1642 emit_sig_cookie (cfg, call, cinfo);
1644 if (cinfo->struct_ret) {
1647 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1648 vtarg->sreg1 = call->vret_var->dreg;
1649 vtarg->dreg = mono_alloc_preg (cfg);
1650 MONO_ADD_INS (cfg->cbb, vtarg);
1652 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1655 call->stack_usage = cinfo->stack_usage;
1656 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1657 cfg->flags |= MONO_CFG_HAS_CALLS;
1665 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1667 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1668 ArgInfo *ainfo = ins->inst_p1;
1669 int ovf_size = ainfo->vtsize;
1670 int doffset = ainfo->offset;
1671 int i, soffset, dreg;
1673 if (ainfo->regtype == RegTypeStructByVal) {
1680 * Darwin pinvokes needs some special handling for 1
1681 * and 2 byte arguments
1683 g_assert (ins->klass);
1684 if (call->signature->pinvoke)
1685 size = mono_class_native_size (ins->klass, NULL);
1686 if (size == 2 || size == 1) {
1687 int tmpr = mono_alloc_ireg (cfg);
1689 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1691 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1692 dreg = mono_alloc_ireg (cfg);
1693 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1694 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1697 for (i = 0; i < ainfo->vtregs; ++i) {
1698 int antipadding = 0;
1701 antipadding = sizeof (gpointer) - ainfo->bytes;
1703 dreg = mono_alloc_ireg (cfg);
1704 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1706 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1707 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1708 soffset += sizeof (gpointer);
1711 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1712 } else if (ainfo->regtype == RegTypeFP) {
1713 int tmpr = mono_alloc_freg (cfg);
1714 if (ainfo->size == 4)
1715 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1717 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1718 dreg = mono_alloc_freg (cfg);
1719 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1720 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1722 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1726 /* FIXME: alignment? */
1727 if (call->signature->pinvoke) {
1728 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1729 vtcopy->backend.is_pinvoke = 1;
1731 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1734 g_assert (ovf_size > 0);
1736 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1737 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1740 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1742 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1747 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1749 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1752 #ifndef __mono_ppc64__
1753 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1756 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1757 ins->sreg1 = val->dreg + 1;
1758 ins->sreg2 = val->dreg + 2;
1759 MONO_ADD_INS (cfg->cbb, ins);
1763 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1764 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1768 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1771 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1773 mono_arch_is_inst_imm (gint64 imm)
1778 #endif /* DISABLE_JIT */
1781 * Allow tracing to work with this interface (with an optional argument)
1785 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1789 ppc_load_ptr (code, ppc_r3, cfg->method);
1790 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1791 ppc_load_func (code, PPC_CALL_REG, func);
1792 ppc_mtlr (code, PPC_CALL_REG);
1806 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1809 int save_mode = SAVE_NONE;
1811 MonoMethod *method = cfg->method;
1812 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
1813 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1817 offset = code - cfg->native_code;
1818 /* we need about 16 instructions */
1819 if (offset > (cfg->code_size - 16 * 4)) {
1820 cfg->code_size *= 2;
1821 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1822 code = cfg->native_code + offset;
1826 case MONO_TYPE_VOID:
1827 /* special case string .ctor icall */
1828 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1829 save_mode = SAVE_ONE;
1831 save_mode = SAVE_NONE;
1833 #ifndef __mono_ppc64__
1836 save_mode = SAVE_TWO;
1841 save_mode = SAVE_FP;
1843 case MONO_TYPE_VALUETYPE:
1844 save_mode = SAVE_STRUCT;
1847 save_mode = SAVE_ONE;
1851 switch (save_mode) {
1853 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1854 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1855 if (enable_arguments) {
1856 ppc_mr (code, ppc_r5, ppc_r4);
1857 ppc_mr (code, ppc_r4, ppc_r3);
1861 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1862 if (enable_arguments) {
1863 ppc_mr (code, ppc_r4, ppc_r3);
1867 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1868 if (enable_arguments) {
1869 /* FIXME: what reg? */
1870 ppc_fmr (code, ppc_f3, ppc_f1);
1871 /* FIXME: use 8 byte load on PPC64 */
1872 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1873 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1877 if (enable_arguments) {
1878 /* FIXME: get the actual address */
1879 ppc_mr (code, ppc_r4, ppc_r3);
1887 ppc_load_ptr (code, ppc_r3, cfg->method);
1888 ppc_load_func (code, PPC_CALL_REG, func);
1889 ppc_mtlr (code, PPC_CALL_REG);
1892 switch (save_mode) {
1894 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1895 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1898 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1901 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1911 * Conditional branches have a small offset, so if it is likely overflowed,
1912 * we do a branch to the end of the method (uncond branches have much larger
1913 * offsets) where we perform the conditional and jump back unconditionally.
1914 * It's slightly slower, since we add two uncond branches, but it's very simple
1915 * with the current patch implementation and such large methods are likely not
1916 * going to be perf critical anyway.
1921 const char *exception;
1928 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1929 if (0 && ins->inst_true_bb->native_offset) { \
1930 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1932 int br_disp = ins->inst_true_bb->max_offset - offset; \
1933 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1934 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1935 ovfj->data.bb = ins->inst_true_bb; \
1936 ovfj->ip_offset = 0; \
1937 ovfj->b0_cond = (b0); \
1938 ovfj->b1_cond = (b1); \
1939 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1942 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1943 ppc_bc (code, (b0), (b1), 0); \
1947 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1949 /* emit an exception if condition is fail
1951 * We assign the extra code used to throw the implicit exceptions
1952 * to cfg->bb_exit as far as the big branch handling is concerned
1954 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1956 int br_disp = cfg->bb_exit->max_offset - offset; \
1957 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1958 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1959 ovfj->data.exception = (exc_name); \
1960 ovfj->ip_offset = code - cfg->native_code; \
1961 ovfj->b0_cond = (b0); \
1962 ovfj->b1_cond = (b1); \
1963 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1965 cfg->bb_exit->max_offset += 24; \
1967 mono_add_patch_info (cfg, code - cfg->native_code, \
1968 MONO_PATCH_INFO_EXC, exc_name); \
1969 ppc_bcl (code, (b0), (b1), 0); \
1973 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1976 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1981 normalize_opcode (int opcode)
1984 #ifndef __mono_ilp32__
1985 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1986 return OP_LOAD_MEMBASE;
1987 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1988 return OP_LOAD_MEMINDEX;
1989 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1990 return OP_STORE_MEMBASE_REG;
1991 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1992 return OP_STORE_MEMBASE_IMM;
1993 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1994 return OP_STORE_MEMINDEX;
1996 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1998 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1999 return OP_SHR_UN_IMM;
2006 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2008 MonoInst *ins, *n, *last_ins = NULL;
2010 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2011 switch (normalize_opcode (ins->opcode)) {
2013 /* remove unnecessary multiplication with 1 */
2014 if (ins->inst_imm == 1) {
2015 if (ins->dreg != ins->sreg1) {
2016 ins->opcode = OP_MOVE;
2018 MONO_DELETE_INS (bb, ins);
2022 int power2 = mono_is_power_of_two (ins->inst_imm);
2024 ins->opcode = OP_SHL_IMM;
2025 ins->inst_imm = power2;
2029 case OP_LOAD_MEMBASE:
2031 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2032 * OP_LOAD_MEMBASE offset(basereg), reg
2034 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2035 ins->inst_basereg == last_ins->inst_destbasereg &&
2036 ins->inst_offset == last_ins->inst_offset) {
2037 if (ins->dreg == last_ins->sreg1) {
2038 MONO_DELETE_INS (bb, ins);
2041 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2042 ins->opcode = OP_MOVE;
2043 ins->sreg1 = last_ins->sreg1;
2047 * Note: reg1 must be different from the basereg in the second load
2048 * OP_LOAD_MEMBASE offset(basereg), reg1
2049 * OP_LOAD_MEMBASE offset(basereg), reg2
2051 * OP_LOAD_MEMBASE offset(basereg), reg1
2052 * OP_MOVE reg1, reg2
2054 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2055 ins->inst_basereg != last_ins->dreg &&
2056 ins->inst_basereg == last_ins->inst_basereg &&
2057 ins->inst_offset == last_ins->inst_offset) {
2059 if (ins->dreg == last_ins->dreg) {
2060 MONO_DELETE_INS (bb, ins);
2063 ins->opcode = OP_MOVE;
2064 ins->sreg1 = last_ins->dreg;
2067 //g_assert_not_reached ();
2071 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2072 * OP_LOAD_MEMBASE offset(basereg), reg
2074 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2075 * OP_ICONST reg, imm
2077 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2078 ins->inst_basereg == last_ins->inst_destbasereg &&
2079 ins->inst_offset == last_ins->inst_offset) {
2080 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2081 ins->opcode = OP_ICONST;
2082 ins->inst_c0 = last_ins->inst_imm;
2083 g_assert_not_reached (); // check this rule
2087 case OP_LOADU1_MEMBASE:
2088 case OP_LOADI1_MEMBASE:
2089 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2090 ins->inst_basereg == last_ins->inst_destbasereg &&
2091 ins->inst_offset == last_ins->inst_offset) {
2092 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2093 ins->sreg1 = last_ins->sreg1;
2096 case OP_LOADU2_MEMBASE:
2097 case OP_LOADI2_MEMBASE:
2098 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2099 ins->inst_basereg == last_ins->inst_destbasereg &&
2100 ins->inst_offset == last_ins->inst_offset) {
2101 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2102 ins->sreg1 = last_ins->sreg1;
2105 #ifdef __mono_ppc64__
2106 case OP_LOADU4_MEMBASE:
2107 case OP_LOADI4_MEMBASE:
2108 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2112 ins->sreg1 = last_ins->sreg1;
2117 ins->opcode = OP_MOVE;
2121 if (ins->dreg == ins->sreg1) {
2122 MONO_DELETE_INS (bb, ins);
2126 * OP_MOVE sreg, dreg
2127 * OP_MOVE dreg, sreg
2129 if (last_ins && last_ins->opcode == OP_MOVE &&
2130 ins->sreg1 == last_ins->dreg &&
2131 ins->dreg == last_ins->sreg1) {
2132 MONO_DELETE_INS (bb, ins);
2140 bb->last_ins = last_ins;
2144 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2146 switch (ins->opcode) {
2147 case OP_ICONV_TO_R_UN: {
2148 // This value is OK as-is for both big and little endian because of how it is stored
2149 static const guint64 adjust_val = 0x4330000000000000ULL;
2150 int msw_reg = mono_alloc_ireg (cfg);
2151 int adj_reg = mono_alloc_freg (cfg);
2152 int tmp_reg = mono_alloc_freg (cfg);
2153 int basereg = ppc_sp;
2155 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2156 if (!ppc_is_imm16 (offset + 4)) {
2157 basereg = mono_alloc_ireg (cfg);
2158 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2160 #if G_BYTE_ORDER == G_BIG_ENDIAN
2161 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2162 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2164 // For little endian the words are reversed
2165 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2166 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2168 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2169 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2171 ins->opcode = OP_NOP;
2174 #ifndef __mono_ppc64__
2175 case OP_ICONV_TO_R4:
2176 case OP_ICONV_TO_R8: {
2177 /* If we have a PPC_FEATURE_64 machine we can avoid
2178 this and use the fcfid instruction. Otherwise
2179 on an old 32-bit chip and we have to do this the
2181 if (!(cpu_hw_caps & PPC_ISA_64)) {
2182 /* FIXME: change precision for CEE_CONV_R4 */
2183 static const guint64 adjust_val = 0x4330000080000000ULL;
2184 int msw_reg = mono_alloc_ireg (cfg);
2185 int xored = mono_alloc_ireg (cfg);
2186 int adj_reg = mono_alloc_freg (cfg);
2187 int tmp_reg = mono_alloc_freg (cfg);
2188 int basereg = ppc_sp;
2190 if (!ppc_is_imm16 (offset + 4)) {
2191 basereg = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2194 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2195 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2196 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2197 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2198 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2199 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2201 if (ins->opcode == OP_ICONV_TO_R4)
2202 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2203 ins->opcode = OP_NOP;
2209 int msw_reg = mono_alloc_ireg (cfg);
2210 int basereg = ppc_sp;
2212 if (!ppc_is_imm16 (offset + 4)) {
2213 basereg = mono_alloc_ireg (cfg);
2214 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2216 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2217 #if G_BYTE_ORDER == G_BIG_ENDIAN
2218 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2220 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2222 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2223 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2224 ins->opcode = OP_NOP;
2227 #ifdef __mono_ppc64__
2229 case OP_IADD_OVF_UN:
2231 int shifted1_reg = mono_alloc_ireg (cfg);
2232 int shifted2_reg = mono_alloc_ireg (cfg);
2233 int result_shifted_reg = mono_alloc_ireg (cfg);
2235 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2236 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2237 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2238 if (ins->opcode == OP_IADD_OVF_UN)
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2241 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2242 ins->opcode = OP_NOP;
2249 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2251 switch (ins->opcode) {
2253 /* ADC sets the condition code */
2254 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2255 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2258 case OP_LADD_OVF_UN:
2259 /* ADC sets the condition code */
2260 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2265 /* SBB sets the condition code */
2266 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2267 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2270 case OP_LSUB_OVF_UN:
2271 /* SBB sets the condition code */
2272 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2273 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2277 /* From gcc generated code */
2278 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2279 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2288 * the branch_b0_table should maintain the order of these
2302 branch_b0_table [] = {
2317 branch_b1_table [] = {
2331 #define NEW_INS(cfg,dest,op) do { \
2332 MONO_INST_NEW((cfg), (dest), (op)); \
2333 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2337 map_to_reg_reg_op (int op)
2346 case OP_COMPARE_IMM:
2348 case OP_ICOMPARE_IMM:
2350 case OP_LCOMPARE_IMM:
2366 case OP_LOAD_MEMBASE:
2367 return OP_LOAD_MEMINDEX;
2368 case OP_LOADI4_MEMBASE:
2369 return OP_LOADI4_MEMINDEX;
2370 case OP_LOADU4_MEMBASE:
2371 return OP_LOADU4_MEMINDEX;
2372 case OP_LOADI8_MEMBASE:
2373 return OP_LOADI8_MEMINDEX;
2374 case OP_LOADU1_MEMBASE:
2375 return OP_LOADU1_MEMINDEX;
2376 case OP_LOADI2_MEMBASE:
2377 return OP_LOADI2_MEMINDEX;
2378 case OP_LOADU2_MEMBASE:
2379 return OP_LOADU2_MEMINDEX;
2380 case OP_LOADI1_MEMBASE:
2381 return OP_LOADI1_MEMINDEX;
2382 case OP_LOADR4_MEMBASE:
2383 return OP_LOADR4_MEMINDEX;
2384 case OP_LOADR8_MEMBASE:
2385 return OP_LOADR8_MEMINDEX;
2386 case OP_STOREI1_MEMBASE_REG:
2387 return OP_STOREI1_MEMINDEX;
2388 case OP_STOREI2_MEMBASE_REG:
2389 return OP_STOREI2_MEMINDEX;
2390 case OP_STOREI4_MEMBASE_REG:
2391 return OP_STOREI4_MEMINDEX;
2392 case OP_STOREI8_MEMBASE_REG:
2393 return OP_STOREI8_MEMINDEX;
2394 case OP_STORE_MEMBASE_REG:
2395 return OP_STORE_MEMINDEX;
2396 case OP_STORER4_MEMBASE_REG:
2397 return OP_STORER4_MEMINDEX;
2398 case OP_STORER8_MEMBASE_REG:
2399 return OP_STORER8_MEMINDEX;
2400 case OP_STORE_MEMBASE_IMM:
2401 return OP_STORE_MEMBASE_REG;
2402 case OP_STOREI1_MEMBASE_IMM:
2403 return OP_STOREI1_MEMBASE_REG;
2404 case OP_STOREI2_MEMBASE_IMM:
2405 return OP_STOREI2_MEMBASE_REG;
2406 case OP_STOREI4_MEMBASE_IMM:
2407 return OP_STOREI4_MEMBASE_REG;
2408 case OP_STOREI8_MEMBASE_IMM:
2409 return OP_STOREI8_MEMBASE_REG;
2411 return mono_op_imm_to_op (op);
2414 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2416 #define compare_opcode_is_unsigned(opcode) \
2417 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2418 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2419 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2420 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2421 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2422 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2423 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2424 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2427 * Remove from the instruction list the instructions that can't be
2428 * represented with very simple instructions with no register
2432 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2434 MonoInst *ins, *next, *temp, *last_ins = NULL;
2437 MONO_BB_FOR_EACH_INS (bb, ins) {
2439 switch (ins->opcode) {
2440 case OP_IDIV_UN_IMM:
2443 case OP_IREM_UN_IMM:
2444 CASE_PPC64 (OP_LREM_IMM) {
2445 NEW_INS (cfg, temp, OP_ICONST);
2446 temp->inst_c0 = ins->inst_imm;
2447 temp->dreg = mono_alloc_ireg (cfg);
2448 ins->sreg2 = temp->dreg;
2449 if (ins->opcode == OP_IDIV_IMM)
2450 ins->opcode = OP_IDIV;
2451 else if (ins->opcode == OP_IREM_IMM)
2452 ins->opcode = OP_IREM;
2453 else if (ins->opcode == OP_IDIV_UN_IMM)
2454 ins->opcode = OP_IDIV_UN;
2455 else if (ins->opcode == OP_IREM_UN_IMM)
2456 ins->opcode = OP_IREM_UN;
2457 else if (ins->opcode == OP_LREM_IMM)
2458 ins->opcode = OP_LREM;
2460 /* handle rem separately */
2465 CASE_PPC64 (OP_LREM)
2466 CASE_PPC64 (OP_LREM_UN) {
2468 /* we change a rem dest, src1, src2 to
2469 * div temp1, src1, src2
2470 * mul temp2, temp1, src2
2471 * sub dest, src1, temp2
2473 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2474 NEW_INS (cfg, mul, OP_IMUL);
2475 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2476 ins->opcode = OP_ISUB;
2478 NEW_INS (cfg, mul, OP_LMUL);
2479 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2480 ins->opcode = OP_LSUB;
2482 temp->sreg1 = ins->sreg1;
2483 temp->sreg2 = ins->sreg2;
2484 temp->dreg = mono_alloc_ireg (cfg);
2485 mul->sreg1 = temp->dreg;
2486 mul->sreg2 = ins->sreg2;
2487 mul->dreg = mono_alloc_ireg (cfg);
2488 ins->sreg2 = mul->dreg;
2492 CASE_PPC64 (OP_LADD_IMM)
2495 if (!ppc_is_imm16 (ins->inst_imm)) {
2496 NEW_INS (cfg, temp, OP_ICONST);
2497 temp->inst_c0 = ins->inst_imm;
2498 temp->dreg = mono_alloc_ireg (cfg);
2499 ins->sreg2 = temp->dreg;
2500 ins->opcode = map_to_reg_reg_op (ins->opcode);
2504 CASE_PPC64 (OP_LSUB_IMM)
2506 if (!ppc_is_imm16 (-ins->inst_imm)) {
2507 NEW_INS (cfg, temp, OP_ICONST);
2508 temp->inst_c0 = ins->inst_imm;
2509 temp->dreg = mono_alloc_ireg (cfg);
2510 ins->sreg2 = temp->dreg;
2511 ins->opcode = map_to_reg_reg_op (ins->opcode);
2523 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2524 #ifdef __mono_ppc64__
2525 if (ins->inst_imm & 0xffffffff00000000ULL)
2529 NEW_INS (cfg, temp, OP_ICONST);
2530 temp->inst_c0 = ins->inst_imm;
2531 temp->dreg = mono_alloc_ireg (cfg);
2532 ins->sreg2 = temp->dreg;
2533 ins->opcode = map_to_reg_reg_op (ins->opcode);
2542 NEW_INS (cfg, temp, OP_ICONST);
2543 temp->inst_c0 = ins->inst_imm;
2544 temp->dreg = mono_alloc_ireg (cfg);
2545 ins->sreg2 = temp->dreg;
2546 ins->opcode = map_to_reg_reg_op (ins->opcode);
2548 case OP_COMPARE_IMM:
2549 case OP_ICOMPARE_IMM:
2550 CASE_PPC64 (OP_LCOMPARE_IMM)
2552 /* Branch opts can eliminate the branch */
2553 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2554 ins->opcode = OP_NOP;
2558 if (compare_opcode_is_unsigned (next->opcode)) {
2559 if (!ppc_is_uimm16 (ins->inst_imm)) {
2560 NEW_INS (cfg, temp, OP_ICONST);
2561 temp->inst_c0 = ins->inst_imm;
2562 temp->dreg = mono_alloc_ireg (cfg);
2563 ins->sreg2 = temp->dreg;
2564 ins->opcode = map_to_reg_reg_op (ins->opcode);
2567 if (!ppc_is_imm16 (ins->inst_imm)) {
2568 NEW_INS (cfg, temp, OP_ICONST);
2569 temp->inst_c0 = ins->inst_imm;
2570 temp->dreg = mono_alloc_ireg (cfg);
2571 ins->sreg2 = temp->dreg;
2572 ins->opcode = map_to_reg_reg_op (ins->opcode);
2578 if (ins->inst_imm == 1) {
2579 ins->opcode = OP_MOVE;
2582 if (ins->inst_imm == 0) {
2583 ins->opcode = OP_ICONST;
2587 imm = mono_is_power_of_two (ins->inst_imm);
2589 ins->opcode = OP_SHL_IMM;
2590 ins->inst_imm = imm;
2593 if (!ppc_is_imm16 (ins->inst_imm)) {
2594 NEW_INS (cfg, temp, OP_ICONST);
2595 temp->inst_c0 = ins->inst_imm;
2596 temp->dreg = mono_alloc_ireg (cfg);
2597 ins->sreg2 = temp->dreg;
2598 ins->opcode = map_to_reg_reg_op (ins->opcode);
2601 case OP_LOCALLOC_IMM:
2602 NEW_INS (cfg, temp, OP_ICONST);
2603 temp->inst_c0 = ins->inst_imm;
2604 temp->dreg = mono_alloc_ireg (cfg);
2605 ins->sreg1 = temp->dreg;
2606 ins->opcode = OP_LOCALLOC;
2608 case OP_LOAD_MEMBASE:
2609 case OP_LOADI4_MEMBASE:
2610 CASE_PPC64 (OP_LOADI8_MEMBASE)
2611 case OP_LOADU4_MEMBASE:
2612 case OP_LOADI2_MEMBASE:
2613 case OP_LOADU2_MEMBASE:
2614 case OP_LOADI1_MEMBASE:
2615 case OP_LOADU1_MEMBASE:
2616 case OP_LOADR4_MEMBASE:
2617 case OP_LOADR8_MEMBASE:
2618 case OP_STORE_MEMBASE_REG:
2619 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2620 case OP_STOREI4_MEMBASE_REG:
2621 case OP_STOREI2_MEMBASE_REG:
2622 case OP_STOREI1_MEMBASE_REG:
2623 case OP_STORER4_MEMBASE_REG:
2624 case OP_STORER8_MEMBASE_REG:
2625 /* we can do two things: load the immed in a register
2626 * and use an indexed load, or see if the immed can be
2627 * represented as an ad_imm + a load with a smaller offset
2628 * that fits. We just do the first for now, optimize later.
2630 if (ppc_is_imm16 (ins->inst_offset))
2632 NEW_INS (cfg, temp, OP_ICONST);
2633 temp->inst_c0 = ins->inst_offset;
2634 temp->dreg = mono_alloc_ireg (cfg);
2635 ins->sreg2 = temp->dreg;
2636 ins->opcode = map_to_reg_reg_op (ins->opcode);
2638 case OP_STORE_MEMBASE_IMM:
2639 case OP_STOREI1_MEMBASE_IMM:
2640 case OP_STOREI2_MEMBASE_IMM:
2641 case OP_STOREI4_MEMBASE_IMM:
2642 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2643 NEW_INS (cfg, temp, OP_ICONST);
2644 temp->inst_c0 = ins->inst_imm;
2645 temp->dreg = mono_alloc_ireg (cfg);
2646 ins->sreg1 = temp->dreg;
2647 ins->opcode = map_to_reg_reg_op (ins->opcode);
2649 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2652 if (cfg->compile_aot) {
2653 /* Keep these in the aot case */
2656 NEW_INS (cfg, temp, OP_ICONST);
2657 temp->inst_c0 = (gulong)ins->inst_p0;
2658 temp->dreg = mono_alloc_ireg (cfg);
2659 ins->inst_basereg = temp->dreg;
2660 ins->inst_offset = 0;
2661 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2663 /* make it handle the possibly big ins->inst_offset
2664 * later optimize to use lis + load_membase
2670 bb->last_ins = last_ins;
2671 bb->max_vreg = cfg->next_vreg;
2675 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2677 long offset = cfg->arch.fp_conv_var_offset;
2679 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2680 #ifdef __mono_ppc64__
2682 ppc_fctidz (code, ppc_f0, sreg);
2687 ppc_fctiwz (code, ppc_f0, sreg);
2690 if (ppc_is_imm16 (offset + sub_offset)) {
2691 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2693 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2695 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2697 ppc_load (code, dreg, offset);
2698 ppc_add (code, dreg, dreg, cfg->frame_reg);
2699 ppc_stfd (code, ppc_f0, 0, dreg);
2701 ppc_ldr (code, dreg, sub_offset, dreg);
2703 ppc_lwz (code, dreg, sub_offset, dreg);
2707 ppc_andid (code, dreg, dreg, 0xff);
2709 ppc_andid (code, dreg, dreg, 0xffff);
2710 #ifdef __mono_ppc64__
2712 ppc_clrldi (code, dreg, dreg, 32);
2716 ppc_extsb (code, dreg, dreg);
2718 ppc_extsh (code, dreg, dreg);
2719 #ifdef __mono_ppc64__
2721 ppc_extsw (code, dreg, dreg);
2729 const guchar *target;
2734 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2737 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2738 #ifdef __mono_ppc64__
2739 g_assert_not_reached ();
2741 PatchData *pdata = (PatchData*)user_data;
2742 guchar *code = data;
2743 guint32 *thunks = data;
2744 guint32 *endthunks = (guint32*)(code + bsize);
2748 int difflow, diffhigh;
2750 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2751 difflow = (char*)pdata->code - (char*)thunks;
2752 diffhigh = (char*)pdata->code - (char*)endthunks;
2753 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2756 templ = (guchar*)load;
2757 ppc_load_sequence (templ, ppc_r0, pdata->target);
2759 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2760 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2761 while (thunks < endthunks) {
2762 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2763 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2764 ppc_patch (pdata->code, (guchar*)thunks);
2767 static int num_thunks = 0;
2769 if ((num_thunks % 20) == 0)
2770 g_print ("num_thunks lookup: %d\n", num_thunks);
2773 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2774 /* found a free slot instead: emit thunk */
2775 code = (guchar*)thunks;
2776 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2777 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2778 ppc_mtctr (code, ppc_r0);
2779 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2780 mono_arch_flush_icache ((guchar*)thunks, 16);
2782 ppc_patch (pdata->code, (guchar*)thunks);
2785 static int num_thunks = 0;
2787 if ((num_thunks % 20) == 0)
2788 g_print ("num_thunks: %d\n", num_thunks);
2792 /* skip 16 bytes, the size of the thunk */
2796 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2803 handle_thunk (int absolute, guchar *code, const guchar *target) {
2804 MonoDomain *domain = mono_domain_get ();
2808 pdata.target = target;
2809 pdata.absolute = absolute;
2812 mono_domain_lock (domain);
2813 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2816 /* this uses the first available slot */
2818 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2820 mono_domain_unlock (domain);
2822 if (pdata.found != 1)
2823 g_print ("thunk failed for %p from %p\n", target, code);
2824 g_assert (pdata.found == 1);
2828 patch_ins (guint8 *code, guint32 ins)
2830 *(guint32*)code = ins;
2831 mono_arch_flush_icache (code, 4);
2835 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2837 guint32 ins = *(guint32*)code;
2838 guint32 prim = ins >> 26;
2841 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2843 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2844 gint diff = target - code;
2847 if (diff <= 33554431){
2848 ins = (18 << 26) | (diff) | (ins & 1);
2849 patch_ins (code, ins);
2853 /* diff between 0 and -33554432 */
2854 if (diff >= -33554432){
2855 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2856 patch_ins (code, ins);
2861 if ((glong)target >= 0){
2862 if ((glong)target <= 33554431){
2863 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2864 patch_ins (code, ins);
2868 if ((glong)target >= -33554432){
2869 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2870 patch_ins (code, ins);
2875 handle_thunk (TRUE, code, target);
2878 g_assert_not_reached ();
2886 guint32 li = (gulong)target;
2887 ins = (ins & 0xffff0000) | (ins & 3);
2888 ovf = li & 0xffff0000;
2889 if (ovf != 0 && ovf != 0xffff0000)
2890 g_assert_not_reached ();
2893 // FIXME: assert the top bits of li are 0
2895 gint diff = target - code;
2896 ins = (ins & 0xffff0000) | (ins & 3);
2897 ovf = diff & 0xffff0000;
2898 if (ovf != 0 && ovf != 0xffff0000)
2899 g_assert_not_reached ();
2903 patch_ins (code, ins);
2907 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2908 #ifdef __mono_ppc64__
2909 guint32 *seq = (guint32*)code;
2910 guint32 *branch_ins;
2912 /* the trampoline code will try to patch the blrl, blr, bcctr */
2913 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2915 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2920 if (ppc_is_load_op (seq [5])
2921 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2922 /* With function descs we need to do more careful
2924 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
2927 branch_ins = seq + 8;
2929 branch_ins = seq + 6;
2932 seq = (guint32*)code;
2933 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2934 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2936 if (ppc_is_load_op (seq [5])) {
2937 g_assert (ppc_is_load_op (seq [6]));
2940 guint8 *buf = (guint8*)&seq [5];
2941 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
2946 target = mono_get_addr_from_ftnptr ((gpointer)target);
2949 /* FIXME: make this thread safe */
2950 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2951 /* FIXME: we're assuming we're using r12 here */
2952 ppc_load_ptr_sequence (code, ppc_r12, target);
2954 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
2956 mono_arch_flush_icache ((guint8*)seq, 28);
2959 /* the trampoline code will try to patch the blrl, blr, bcctr */
2960 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2963 /* this is the lis/ori/mtlr/blrl sequence */
2964 seq = (guint32*)code;
2965 g_assert ((seq [0] >> 26) == 15);
2966 g_assert ((seq [1] >> 26) == 24);
2967 g_assert ((seq [2] >> 26) == 31);
2968 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2969 /* FIXME: make this thread safe */
2970 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
2971 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
2972 mono_arch_flush_icache (code - 8, 8);
2975 g_assert_not_reached ();
2977 // g_print ("patched with 0x%08x\n", ins);
2981 ppc_patch (guchar *code, const guchar *target)
2983 ppc_patch_full (code, target, FALSE);
2987 mono_ppc_patch (guchar *code, const guchar *target)
2989 ppc_patch (code, target);
2993 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2995 switch (ins->opcode) {
2998 case OP_FCALL_MEMBASE:
2999 if (ins->dreg != ppc_f1)
3000 ppc_fmr (code, ins->dreg, ppc_f1);
3008 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3010 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3014 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3016 long size = cfg->param_area;
3018 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3019 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3024 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3025 if (ppc_is_imm16 (-size)) {
3026 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3028 ppc_load (code, ppc_r12, -size);
3029 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3036 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3038 long size = cfg->param_area;
3040 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3041 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3046 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3047 if (ppc_is_imm16 (size)) {
3048 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3050 ppc_load (code, ppc_r12, size);
3051 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3057 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3061 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3063 MonoInst *ins, *next;
3066 guint8 *code = cfg->native_code + cfg->code_len;
3067 MonoInst *last_ins = NULL;
3068 guint last_offset = 0;
3072 /* we don't align basic blocks of loops on ppc */
3074 if (cfg->verbose_level > 2)
3075 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3077 cpos = bb->max_offset;
3079 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3080 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3081 //g_assert (!mono_compile_aot);
3084 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3085 /* this is not thread save, but good enough */
3086 /* fixme: howto handle overflows? */
3087 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3090 MONO_BB_FOR_EACH_INS (bb, ins) {
3091 offset = code - cfg->native_code;
3093 max_len = ins_native_length (cfg, ins);
3095 if (offset > (cfg->code_size - max_len - 16)) {
3096 cfg->code_size *= 2;
3097 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3098 code = cfg->native_code + offset;
3100 // if (ins->cil_code)
3101 // g_print ("cil code\n");
3102 mono_debug_record_line_number (cfg, ins, offset);
3104 switch (normalize_opcode (ins->opcode)) {
3105 case OP_RELAXED_NOP:
3108 case OP_DUMMY_STORE:
3109 case OP_NOT_REACHED:
3112 case OP_IL_SEQ_POINT:
3113 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3115 case OP_SEQ_POINT: {
3118 if (cfg->compile_aot)
3122 * Read from the single stepping trigger page. This will cause a
3123 * SIGSEGV when single stepping is enabled.
3124 * We do this _before_ the breakpoint, so single stepping after
3125 * a breakpoint is hit will step to the next IL offset.
3127 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3128 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3129 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3132 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3135 * A placeholder for a possible breakpoint inserted by
3136 * mono_arch_set_breakpoint ().
3138 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3143 emit_tls_access (code, ins->dreg, ins->inst_offset);
3146 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3147 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3148 ppc_mr (code, ppc_r4, ppc_r0);
3151 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3152 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3153 ppc_mr (code, ppc_r4, ppc_r0);
3155 case OP_MEMORY_BARRIER:
3158 case OP_STOREI1_MEMBASE_REG:
3159 if (ppc_is_imm16 (ins->inst_offset)) {
3160 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3162 if (ppc_is_imm32 (ins->inst_offset)) {
3163 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3164 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3166 ppc_load (code, ppc_r0, ins->inst_offset);
3167 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3171 case OP_STOREI2_MEMBASE_REG:
3172 if (ppc_is_imm16 (ins->inst_offset)) {
3173 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3175 if (ppc_is_imm32 (ins->inst_offset)) {
3176 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3177 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3179 ppc_load (code, ppc_r0, ins->inst_offset);
3180 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3184 case OP_STORE_MEMBASE_REG:
3185 if (ppc_is_imm16 (ins->inst_offset)) {
3186 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3188 if (ppc_is_imm32 (ins->inst_offset)) {
3189 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3190 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3192 ppc_load (code, ppc_r0, ins->inst_offset);
3193 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3197 #ifdef __mono_ilp32__
3198 case OP_STOREI8_MEMBASE_REG:
3199 if (ppc_is_imm16 (ins->inst_offset)) {
3200 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3202 ppc_load (code, ppc_r0, ins->inst_offset);
3203 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3207 case OP_STOREI1_MEMINDEX:
3208 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3210 case OP_STOREI2_MEMINDEX:
3211 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3213 case OP_STORE_MEMINDEX:
3214 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3217 g_assert_not_reached ();
3219 case OP_LOAD_MEMBASE:
3220 if (ppc_is_imm16 (ins->inst_offset)) {
3221 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3223 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3224 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3225 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3227 ppc_load (code, ppc_r0, ins->inst_offset);
3228 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3232 case OP_LOADI4_MEMBASE:
3233 #ifdef __mono_ppc64__
3234 if (ppc_is_imm16 (ins->inst_offset)) {
3235 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3237 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3238 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3239 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3241 ppc_load (code, ppc_r0, ins->inst_offset);
3242 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3247 case OP_LOADU4_MEMBASE:
3248 if (ppc_is_imm16 (ins->inst_offset)) {
3249 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3251 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3252 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3253 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3255 ppc_load (code, ppc_r0, ins->inst_offset);
3256 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3260 case OP_LOADI1_MEMBASE:
3261 case OP_LOADU1_MEMBASE:
3262 if (ppc_is_imm16 (ins->inst_offset)) {
3263 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3265 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3266 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3267 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3269 ppc_load (code, ppc_r0, ins->inst_offset);
3270 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3273 if (ins->opcode == OP_LOADI1_MEMBASE)
3274 ppc_extsb (code, ins->dreg, ins->dreg);
3276 case OP_LOADU2_MEMBASE:
3277 if (ppc_is_imm16 (ins->inst_offset)) {
3278 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3280 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3281 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3282 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3284 ppc_load (code, ppc_r0, ins->inst_offset);
3285 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3289 case OP_LOADI2_MEMBASE:
3290 if (ppc_is_imm16 (ins->inst_offset)) {
3291 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3293 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3294 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3295 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3297 ppc_load (code, ppc_r0, ins->inst_offset);
3298 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3302 #ifdef __mono_ilp32__
3303 case OP_LOADI8_MEMBASE:
3304 if (ppc_is_imm16 (ins->inst_offset)) {
3305 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3307 ppc_load (code, ppc_r0, ins->inst_offset);
3308 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3312 case OP_LOAD_MEMINDEX:
3313 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3315 case OP_LOADI4_MEMINDEX:
3316 #ifdef __mono_ppc64__
3317 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3320 case OP_LOADU4_MEMINDEX:
3321 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3323 case OP_LOADU2_MEMINDEX:
3324 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3326 case OP_LOADI2_MEMINDEX:
3327 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3329 case OP_LOADU1_MEMINDEX:
3330 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3332 case OP_LOADI1_MEMINDEX:
3333 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3334 ppc_extsb (code, ins->dreg, ins->dreg);
3336 case OP_ICONV_TO_I1:
3337 CASE_PPC64 (OP_LCONV_TO_I1)
3338 ppc_extsb (code, ins->dreg, ins->sreg1);
3340 case OP_ICONV_TO_I2:
3341 CASE_PPC64 (OP_LCONV_TO_I2)
3342 ppc_extsh (code, ins->dreg, ins->sreg1);
3344 case OP_ICONV_TO_U1:
3345 CASE_PPC64 (OP_LCONV_TO_U1)
3346 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3348 case OP_ICONV_TO_U2:
3349 CASE_PPC64 (OP_LCONV_TO_U2)
3350 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3354 CASE_PPC64 (OP_LCOMPARE)
3355 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3357 if (next && compare_opcode_is_unsigned (next->opcode))
3358 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3360 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3362 case OP_COMPARE_IMM:
3363 case OP_ICOMPARE_IMM:
3364 CASE_PPC64 (OP_LCOMPARE_IMM)
3365 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3367 if (next && compare_opcode_is_unsigned (next->opcode)) {
3368 if (ppc_is_uimm16 (ins->inst_imm)) {
3369 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3371 g_assert_not_reached ();
3374 if (ppc_is_imm16 (ins->inst_imm)) {
3375 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3377 g_assert_not_reached ();
3383 * gdb does not like encountering a trap in the debugged code. So
3384 * instead of emitting a trap, we emit a call a C function and place a
3388 ppc_mr (code, ppc_r3, ins->sreg1);
3389 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3390 (gpointer)"mono_break");
3391 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3392 ppc_load_func (code, PPC_CALL_REG, 0);
3393 ppc_mtlr (code, PPC_CALL_REG);
3401 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3404 CASE_PPC64 (OP_LADD)
3405 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3409 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3412 if (ppc_is_imm16 (ins->inst_imm)) {
3413 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3415 g_assert_not_reached ();
3420 CASE_PPC64 (OP_LADD_IMM)
3421 if (ppc_is_imm16 (ins->inst_imm)) {
3422 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3424 g_assert_not_reached ();
3428 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3430 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3431 ppc_mfspr (code, ppc_r0, ppc_xer);
3432 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3433 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3435 case OP_IADD_OVF_UN:
3436 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3438 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3439 ppc_mfspr (code, ppc_r0, ppc_xer);
3440 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3441 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3444 CASE_PPC64 (OP_LSUB_OVF)
3445 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3447 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3448 ppc_mfspr (code, ppc_r0, ppc_xer);
3449 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3450 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3452 case OP_ISUB_OVF_UN:
3453 CASE_PPC64 (OP_LSUB_OVF_UN)
3454 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3456 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3457 ppc_mfspr (code, ppc_r0, ppc_xer);
3458 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3459 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3461 case OP_ADD_OVF_CARRY:
3462 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3464 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3465 ppc_mfspr (code, ppc_r0, ppc_xer);
3466 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3467 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3469 case OP_ADD_OVF_UN_CARRY:
3470 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3472 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3473 ppc_mfspr (code, ppc_r0, ppc_xer);
3474 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3475 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3477 case OP_SUB_OVF_CARRY:
3478 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3480 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3481 ppc_mfspr (code, ppc_r0, ppc_xer);
3482 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3483 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3485 case OP_SUB_OVF_UN_CARRY:
3486 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3488 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3489 ppc_mfspr (code, ppc_r0, ppc_xer);
3490 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3491 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3495 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3498 CASE_PPC64 (OP_LSUB)
3499 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3503 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3507 CASE_PPC64 (OP_LSUB_IMM)
3508 // we add the negated value
3509 if (ppc_is_imm16 (-ins->inst_imm))
3510 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3512 g_assert_not_reached ();
3516 g_assert (ppc_is_imm16 (ins->inst_imm));
3517 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3520 ppc_subfze (code, ins->dreg, ins->sreg1);
3523 CASE_PPC64 (OP_LAND)
3524 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3525 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3529 CASE_PPC64 (OP_LAND_IMM)
3530 if (!(ins->inst_imm & 0xffff0000)) {
3531 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3532 } else if (!(ins->inst_imm & 0xffff)) {
3533 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3535 g_assert_not_reached ();
3539 CASE_PPC64 (OP_LDIV) {
3540 guint8 *divisor_is_m1;
3541 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3543 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3544 divisor_is_m1 = code;
3545 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3546 ppc_lis (code, ppc_r0, 0x8000);
3547 #ifdef __mono_ppc64__
3548 if (ins->opcode == OP_LDIV)
3549 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3551 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3552 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3553 ppc_patch (divisor_is_m1, code);
3554 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3556 if (ins->opcode == OP_IDIV)
3557 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3558 #ifdef __mono_ppc64__
3560 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3562 ppc_mfspr (code, ppc_r0, ppc_xer);
3563 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3564 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3568 CASE_PPC64 (OP_LDIV_UN)
3569 if (ins->opcode == OP_IDIV_UN)
3570 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3571 #ifdef __mono_ppc64__
3573 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3575 ppc_mfspr (code, ppc_r0, ppc_xer);
3576 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3577 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3583 g_assert_not_reached ();
3586 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3590 CASE_PPC64 (OP_LOR_IMM)
3591 if (!(ins->inst_imm & 0xffff0000)) {
3592 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3593 } else if (!(ins->inst_imm & 0xffff)) {
3594 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3596 g_assert_not_reached ();
3600 CASE_PPC64 (OP_LXOR)
3601 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3605 CASE_PPC64 (OP_LXOR_IMM)
3606 if (!(ins->inst_imm & 0xffff0000)) {
3607 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3608 } else if (!(ins->inst_imm & 0xffff)) {
3609 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3611 g_assert_not_reached ();
3615 CASE_PPC64 (OP_LSHL)
3616 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 CASE_PPC64 (OP_LSHL_IMM)
3621 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3624 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3630 if (MASK_SHIFT_IMM (ins->inst_imm))
3631 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3633 ppc_mr (code, ins->dreg, ins->sreg1);
3636 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3639 CASE_PPC64 (OP_LNOT)
3640 ppc_not (code, ins->dreg, ins->sreg1);
3643 CASE_PPC64 (OP_LNEG)
3644 ppc_neg (code, ins->dreg, ins->sreg1);
3647 CASE_PPC64 (OP_LMUL)
3648 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3652 CASE_PPC64 (OP_LMUL_IMM)
3653 if (ppc_is_imm16 (ins->inst_imm)) {
3654 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3656 g_assert_not_reached ();
3660 CASE_PPC64 (OP_LMUL_OVF)
3661 /* we annot use mcrxr, since it's not implemented on some processors
3662 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3664 if (ins->opcode == OP_IMUL_OVF)
3665 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3666 #ifdef __mono_ppc64__
3668 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3670 ppc_mfspr (code, ppc_r0, ppc_xer);
3671 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3672 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3674 case OP_IMUL_OVF_UN:
3675 CASE_PPC64 (OP_LMUL_OVF_UN)
3676 /* we first multiply to get the high word and compare to 0
3677 * to set the flags, then the result is discarded and then
3678 * we multiply to get the lower * bits result
3680 if (ins->opcode == OP_IMUL_OVF_UN)
3681 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3682 #ifdef __mono_ppc64__
3684 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3686 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3687 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3688 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3691 ppc_load (code, ins->dreg, ins->inst_c0);
3694 ppc_load (code, ins->dreg, ins->inst_l);
3697 case OP_LOAD_GOTADDR:
3698 /* The PLT implementation depends on this */
3699 g_assert (ins->dreg == ppc_r30);
3701 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3704 // FIXME: Fix max instruction length
3705 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3706 /* arch_emit_got_access () patches this */
3707 ppc_load32 (code, ppc_r0, 0);
3708 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3711 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3712 ppc_load_sequence (code, ins->dreg, 0);
3714 CASE_PPC32 (OP_ICONV_TO_I4)
3715 CASE_PPC32 (OP_ICONV_TO_U4)
3717 if (ins->dreg != ins->sreg1)
3718 ppc_mr (code, ins->dreg, ins->sreg1);
3721 int saved = ins->sreg1;
3722 if (ins->sreg1 == ppc_r3) {
3723 ppc_mr (code, ppc_r0, ins->sreg1);
3726 if (ins->sreg2 != ppc_r3)
3727 ppc_mr (code, ppc_r3, ins->sreg2);
3728 if (saved != ppc_r4)
3729 ppc_mr (code, ppc_r4, saved);
3733 if (ins->dreg != ins->sreg1)
3734 ppc_fmr (code, ins->dreg, ins->sreg1);
3736 case OP_FCONV_TO_R4:
3737 ppc_frsp (code, ins->dreg, ins->sreg1);
3741 MonoCallInst *call = (MonoCallInst*)ins;
3744 * Keep in sync with mono_arch_emit_epilog
3746 g_assert (!cfg->method->save_lmf);
3748 * Note: we can use ppc_r12 here because it is dead anyway:
3749 * we're leaving the method.
3751 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3752 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3753 if (ppc_is_imm16 (ret_offset)) {
3754 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3756 ppc_load (code, ppc_r12, ret_offset);
3757 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3759 ppc_mtlr (code, ppc_r0);
3762 if (ppc_is_imm16 (cfg->stack_usage)) {
3763 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3765 /* cfg->stack_usage is an int, so we can use
3766 * an addis/addi sequence here even in 64-bit. */
3767 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3768 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3770 if (!cfg->method->save_lmf) {
3772 for (i = 31; i >= 13; --i) {
3773 if (cfg->used_int_regs & (1 << i)) {
3774 pos += sizeof (gpointer);
3775 ppc_ldptr (code, i, -pos, ppc_r12);
3779 /* FIXME restore from MonoLMF: though this can't happen yet */
3782 /* Copy arguments on the stack to our argument area */
3783 if (call->stack_usage) {
3784 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3785 /* r12 was clobbered */
3786 g_assert (cfg->frame_reg == ppc_sp);
3787 if (ppc_is_imm16 (cfg->stack_usage)) {
3788 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3790 /* cfg->stack_usage is an int, so we can use
3791 * an addis/addi sequence here even in 64-bit. */
3792 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3793 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3797 ppc_mr (code, ppc_sp, ppc_r12);
3798 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3799 if (cfg->compile_aot) {
3800 /* arch_emit_got_access () patches this */
3801 ppc_load32 (code, ppc_r0, 0);
3802 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3803 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3804 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3806 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3808 ppc_mtctr (code, ppc_r0);
3809 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3816 /* ensure ins->sreg1 is not NULL */
3817 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3820 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3821 if (ppc_is_imm16 (cookie_offset)) {
3822 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3824 ppc_load (code, ppc_r0, cookie_offset);
3825 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3827 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3836 call = (MonoCallInst*)ins;
3837 if (ins->flags & MONO_INST_HAS_METHOD)
3838 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3840 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3841 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3842 ppc_load_func (code, PPC_CALL_REG, 0);
3843 ppc_mtlr (code, PPC_CALL_REG);
3848 /* FIXME: this should be handled somewhere else in the new jit */
3849 code = emit_move_return_value (cfg, ins, code);
3855 case OP_VOIDCALL_REG:
3857 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3858 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3859 /* FIXME: if we know that this is a method, we
3860 can omit this load */
3861 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3862 ppc_mtlr (code, ppc_r0);
3864 ppc_mtlr (code, ins->sreg1);
3867 /* FIXME: this should be handled somewhere else in the new jit */
3868 code = emit_move_return_value (cfg, ins, code);
3870 case OP_FCALL_MEMBASE:
3871 case OP_LCALL_MEMBASE:
3872 case OP_VCALL_MEMBASE:
3873 case OP_VCALL2_MEMBASE:
3874 case OP_VOIDCALL_MEMBASE:
3875 case OP_CALL_MEMBASE:
3876 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3877 /* The trampolines clobber this */
3878 ppc_mr (code, ppc_r29, ins->sreg1);
3879 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3881 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3883 ppc_mtlr (code, ppc_r0);
3885 /* FIXME: this should be handled somewhere else in the new jit */
3886 code = emit_move_return_value (cfg, ins, code);
3889 guint8 * zero_loop_jump, * zero_loop_start;
3890 /* keep alignment */
3891 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3892 int area_offset = alloca_waste;
3894 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3895 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3896 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3897 /* use ctr to store the number of words to 0 if needed */
3898 if (ins->flags & MONO_INST_INIT) {
3899 /* we zero 4 bytes at a time:
3900 * we add 7 instead of 3 so that we set the counter to
3901 * at least 1, otherwise the bdnz instruction will make
3902 * it negative and iterate billions of times.
3904 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3905 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3906 ppc_mtctr (code, ppc_r0);
3908 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3909 ppc_neg (code, ppc_r12, ppc_r12);
3910 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3912 /* FIXME: make this loop work in 8 byte
3913 increments on PPC64 */
3914 if (ins->flags & MONO_INST_INIT) {
3915 /* adjust the dest reg by -4 so we can use stwu */
3916 /* we actually adjust -8 because we let the loop
3919 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3920 ppc_li (code, ppc_r12, 0);
3921 zero_loop_start = code;
3922 ppc_stwu (code, ppc_r12, 4, ins->dreg);
3923 zero_loop_jump = code;
3924 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3925 ppc_patch (zero_loop_jump, zero_loop_start);
3927 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3932 ppc_mr (code, ppc_r3, ins->sreg1);
3933 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3934 (gpointer)"mono_arch_throw_exception");
3935 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3936 ppc_load_func (code, PPC_CALL_REG, 0);
3937 ppc_mtlr (code, PPC_CALL_REG);
3946 ppc_mr (code, ppc_r3, ins->sreg1);
3947 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3948 (gpointer)"mono_arch_rethrow_exception");
3949 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3950 ppc_load_func (code, PPC_CALL_REG, 0);
3951 ppc_mtlr (code, PPC_CALL_REG);
3958 case OP_START_HANDLER: {
3959 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3960 g_assert (spvar->inst_basereg != ppc_sp);
3961 code = emit_reserve_param_area (cfg, code);
3962 ppc_mflr (code, ppc_r0);
3963 if (ppc_is_imm16 (spvar->inst_offset)) {
3964 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3966 ppc_load (code, ppc_r12, spvar->inst_offset);
3967 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
3971 case OP_ENDFILTER: {
3972 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3973 g_assert (spvar->inst_basereg != ppc_sp);
3974 code = emit_unreserve_param_area (cfg, code);
3975 if (ins->sreg1 != ppc_r3)
3976 ppc_mr (code, ppc_r3, ins->sreg1);
3977 if (ppc_is_imm16 (spvar->inst_offset)) {
3978 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3980 ppc_load (code, ppc_r12, spvar->inst_offset);
3981 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
3983 ppc_mtlr (code, ppc_r0);
3987 case OP_ENDFINALLY: {
3988 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3989 g_assert (spvar->inst_basereg != ppc_sp);
3990 code = emit_unreserve_param_area (cfg, code);
3991 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3992 ppc_mtlr (code, ppc_r0);
3996 case OP_CALL_HANDLER:
3997 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3999 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4002 ins->inst_c0 = code - cfg->native_code;
4005 /*if (ins->inst_target_bb->native_offset) {
4007 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4009 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4014 ppc_mtctr (code, ins->sreg1);
4015 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4019 CASE_PPC64 (OP_LCEQ)
4020 ppc_li (code, ins->dreg, 0);
4021 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4022 ppc_li (code, ins->dreg, 1);
4028 CASE_PPC64 (OP_LCLT)
4029 CASE_PPC64 (OP_LCLT_UN)
4030 ppc_li (code, ins->dreg, 1);
4031 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4032 ppc_li (code, ins->dreg, 0);
4038 CASE_PPC64 (OP_LCGT)
4039 CASE_PPC64 (OP_LCGT_UN)
4040 ppc_li (code, ins->dreg, 1);
4041 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4042 ppc_li (code, ins->dreg, 0);
4044 case OP_COND_EXC_EQ:
4045 case OP_COND_EXC_NE_UN:
4046 case OP_COND_EXC_LT:
4047 case OP_COND_EXC_LT_UN:
4048 case OP_COND_EXC_GT:
4049 case OP_COND_EXC_GT_UN:
4050 case OP_COND_EXC_GE:
4051 case OP_COND_EXC_GE_UN:
4052 case OP_COND_EXC_LE:
4053 case OP_COND_EXC_LE_UN:
4054 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4056 case OP_COND_EXC_IEQ:
4057 case OP_COND_EXC_INE_UN:
4058 case OP_COND_EXC_ILT:
4059 case OP_COND_EXC_ILT_UN:
4060 case OP_COND_EXC_IGT:
4061 case OP_COND_EXC_IGT_UN:
4062 case OP_COND_EXC_IGE:
4063 case OP_COND_EXC_IGE_UN:
4064 case OP_COND_EXC_ILE:
4065 case OP_COND_EXC_ILE_UN:
4066 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4078 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4081 /* floating point opcodes */
4083 g_assert (cfg->compile_aot);
4085 /* FIXME: Optimize this */
4087 ppc_mflr (code, ppc_r12);
4089 *(double*)code = *(double*)ins->inst_p0;
4091 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4094 g_assert_not_reached ();
4096 case OP_STORER8_MEMBASE_REG:
4097 if (ppc_is_imm16 (ins->inst_offset)) {
4098 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4100 if (ppc_is_imm32 (ins->inst_offset)) {
4101 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4102 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4104 ppc_load (code, ppc_r0, ins->inst_offset);
4105 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4109 case OP_LOADR8_MEMBASE:
4110 if (ppc_is_imm16 (ins->inst_offset)) {
4111 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4113 if (ppc_is_imm32 (ins->inst_offset)) {
4114 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4115 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4117 ppc_load (code, ppc_r0, ins->inst_offset);
4118 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4122 case OP_STORER4_MEMBASE_REG:
4123 ppc_frsp (code, ins->sreg1, ins->sreg1);
4124 if (ppc_is_imm16 (ins->inst_offset)) {
4125 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4127 if (ppc_is_imm32 (ins->inst_offset)) {
4128 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4129 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4131 ppc_load (code, ppc_r0, ins->inst_offset);
4132 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4136 case OP_LOADR4_MEMBASE:
4137 if (ppc_is_imm16 (ins->inst_offset)) {
4138 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4140 if (ppc_is_imm32 (ins->inst_offset)) {
4141 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4142 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4144 ppc_load (code, ppc_r0, ins->inst_offset);
4145 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4149 case OP_LOADR4_MEMINDEX:
4150 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4152 case OP_LOADR8_MEMINDEX:
4153 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4155 case OP_STORER4_MEMINDEX:
4156 ppc_frsp (code, ins->sreg1, ins->sreg1);
4157 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4159 case OP_STORER8_MEMINDEX:
4160 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4163 case CEE_CONV_R4: /* FIXME: change precision */
4165 g_assert_not_reached ();
4166 case OP_FCONV_TO_I1:
4167 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4169 case OP_FCONV_TO_U1:
4170 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4172 case OP_FCONV_TO_I2:
4173 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4175 case OP_FCONV_TO_U2:
4176 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4178 case OP_FCONV_TO_I4:
4180 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4182 case OP_FCONV_TO_U4:
4184 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4186 case OP_LCONV_TO_R_UN:
4187 g_assert_not_reached ();
4188 /* Implemented as helper calls */
4190 case OP_LCONV_TO_OVF_I4_2:
4191 case OP_LCONV_TO_OVF_I: {
4192 #ifdef __mono_ppc64__
4195 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4196 // Check if its negative
4197 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4198 negative_branch = code;
4199 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4200 // Its positive msword == 0
4201 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4202 msword_positive_branch = code;
4203 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4205 ovf_ex_target = code;
4206 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4208 ppc_patch (negative_branch, code);
4209 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4210 msword_negative_branch = code;
4211 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4212 ppc_patch (msword_negative_branch, ovf_ex_target);
4214 ppc_patch (msword_positive_branch, code);
4215 if (ins->dreg != ins->sreg1)
4216 ppc_mr (code, ins->dreg, ins->sreg1);
4221 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4224 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4227 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4230 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4233 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4236 ppc_fneg (code, ins->dreg, ins->sreg1);
4240 g_assert_not_reached ();
4243 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4246 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4247 ppc_li (code, ins->dreg, 0);
4248 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4249 ppc_li (code, ins->dreg, 1);
4252 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4253 ppc_li (code, ins->dreg, 1);
4254 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4255 ppc_li (code, ins->dreg, 0);
4258 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4259 ppc_li (code, ins->dreg, 1);
4260 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4261 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4262 ppc_li (code, ins->dreg, 0);
4265 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4266 ppc_li (code, ins->dreg, 1);
4267 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4268 ppc_li (code, ins->dreg, 0);
4271 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4272 ppc_li (code, ins->dreg, 1);
4273 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4274 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4275 ppc_li (code, ins->dreg, 0);
4278 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4281 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4284 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4285 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4288 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4289 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4292 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4293 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4296 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4297 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4300 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4301 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4304 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4307 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4308 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4311 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4314 g_assert_not_reached ();
4315 case OP_CHECK_FINITE: {
4316 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4317 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4318 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4319 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4322 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4323 #ifdef __mono_ppc64__
4324 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4326 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4331 #ifdef __mono_ppc64__
4332 case OP_ICONV_TO_I4:
4334 ppc_extsw (code, ins->dreg, ins->sreg1);
4336 case OP_ICONV_TO_U4:
4338 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4340 case OP_ICONV_TO_R4:
4341 case OP_ICONV_TO_R8:
4342 case OP_LCONV_TO_R4:
4343 case OP_LCONV_TO_R8: {
4345 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4346 ppc_extsw (code, ppc_r0, ins->sreg1);
4351 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4352 ppc_mffgpr (code, ins->dreg, tmp);
4354 ppc_str (code, tmp, -8, ppc_r1);
4355 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4357 ppc_fcfid (code, ins->dreg, ins->dreg);
4358 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4359 ppc_frsp (code, ins->dreg, ins->dreg);
4363 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4366 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4369 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4371 ppc_mfspr (code, ppc_r0, ppc_xer);
4372 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4373 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4375 case OP_COND_EXC_OV:
4376 ppc_mfspr (code, ppc_r0, ppc_xer);
4377 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4378 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4390 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4392 case OP_FCONV_TO_I8:
4393 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4395 case OP_FCONV_TO_U8:
4396 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4398 case OP_STOREI4_MEMBASE_REG:
4399 if (ppc_is_imm16 (ins->inst_offset)) {
4400 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4402 ppc_load (code, ppc_r0, ins->inst_offset);
4403 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4406 case OP_STOREI4_MEMINDEX:
4407 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4410 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4412 case OP_ISHR_UN_IMM:
4413 if (ins->inst_imm & 0x1f)
4414 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4416 ppc_mr (code, ins->dreg, ins->sreg1);
4418 case OP_ATOMIC_ADD_I4:
4419 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4420 int location = ins->inst_basereg;
4421 int addend = ins->sreg2;
4422 guint8 *loop, *branch;
4423 g_assert (ins->inst_offset == 0);
4427 if (ins->opcode == OP_ATOMIC_ADD_I4)
4428 ppc_lwarx (code, ppc_r0, 0, location);
4429 #ifdef __mono_ppc64__
4431 ppc_ldarx (code, ppc_r0, 0, location);
4434 ppc_add (code, ppc_r0, ppc_r0, addend);
4436 if (ins->opcode == OP_ATOMIC_ADD_I4)
4437 ppc_stwcxd (code, ppc_r0, 0, location);
4438 #ifdef __mono_ppc64__
4440 ppc_stdcxd (code, ppc_r0, 0, location);
4444 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4445 ppc_patch (branch, loop);
4448 ppc_mr (code, ins->dreg, ppc_r0);
4452 case OP_ICONV_TO_R4:
4453 case OP_ICONV_TO_R8: {
4454 if (cpu_hw_caps & PPC_ISA_64) {
4455 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4456 ppc_stw (code, ppc_r0, -8, ppc_r1);
4457 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4458 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4459 ppc_fcfid (code, ins->dreg, ins->dreg);
4460 if (ins->opcode == OP_ICONV_TO_R4)
4461 ppc_frsp (code, ins->dreg, ins->dreg);
4466 case OP_ATOMIC_CAS_I4:
4467 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4468 int location = ins->sreg1;
4469 int value = ins->sreg2;
4470 int comparand = ins->sreg3;
4471 guint8 *start, *not_equal, *lost_reservation;
4475 if (ins->opcode == OP_ATOMIC_CAS_I4)
4476 ppc_lwarx (code, ppc_r0, 0, location);
4477 #ifdef __mono_ppc64__
4479 ppc_ldarx (code, ppc_r0, 0, location);
4482 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4484 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4486 if (ins->opcode == OP_ATOMIC_CAS_I4)
4487 ppc_stwcxd (code, value, 0, location);
4488 #ifdef __mono_ppc64__
4490 ppc_stdcxd (code, value, 0, location);
4493 lost_reservation = code;
4494 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4495 ppc_patch (lost_reservation, start);
4496 ppc_patch (not_equal, code);
4499 ppc_mr (code, ins->dreg, ppc_r0);
4504 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4505 g_assert_not_reached ();
4508 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4509 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4510 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4511 g_assert_not_reached ();
4517 last_offset = offset;
4520 cfg->code_len = code - cfg->native_code;
4522 #endif /* !DISABLE_JIT */
4525 mono_arch_register_lowlevel_calls (void)
4527 /* The signature doesn't matter */
4528 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4531 #ifdef __mono_ppc64__
4532 #ifdef _LITTLE_ENDIAN
4533 #define patch_load_sequence(ip,val) do {\
4534 guint16 *__load = (guint16*)(ip); \
4535 g_assert (sizeof (val) == sizeof (gsize)); \
4536 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4537 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4538 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4539 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4541 #elif defined _BIG_ENDIAN
4542 #define patch_load_sequence(ip,val) do {\
4543 guint16 *__load = (guint16*)(ip); \
4544 g_assert (sizeof (val) == sizeof (gsize)); \
4545 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4546 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4547 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4548 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4551 #error huh? No endianess defined by compiler
4554 #define patch_load_sequence(ip,val) do {\
4555 guint16 *__lis_ori = (guint16*)(ip); \
4556 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4557 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4563 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4565 MonoJumpInfo *patch_info;
4566 gboolean compile_aot = !run_cctors;
4568 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4569 unsigned char *ip = patch_info->ip.i + code;
4570 unsigned char *target;
4571 gboolean is_fd = FALSE;
4573 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4576 switch (patch_info->type) {
4577 case MONO_PATCH_INFO_BB:
4578 case MONO_PATCH_INFO_LABEL:
4581 /* No need to patch these */
4586 switch (patch_info->type) {
4587 case MONO_PATCH_INFO_IP:
4588 patch_load_sequence (ip, ip);
4590 case MONO_PATCH_INFO_METHOD_REL:
4591 g_assert_not_reached ();
4592 *((gpointer *)(ip)) = code + patch_info->data.offset;
4594 case MONO_PATCH_INFO_SWITCH: {
4595 gpointer *table = (gpointer *)patch_info->data.table->table;
4598 patch_load_sequence (ip, table);
4600 for (i = 0; i < patch_info->data.table->table_size; i++) {
4601 table [i] = (glong)patch_info->data.table->table [i] + code;
4603 /* we put into the table the absolute address, no need for ppc_patch in this case */
4606 case MONO_PATCH_INFO_METHODCONST:
4607 case MONO_PATCH_INFO_CLASS:
4608 case MONO_PATCH_INFO_IMAGE:
4609 case MONO_PATCH_INFO_FIELD:
4610 case MONO_PATCH_INFO_VTABLE:
4611 case MONO_PATCH_INFO_IID:
4612 case MONO_PATCH_INFO_SFLDA:
4613 case MONO_PATCH_INFO_LDSTR:
4614 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4615 case MONO_PATCH_INFO_LDTOKEN:
4616 /* from OP_AOTCONST : lis + ori */
4617 patch_load_sequence (ip, target);
4619 case MONO_PATCH_INFO_R4:
4620 case MONO_PATCH_INFO_R8:
4621 g_assert_not_reached ();
4622 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4624 case MONO_PATCH_INFO_EXC_NAME:
4625 g_assert_not_reached ();
4626 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4628 case MONO_PATCH_INFO_NONE:
4629 case MONO_PATCH_INFO_BB_OVF:
4630 case MONO_PATCH_INFO_EXC_OVF:
4631 /* everything is dealt with at epilog output time */
4633 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4634 case MONO_PATCH_INFO_INTERNAL_METHOD:
4635 case MONO_PATCH_INFO_ABS:
4636 case MONO_PATCH_INFO_RGCTX_FETCH:
4637 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4644 ppc_patch_full (ip, target, is_fd);
4649 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4650 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4651 * the instruction offset immediate for all the registers.
4654 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4658 for (i = 13; i <= 31; i++) {
4659 if (used_int_regs & (1 << i)) {
4660 ppc_str (code, i, pos, base_reg);
4661 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4662 pos += sizeof (mgreg_t);
4666 /* pos is the start of the MonoLMF structure */
4667 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4668 for (i = 13; i <= 31; i++) {
4669 ppc_str (code, i, offset, base_reg);
4670 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4671 offset += sizeof (mgreg_t);
4673 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4674 for (i = 14; i < 32; i++) {
4675 ppc_stfd (code, i, offset, base_reg);
4676 offset += sizeof (gdouble);
4683 * Stack frame layout:
4685 * ------------------- sp
4686 * MonoLMF structure or saved registers
4687 * -------------------
4689 * -------------------
4691 * -------------------
4692 * optional 8 bytes for tracing
4693 * -------------------
4694 * param area size is cfg->param_area
4695 * -------------------
4696 * linkage area size is PPC_STACK_PARAM_OFFSET
4697 * ------------------- sp
4701 mono_arch_emit_prolog (MonoCompile *cfg)
4703 MonoMethod *method = cfg->method;
4705 MonoMethodSignature *sig;
4707 long alloc_size, pos, max_offset, cfa_offset;
4713 int tailcall_struct_index;
4715 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4718 sig = mono_method_signature (method);
4719 cfg->code_size = 512 + sig->param_count * 32;
4720 code = cfg->native_code = g_malloc (cfg->code_size);
4724 /* We currently emit unwind info for aot, but don't use it */
4725 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4727 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4728 ppc_mflr (code, ppc_r0);
4729 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4730 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4733 alloc_size = cfg->stack_offset;
4736 if (!method->save_lmf) {
4737 for (i = 31; i >= 13; --i) {
4738 if (cfg->used_int_regs & (1 << i)) {
4739 pos += sizeof (mgreg_t);
4743 pos += sizeof (MonoLMF);
4747 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4748 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4749 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4750 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4753 cfg->stack_usage = alloc_size;
4754 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4756 if (ppc_is_imm16 (-alloc_size)) {
4757 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4758 cfa_offset = alloc_size;
4759 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4760 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4763 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4764 ppc_load (code, ppc_r0, -alloc_size);
4765 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4766 cfa_offset = alloc_size;
4767 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4768 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4771 if (cfg->frame_reg != ppc_sp) {
4772 ppc_mr (code, cfg->frame_reg, ppc_sp);
4773 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4776 /* store runtime generic context */
4777 if (cfg->rgctx_var) {
4778 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4779 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4781 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4784 /* compute max_offset in order to use short forward jumps
4785 * we always do it on ppc because the immediate displacement
4786 * for jumps is too small
4789 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4791 bb->max_offset = max_offset;
4793 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4796 MONO_BB_FOR_EACH_INS (bb, ins)
4797 max_offset += ins_native_length (cfg, ins);
4800 /* load arguments allocated to register from the stack */
4803 cinfo = get_call_info (sig);
4805 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4806 ArgInfo *ainfo = &cinfo->ret;
4808 inst = cfg->vret_addr;
4811 if (ppc_is_imm16 (inst->inst_offset)) {
4812 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4814 ppc_load (code, ppc_r12, inst->inst_offset);
4815 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4819 tailcall_struct_index = 0;
4820 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4821 ArgInfo *ainfo = cinfo->args + i;
4822 inst = cfg->args [pos];
4824 if (cfg->verbose_level > 2)
4825 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4826 if (inst->opcode == OP_REGVAR) {
4827 if (ainfo->regtype == RegTypeGeneral)
4828 ppc_mr (code, inst->dreg, ainfo->reg);
4829 else if (ainfo->regtype == RegTypeFP)
4830 ppc_fmr (code, inst->dreg, ainfo->reg);
4831 else if (ainfo->regtype == RegTypeBase) {
4832 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4833 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4835 g_assert_not_reached ();
4837 if (cfg->verbose_level > 2)
4838 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4840 /* the argument should be put on the stack: FIXME handle size != word */
4841 if (ainfo->regtype == RegTypeGeneral) {
4842 switch (ainfo->size) {
4844 if (ppc_is_imm16 (inst->inst_offset)) {
4845 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4847 if (ppc_is_imm32 (inst->inst_offset)) {
4848 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4849 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4851 ppc_load (code, ppc_r12, inst->inst_offset);
4852 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4857 if (ppc_is_imm16 (inst->inst_offset)) {
4858 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4860 if (ppc_is_imm32 (inst->inst_offset)) {
4861 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4862 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4864 ppc_load (code, ppc_r12, inst->inst_offset);
4865 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4869 #ifdef __mono_ppc64__
4871 if (ppc_is_imm16 (inst->inst_offset)) {
4872 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4874 if (ppc_is_imm32 (inst->inst_offset)) {
4875 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4876 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4878 ppc_load (code, ppc_r12, inst->inst_offset);
4879 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4884 if (ppc_is_imm16 (inst->inst_offset)) {
4885 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4887 ppc_load (code, ppc_r12, inst->inst_offset);
4888 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4893 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4894 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4895 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4897 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4898 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4899 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4900 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4905 if (ppc_is_imm16 (inst->inst_offset)) {
4906 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4908 if (ppc_is_imm32 (inst->inst_offset)) {
4909 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4910 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
4912 ppc_load (code, ppc_r12, inst->inst_offset);
4913 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4918 } else if (ainfo->regtype == RegTypeBase) {
4919 g_assert (ppc_is_imm16 (ainfo->offset));
4920 /* load the previous stack pointer in r12 */
4921 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4922 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
4923 switch (ainfo->size) {
4925 if (ppc_is_imm16 (inst->inst_offset)) {
4926 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4928 if (ppc_is_imm32 (inst->inst_offset)) {
4929 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4930 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
4932 ppc_load (code, ppc_r12, inst->inst_offset);
4933 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4938 if (ppc_is_imm16 (inst->inst_offset)) {
4939 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4941 if (ppc_is_imm32 (inst->inst_offset)) {
4942 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4943 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
4945 ppc_load (code, ppc_r12, inst->inst_offset);
4946 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4950 #ifdef __mono_ppc64__
4952 if (ppc_is_imm16 (inst->inst_offset)) {
4953 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4955 if (ppc_is_imm32 (inst->inst_offset)) {
4956 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4957 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
4959 ppc_load (code, ppc_r12, inst->inst_offset);
4960 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4965 if (ppc_is_imm16 (inst->inst_offset)) {
4966 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4968 ppc_load (code, ppc_r12, inst->inst_offset);
4969 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
4974 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4975 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4976 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4977 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
4978 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4980 /* use r11 to load the 2nd half of the long before we clobber r12. */
4981 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
4982 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4983 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4984 ppc_stw (code, ppc_r0, 0, ppc_r12);
4985 ppc_stw (code, ppc_r11, 4, ppc_r12);
4990 if (ppc_is_imm16 (inst->inst_offset)) {
4991 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4993 if (ppc_is_imm32 (inst->inst_offset)) {
4994 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4995 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
4997 ppc_load (code, ppc_r12, inst->inst_offset);
4998 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5003 } else if (ainfo->regtype == RegTypeFP) {
5004 g_assert (ppc_is_imm16 (inst->inst_offset));
5005 if (ainfo->size == 8)
5006 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5007 else if (ainfo->size == 4)
5008 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5010 g_assert_not_reached ();
5011 } else if (ainfo->regtype == RegTypeStructByVal) {
5012 int doffset = inst->inst_offset;
5016 g_assert (ppc_is_imm16 (inst->inst_offset));
5017 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5018 /* FIXME: what if there is no class? */
5019 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5020 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5021 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5024 * Darwin handles 1 and 2 byte
5025 * structs specially by
5026 * loading h/b into the arg
5027 * register. Only done for
5031 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5033 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5037 #ifdef __mono_ppc64__
5039 g_assert (cur_reg == 0);
5040 ppc_sldi (code, ppc_r0, ainfo->reg,
5041 (sizeof (gpointer) - ainfo->bytes) * 8);
5042 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5046 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5047 inst->inst_basereg);
5050 soffset += sizeof (gpointer);
5051 doffset += sizeof (gpointer);
5053 if (ainfo->vtsize) {
5054 /* FIXME: we need to do the shifting here, too */
5057 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5058 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5059 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5060 code = emit_memcpy (code, size - soffset,
5061 inst->inst_basereg, doffset,
5062 ppc_r12, ainfo->offset + soffset);
5064 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5065 inst->inst_basereg, doffset,
5066 ppc_r12, ainfo->offset + soffset);
5069 } else if (ainfo->regtype == RegTypeStructByAddr) {
5070 /* if it was originally a RegTypeBase */
5071 if (ainfo->offset) {
5072 /* load the previous stack pointer in r12 */
5073 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5074 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5076 ppc_mr (code, ppc_r12, ainfo->reg);
5079 if (cfg->tailcall_valuetype_addrs) {
5080 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5082 g_assert (ppc_is_imm16 (addr->inst_offset));
5083 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5085 tailcall_struct_index++;
5088 g_assert (ppc_is_imm16 (inst->inst_offset));
5089 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5090 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5092 g_assert_not_reached ();
5097 if (method->save_lmf) {
5098 if (lmf_pthread_key != -1) {
5099 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5100 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5101 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5103 if (cfg->compile_aot) {
5104 /* Compute the got address which is needed by the PLT entry */
5105 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5107 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5108 (gpointer)"mono_get_lmf_addr");
5109 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5110 ppc_load_func (code, PPC_CALL_REG, 0);
5111 ppc_mtlr (code, PPC_CALL_REG);
5117 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5118 /* lmf_offset is the offset from the previous stack pointer,
5119 * alloc_size is the total stack space allocated, so the offset
5120 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5121 * The pointer to the struct is put in ppc_r12 (new_lmf).
5122 * The callee-saved registers are already in the MonoLMF structure
5124 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5125 /* ppc_r3 is the result from mono_get_lmf_addr () */
5126 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5127 /* new_lmf->previous_lmf = *lmf_addr */
5128 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5129 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5130 /* *(lmf_addr) = r12 */
5131 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5132 /* save method info */
5133 if (cfg->compile_aot)
5135 ppc_load (code, ppc_r0, 0);
5137 ppc_load_ptr (code, ppc_r0, method);
5138 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5139 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5140 /* save the current IP */
5141 if (cfg->compile_aot) {
5143 ppc_mflr (code, ppc_r0);
5145 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5146 #ifdef __mono_ppc64__
5147 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5149 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5152 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5156 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5158 cfg->code_len = code - cfg->native_code;
5159 g_assert (cfg->code_len <= cfg->code_size);
5166 mono_arch_emit_epilog (MonoCompile *cfg)
5168 MonoMethod *method = cfg->method;
5170 int max_epilog_size = 16 + 20*4;
5173 if (cfg->method->save_lmf)
5174 max_epilog_size += 128;
5176 if (mono_jit_trace_calls != NULL)
5177 max_epilog_size += 50;
5179 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5180 max_epilog_size += 50;
5182 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5183 cfg->code_size *= 2;
5184 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5185 cfg->stat_code_reallocs++;
5189 * Keep in sync with OP_JMP
5191 code = cfg->native_code + cfg->code_len;
5193 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5194 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5198 if (method->save_lmf) {
5200 pos += sizeof (MonoLMF);
5202 /* save the frame reg in r8 */
5203 ppc_mr (code, ppc_r8, cfg->frame_reg);
5204 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5205 /* r5 = previous_lmf */
5206 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5208 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5209 /* *(lmf_addr) = previous_lmf */
5210 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5211 /* FIXME: speedup: there is no actual need to restore the registers if
5212 * we didn't actually change them (idea from Zoltan).
5215 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5217 /*for (i = 14; i < 32; i++) {
5218 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5220 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5221 /* use the saved copy of the frame reg in r8 */
5222 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5223 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5224 ppc_mtlr (code, ppc_r0);
5226 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5228 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5229 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5230 if (ppc_is_imm16 (return_offset)) {
5231 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5233 ppc_load (code, ppc_r12, return_offset);
5234 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5236 ppc_mtlr (code, ppc_r0);
5238 if (ppc_is_imm16 (cfg->stack_usage)) {
5239 int offset = cfg->stack_usage;
5240 for (i = 13; i <= 31; i++) {
5241 if (cfg->used_int_regs & (1 << i))
5242 offset -= sizeof (mgreg_t);
5244 if (cfg->frame_reg != ppc_sp)
5245 ppc_mr (code, ppc_r12, cfg->frame_reg);
5246 /* note r31 (possibly the frame register) is restored last */
5247 for (i = 13; i <= 31; i++) {
5248 if (cfg->used_int_regs & (1 << i)) {
5249 ppc_ldr (code, i, offset, cfg->frame_reg);
5250 offset += sizeof (mgreg_t);
5253 if (cfg->frame_reg != ppc_sp)
5254 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5256 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5258 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5259 if (cfg->used_int_regs) {
5260 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5261 for (i = 31; i >= 13; --i) {
5262 if (cfg->used_int_regs & (1 << i)) {
5263 pos += sizeof (mgreg_t);
5264 ppc_ldr (code, i, -pos, ppc_r12);
5267 ppc_mr (code, ppc_sp, ppc_r12);
5269 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5276 cfg->code_len = code - cfg->native_code;
5278 g_assert (cfg->code_len < cfg->code_size);
5281 #endif /* ifndef DISABLE_JIT */
5283 /* remove once throw_exception_by_name is eliminated */
5285 exception_id_by_name (const char *name)
5287 if (strcmp (name, "IndexOutOfRangeException") == 0)
5288 return MONO_EXC_INDEX_OUT_OF_RANGE;
5289 if (strcmp (name, "OverflowException") == 0)
5290 return MONO_EXC_OVERFLOW;
5291 if (strcmp (name, "ArithmeticException") == 0)
5292 return MONO_EXC_ARITHMETIC;
5293 if (strcmp (name, "DivideByZeroException") == 0)
5294 return MONO_EXC_DIVIDE_BY_ZERO;
5295 if (strcmp (name, "InvalidCastException") == 0)
5296 return MONO_EXC_INVALID_CAST;
5297 if (strcmp (name, "NullReferenceException") == 0)
5298 return MONO_EXC_NULL_REF;
5299 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5300 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5301 if (strcmp (name, "ArgumentException") == 0)
5302 return MONO_EXC_ARGUMENT;
5303 g_error ("Unknown intrinsic exception %s\n", name);
5309 mono_arch_emit_exceptions (MonoCompile *cfg)
5311 MonoJumpInfo *patch_info;
5314 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5315 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5316 int max_epilog_size = 50;
5318 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5319 exc_throw_pos [i] = NULL;
5320 exc_throw_found [i] = 0;
5323 /* count the number of exception infos */
5326 * make sure we have enough space for exceptions
5328 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5329 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5330 i = exception_id_by_name (patch_info->data.target);
5331 if (!exc_throw_found [i]) {
5332 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5333 exc_throw_found [i] = TRUE;
5335 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5336 max_epilog_size += 12;
5337 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5338 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5339 i = exception_id_by_name (ovfj->data.exception);
5340 if (!exc_throw_found [i]) {
5341 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5342 exc_throw_found [i] = TRUE;
5344 max_epilog_size += 8;
5348 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5349 cfg->code_size *= 2;
5350 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5351 cfg->stat_code_reallocs++;
5354 code = cfg->native_code + cfg->code_len;
5356 /* add code to raise exceptions */
5357 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5358 switch (patch_info->type) {
5359 case MONO_PATCH_INFO_BB_OVF: {
5360 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5361 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5362 /* patch the initial jump */
5363 ppc_patch (ip, code);
5364 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5366 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5367 /* jump back to the true target */
5369 ip = ovfj->data.bb->native_offset + cfg->native_code;
5370 ppc_patch (code - 4, ip);
5371 patch_info->type = MONO_PATCH_INFO_NONE;
5374 case MONO_PATCH_INFO_EXC_OVF: {
5375 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5376 MonoJumpInfo *newji;
5377 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5378 unsigned char *bcl = code;
5379 /* patch the initial jump: we arrived here with a call */
5380 ppc_patch (ip, code);
5381 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5383 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5384 /* patch the conditional jump to the right handler */
5385 /* make it processed next */
5386 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5387 newji->type = MONO_PATCH_INFO_EXC;
5388 newji->ip.i = bcl - cfg->native_code;
5389 newji->data.target = ovfj->data.exception;
5390 newji->next = patch_info->next;
5391 patch_info->next = newji;
5392 patch_info->type = MONO_PATCH_INFO_NONE;
5395 case MONO_PATCH_INFO_EXC: {
5396 MonoClass *exc_class;
5398 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5399 i = exception_id_by_name (patch_info->data.target);
5400 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5401 ppc_patch (ip, exc_throw_pos [i]);
5402 patch_info->type = MONO_PATCH_INFO_NONE;
5405 exc_throw_pos [i] = code;
5408 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5409 g_assert (exc_class);
5411 ppc_patch (ip, code);
5412 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5413 ppc_load (code, ppc_r3, exc_class->type_token);
5414 /* we got here from a conditional call, so the calling ip is set in lr */
5415 ppc_mflr (code, ppc_r4);
5416 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5417 patch_info->data.name = "mono_arch_throw_corlib_exception";
5418 patch_info->ip.i = code - cfg->native_code;
5419 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5420 ppc_load_func (code, PPC_CALL_REG, 0);
5421 ppc_mtctr (code, PPC_CALL_REG);
5422 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5434 cfg->code_len = code - cfg->native_code;
5436 g_assert (cfg->code_len <= cfg->code_size);
5442 try_offset_access (void *value, guint32 idx)
5444 register void* me __asm__ ("r2");
5445 void ***p = (void***)((char*)me + 284);
5446 int idx1 = idx / 32;
5447 int idx2 = idx % 32;
5450 if (value != p[idx1][idx2])
5457 setup_tls_access (void)
5459 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5460 size_t conf_size = 0;
5463 /* FIXME for darwin */
5464 guint32 *ins, *code;
5465 guint32 cmplwi_1023, li_0x48, blr_ins;
5469 tls_mode = TLS_MODE_FAILED;
5472 if (tls_mode == TLS_MODE_FAILED)
5474 if (g_getenv ("MONO_NO_TLS")) {
5475 tls_mode = TLS_MODE_FAILED;
5479 if (tls_mode == TLS_MODE_DETECT) {
5480 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5481 tls_mode = TLS_MODE_DARWIN_G4;
5482 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5483 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5484 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5485 tls_mode = TLS_MODE_NPTL;
5486 #elif !defined(TARGET_PS3)
5487 ins = (guint32*)pthread_getspecific;
5488 /* uncond branch to the real method */
5489 if ((*ins >> 26) == 18) {
5491 val = (*ins & ~3) << 6;
5495 ins = (guint32*)(long)val;
5497 ins = (guint32*) ((char*)ins + val);
5500 code = &cmplwi_1023;
5501 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5503 ppc_li (code, ppc_r4, 0x48);
5506 if (*ins == cmplwi_1023) {
5507 int found_lwz_284 = 0;
5509 for (ptk = 0; ptk < 20; ++ptk) {
5511 if (!*ins || *ins == blr_ins)
5513 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5518 if (!found_lwz_284) {
5519 tls_mode = TLS_MODE_FAILED;
5522 tls_mode = TLS_MODE_LTHREADS;
5523 } else if (*ins == li_0x48) {
5525 /* uncond branch to the real method */
5526 if ((*ins >> 26) == 18) {
5528 val = (*ins & ~3) << 6;
5532 ins = (guint32*)(long)val;
5534 ins = (guint32*) ((char*)ins + val);
5536 code = (guint32*)&val;
5537 ppc_li (code, ppc_r0, 0x7FF2);
5538 if (ins [1] == val) {
5539 /* Darwin on G4, implement */
5540 tls_mode = TLS_MODE_FAILED;
5543 code = (guint32*)&val;
5544 ppc_mfspr (code, ppc_r3, 104);
5545 if (ins [1] != val) {
5546 tls_mode = TLS_MODE_FAILED;
5549 tls_mode = TLS_MODE_DARWIN_G5;
5552 tls_mode = TLS_MODE_FAILED;
5556 tls_mode = TLS_MODE_FAILED;
5562 if (tls_mode == TLS_MODE_DETECT)
5563 tls_mode = TLS_MODE_FAILED;
5564 if (tls_mode == TLS_MODE_FAILED)
5566 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5567 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5571 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5572 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5573 if (lmf_pthread_key == -1) {
5574 guint32 ptk = mono_jit_tls_id;
5576 /*g_print ("MonoLMF at: %d\n", ptk);*/
5577 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5578 init_tls_failed = 1;
5581 lmf_pthread_key = ptk;
5590 mono_arch_finish_init (void)
5592 setup_tls_access ();
5596 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5600 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5602 #define LOADSTORE_SIZE 4
5603 #define JUMP_IMM_SIZE 12
5604 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5605 #define ENABLE_WRONG_METHOD_CHECK 0
5608 * LOCKING: called with the domain lock held
5611 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5612 gpointer fail_tramp)
5616 guint8 *code, *start;
5618 for (i = 0; i < count; ++i) {
5619 MonoIMTCheckItem *item = imt_entries [i];
5620 if (item->is_equals) {
5621 if (item->check_target_idx) {
5622 if (!item->compare_done)
5623 item->chunk_size += CMP_SIZE;
5624 if (item->has_target_code)
5625 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5627 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5630 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5631 if (!item->has_target_code)
5632 item->chunk_size += LOADSTORE_SIZE;
5634 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5635 #if ENABLE_WRONG_METHOD_CHECK
5636 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5641 item->chunk_size += CMP_SIZE + BR_SIZE;
5642 imt_entries [item->check_target_idx]->compare_done = TRUE;
5644 size += item->chunk_size;
5646 /* the initial load of the vtable address */
5647 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5649 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5651 code = mono_domain_code_reserve (domain, size);
5656 * We need to save and restore r12 because it might be
5657 * used by the caller as the vtable register, so
5658 * clobbering it will trip up the magic trampoline.
5660 * FIXME: Get rid of this by making sure that r12 is
5661 * not used as the vtable register in interface calls.
5663 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5664 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5666 for (i = 0; i < count; ++i) {
5667 MonoIMTCheckItem *item = imt_entries [i];
5668 item->code_target = code;
5669 if (item->is_equals) {
5670 if (item->check_target_idx) {
5671 if (!item->compare_done) {
5672 ppc_load (code, ppc_r0, (gsize)item->key);
5673 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5675 item->jmp_code = code;
5676 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5677 if (item->has_target_code) {
5678 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5680 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5681 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5683 ppc_mtctr (code, ppc_r0);
5684 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5687 ppc_load (code, ppc_r0, (gulong)item->key);
5688 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5689 item->jmp_code = code;
5690 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5691 if (item->has_target_code) {
5692 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5695 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5696 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5698 ppc_mtctr (code, ppc_r0);
5699 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5700 ppc_patch (item->jmp_code, code);
5701 ppc_load_ptr (code, ppc_r0, fail_tramp);
5702 ppc_mtctr (code, ppc_r0);
5703 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5704 item->jmp_code = NULL;
5706 /* enable the commented code to assert on wrong method */
5707 #if ENABLE_WRONG_METHOD_CHECK
5708 ppc_load (code, ppc_r0, (guint32)item->key);
5709 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5710 item->jmp_code = code;
5711 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5713 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5714 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5715 ppc_mtctr (code, ppc_r0);
5716 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5717 #if ENABLE_WRONG_METHOD_CHECK
5718 ppc_patch (item->jmp_code, code);
5720 item->jmp_code = NULL;
5725 ppc_load (code, ppc_r0, (gulong)item->key);
5726 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5727 item->jmp_code = code;
5728 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5731 /* patch the branches to get to the target items */
5732 for (i = 0; i < count; ++i) {
5733 MonoIMTCheckItem *item = imt_entries [i];
5734 if (item->jmp_code) {
5735 if (item->check_target_idx) {
5736 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5742 mono_stats.imt_thunks_size += code - start;
5743 g_assert (code - start <= size);
5744 mono_arch_flush_icache (start, size);
5749 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5751 mgreg_t *r = (mgreg_t*)regs;
5753 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5757 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5759 mgreg_t *r = (mgreg_t*)regs;
5761 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5765 mono_arch_get_cie_program (void)
5769 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5775 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5782 mono_arch_print_tree (MonoInst *tree, int arity)
5788 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5791 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5793 g_assert (reg >= ppc_r13);
5795 return ctx->regs [reg - ppc_r13];
5799 mono_arch_get_patch_offset (guint8 *code)
5805 * mono_aot_emit_load_got_addr:
5807 * Emit code to load the got address.
5808 * On PPC, the result is placed into r30.
5811 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5814 ppc_mflr (code, ppc_r30);
5816 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5818 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5819 /* arch_emit_got_address () patches this */
5820 #if defined(TARGET_POWERPC64)
5826 ppc_load32 (code, ppc_r0, 0);
5827 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5834 * mono_ppc_emit_load_aotconst:
5836 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5837 * TARGET from the mscorlib GOT in full-aot code.
5838 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5842 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5844 /* Load the mscorlib got address */
5845 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5846 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5847 /* arch_emit_got_access () patches this */
5848 ppc_load32 (code, ppc_r0, 0);
5849 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5854 /* Soft Debug support */
5855 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5862 * mono_arch_set_breakpoint:
5864 * See mini-amd64.c for docs.
5867 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5870 guint8 *orig_code = code;
5872 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5873 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5875 g_assert (code - orig_code == BREAKPOINT_SIZE);
5877 mono_arch_flush_icache (orig_code, code - orig_code);
5881 * mono_arch_clear_breakpoint:
5883 * See mini-amd64.c for docs.
5886 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5891 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5894 mono_arch_flush_icache (ip, code - ip);
5898 * mono_arch_is_breakpoint_event:
5900 * See mini-amd64.c for docs.
5903 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5905 siginfo_t* sinfo = (siginfo_t*) info;
5906 /* Sometimes the address is off by 4 */
5907 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5914 * mono_arch_skip_breakpoint:
5916 * See mini-amd64.c for docs.
5919 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5921 /* skip the ldptr */
5922 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5930 * mono_arch_start_single_stepping:
5932 * See mini-amd64.c for docs.
5935 mono_arch_start_single_stepping (void)
5937 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5941 * mono_arch_stop_single_stepping:
5943 * See mini-amd64.c for docs.
5946 mono_arch_stop_single_stepping (void)
5948 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5952 * mono_arch_is_single_step_event:
5954 * See mini-amd64.c for docs.
5957 mono_arch_is_single_step_event (void *info, void *sigctx)
5959 siginfo_t* sinfo = (siginfo_t*) info;
5960 /* Sometimes the address is off by 4 */
5961 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5968 * mono_arch_skip_single_step:
5970 * See mini-amd64.c for docs.
5973 mono_arch_skip_single_step (MonoContext *ctx)
5975 /* skip the ldptr */
5976 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5980 * mono_arch_create_seq_point_info:
5982 * See mini-amd64.c for docs.
5985 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5992 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5994 ext->lmf.previous_lmf = prev_lmf;
5995 /* Mark that this is a MonoLMFExt */
5996 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5997 ext->lmf.ebp = (gssize)ext;
6003 mono_arch_opcode_supported (int opcode)
6006 case OP_ATOMIC_ADD_I4:
6007 case OP_ATOMIC_CAS_I4:
6008 #ifdef TARGET_POWERPC64
6009 case OP_ATOMIC_ADD_I8:
6010 case OP_ATOMIC_CAS_I8: