2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-proclib.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-ppc.h>
23 #ifdef TARGET_POWERPC64
24 #include "cpu-ppc64.h"
31 #include <sys/sysctl.h>
37 #define FORCE_INDIR_CALL 1
48 /* cpu_hw_caps contains the flags defined below */
49 static int cpu_hw_caps = 0;
50 static int cachelinesize = 0;
51 static int cachelineinc = 0;
53 PPC_ICACHE_SNOOP = 1 << 0,
54 PPC_MULTIPLE_LS_UNITS = 1 << 1,
55 PPC_SMP_CAPABLE = 1 << 2,
58 PPC_MOVE_FPR_GPR = 1 << 5,
62 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
64 /* This mutex protects architecture specific caches */
65 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
67 static mono_mutex_t mini_arch_mutex;
69 int mono_exc_esp_offset = 0;
70 static int tls_mode = TLS_MODE_DETECT;
71 static int lmf_pthread_key = -1;
74 * The code generated for sequence points reads from this location, which is
75 * made read-only when single stepping is enabled.
77 static gpointer ss_trigger_page;
79 /* Enabled breakpoints read from this trigger page */
80 static gpointer bp_trigger_page;
83 offsets_from_pthread_key (guint32 key, int *offset2)
87 *offset2 = idx2 * sizeof (gpointer);
88 return 284 + idx1 * sizeof (gpointer);
91 #define emit_linuxthreads_tls(code,dreg,key) do {\
93 off1 = offsets_from_pthread_key ((key), &off2); \
94 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
95 ppc_ldptr ((code), (dreg), off2, (dreg)); \
98 #define emit_darwing5_tls(code,dreg,key) do {\
99 int off1 = 0x48 + key * sizeof (gpointer); \
100 ppc_mfspr ((code), (dreg), 104); \
101 ppc_ldptr ((code), (dreg), off1, (dreg)); \
104 /* FIXME: ensure the sc call preserves all but r3 */
105 #define emit_darwing4_tls(code,dreg,key) do {\
106 int off1 = 0x48 + key * sizeof (gpointer); \
107 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r12, ppc_r3); \
108 ppc_li ((code), ppc_r0, 0x7FF2); \
110 ppc_lwz ((code), (dreg), off1, ppc_r3); \
111 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r12); \
114 #ifdef PPC_THREAD_PTR_REG
115 #define emit_nptl_tls(code,dreg,key) do { \
117 int off2 = key >> 15; \
118 if ((off2 == 0) || (off2 == -1)) { \
119 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
121 int off3 = (off2 + 1) > 1; \
122 ppc_addis ((code), ppc_r12, PPC_THREAD_PTR_REG, off3); \
123 ppc_ldptr ((code), (dreg), off1, ppc_r12); \
127 #define emit_nptl_tls(code,dreg,key) do { \
128 g_assert_not_reached (); \
132 #define emit_tls_access(code,dreg,key) do { \
133 switch (tls_mode) { \
134 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
135 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
137 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
138 default: g_assert_not_reached (); \
142 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
144 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
145 inst->type = STACK_R8; \
147 inst->inst_p0 = (void*)(addr); \
148 mono_bblock_add_inst (cfg->cbb, inst); \
152 mono_arch_regname (int reg) {
153 static const char rnames[][4] = {
154 "r0", "sp", "r2", "r3", "r4",
155 "r5", "r6", "r7", "r8", "r9",
156 "r10", "r11", "r12", "r13", "r14",
157 "r15", "r16", "r17", "r18", "r19",
158 "r20", "r21", "r22", "r23", "r24",
159 "r25", "r26", "r27", "r28", "r29",
162 if (reg >= 0 && reg < 32)
168 mono_arch_fregname (int reg) {
169 static const char rnames[][4] = {
170 "f0", "f1", "f2", "f3", "f4",
171 "f5", "f6", "f7", "f8", "f9",
172 "f10", "f11", "f12", "f13", "f14",
173 "f15", "f16", "f17", "f18", "f19",
174 "f20", "f21", "f22", "f23", "f24",
175 "f25", "f26", "f27", "f28", "f29",
178 if (reg >= 0 && reg < 32)
183 /* this function overwrites r0, r11, r12 */
185 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
187 /* unrolled, use the counter in big */
188 if (size > sizeof (gpointer) * 5) {
189 long shifted = size / SIZEOF_VOID_P;
190 guint8 *copy_loop_start, *copy_loop_jump;
192 ppc_load (code, ppc_r0, shifted);
193 ppc_mtctr (code, ppc_r0);
194 //g_assert (sreg == ppc_r12);
195 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (gpointer)));
196 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (gpointer)));
197 copy_loop_start = code;
198 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
200 copy_loop_jump = code;
201 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
202 ppc_patch (copy_loop_jump, copy_loop_start);
203 size -= shifted * sizeof (gpointer);
204 doffset = soffset = 0;
207 #ifdef __mono_ppc64__
208 /* the hardware has multiple load/store units and the move is long
209 enough to use more then one regiester, then use load/load/store/store
210 to execute 2 instructions per cycle. */
211 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
213 ppc_ldptr (code, ppc_r0, soffset, sreg);
214 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
215 ppc_stptr (code, ppc_r0, doffset, dreg);
216 ppc_stptr (code, ppc_r11, doffset+8, dreg);
223 ppc_ldr (code, ppc_r0, soffset, sreg);
224 ppc_str (code, ppc_r0, doffset, dreg);
230 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
232 ppc_lwz (code, ppc_r0, soffset, sreg);
233 ppc_lwz (code, ppc_r11, soffset+4, sreg);
234 ppc_stw (code, ppc_r0, doffset, dreg);
235 ppc_stw (code, ppc_r11, doffset+4, dreg);
243 ppc_lwz (code, ppc_r0, soffset, sreg);
244 ppc_stw (code, ppc_r0, doffset, dreg);
250 ppc_lhz (code, ppc_r0, soffset, sreg);
251 ppc_sth (code, ppc_r0, doffset, dreg);
257 ppc_lbz (code, ppc_r0, soffset, sreg);
258 ppc_stb (code, ppc_r0, doffset, dreg);
267 * mono_arch_get_argument_info:
268 * @csig: a method signature
269 * @param_count: the number of parameters to consider
270 * @arg_info: an array to store the result infos
272 * Gathers information on parameters such as size, alignment and
273 * padding. arg_info should be large enought to hold param_count + 1 entries.
275 * Returns the size of the activation frame.
278 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
284 int k, frame_size = 0;
285 int size, align, pad;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
293 arg_info [0].offset = offset;
296 frame_size += sizeof (gpointer);
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
307 size = mini_type_stack_size (NULL, csig->params [k], &align);
309 /* ignore alignment for now */
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
318 arg_info [k + 1].offset = offset;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
330 #ifdef __mono_ppc64__
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
367 return is_load_sequence (&code [-6]);
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
380 #define MAX_ARCH_DELEGATE_PARAMS 7
383 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
385 guint8 *code, *start;
388 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
390 start = code = mono_global_codeman_reserve (size);
392 code = mono_ppc_create_pre_code_ftnptr (code);
394 /* Replace the this argument with the target */
395 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
396 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
397 /* it's a function descriptor */
398 /* Can't use ldptr as it doesn't work with r0 */
399 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
401 ppc_mtctr (code, ppc_r0);
402 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
403 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
405 g_assert ((code - start) <= size);
407 mono_arch_flush_icache (start, size);
411 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
412 start = code = mono_global_codeman_reserve (size);
414 code = mono_ppc_create_pre_code_ftnptr (code);
416 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
417 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
418 /* it's a function descriptor */
419 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
421 ppc_mtctr (code, ppc_r0);
422 /* slide down the arguments */
423 for (i = 0; i < param_count; ++i) {
424 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
428 g_assert ((code - start) <= size);
430 mono_arch_flush_icache (start, size);
434 *code_len = code - start;
440 mono_arch_get_delegate_invoke_impls (void)
448 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
449 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
451 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
452 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
453 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
454 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
462 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
464 guint8 *code, *start;
466 /* FIXME: Support more cases */
467 if (MONO_TYPE_ISSTRUCT (sig->ret))
471 static guint8* cached = NULL;
477 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
479 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
481 mono_memory_barrier ();
485 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
488 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
490 for (i = 0; i < sig->param_count; ++i)
491 if (!mono_is_regsize_var (sig->params [i]))
495 code = cache [sig->param_count];
500 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
501 start = mono_aot_get_trampoline (name);
504 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
507 mono_memory_barrier ();
509 cache [sig->param_count] = start;
515 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
521 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
523 mgreg_t *r = (mgreg_t*)regs;
525 return (gpointer)(gsize)r [ppc_r3];
533 #define MAX_AUX_ENTRIES 128
535 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
536 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
538 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
540 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
541 #define ISA_64 0x40000000
543 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
544 #define ISA_MOVE_FPR_GPR 0x00000200
546 * Initialize the cpu to execute managed code.
549 mono_arch_cpu_init (void)
554 * Initialize architecture specific code.
557 mono_arch_init (void)
559 #if defined(MONO_CROSS_COMPILE)
560 #elif defined(__APPLE__)
562 size_t len = sizeof (cachelinesize);
565 mib [1] = HW_CACHELINE;
567 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
571 cachelineinc = cachelinesize;
573 #elif defined(__linux__)
574 AuxVec vec [MAX_AUX_ENTRIES];
575 int i, vec_entries = 0;
576 /* sadly this will work only with 2.6 kernels... */
577 FILE* f = fopen ("/proc/self/auxv", "rb");
580 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
584 for (i = 0; i < vec_entries; i++) {
585 int type = vec [i].type;
587 if (type == 19) { /* AT_DCACHEBSIZE */
588 cachelinesize = vec [i].value;
592 #elif defined(G_COMPILER_CODEWARRIOR)
596 //#error Need a way to get cache line size
599 if (mono_hwcap_ppc_has_icache_snoop)
600 cpu_hw_caps |= PPC_ICACHE_SNOOP;
602 if (mono_hwcap_ppc_is_isa_2x)
603 cpu_hw_caps |= PPC_ISA_2X;
605 if (mono_hwcap_ppc_is_isa_64)
606 cpu_hw_caps |= PPC_ISA_64;
608 if (mono_hwcap_ppc_has_move_fpr_gpr)
609 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
611 if (mono_hwcap_ppc_has_multiple_ls_units)
612 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
618 cachelineinc = cachelinesize;
620 if (mono_cpu_count () > 1)
621 cpu_hw_caps |= PPC_SMP_CAPABLE;
623 mono_mutex_init_recursive (&mini_arch_mutex);
625 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
626 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
627 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
629 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
633 * Cleanup architecture specific code.
636 mono_arch_cleanup (void)
638 mono_mutex_destroy (&mini_arch_mutex);
642 * This function returns the optimizations supported on this cpu.
645 mono_arch_cpu_optimizations (guint32 *exclude_mask)
649 /* no ppc-specific optimizations yet */
655 * This function test for all SIMD functions supported.
657 * Returns a bitmask corresponding to all supported versions.
661 mono_arch_cpu_enumerate_simd_versions (void)
663 /* SIMD is currently unimplemented */
667 #ifdef __mono_ppc64__
668 #define CASE_PPC32(c)
669 #define CASE_PPC64(c) case c:
671 #define CASE_PPC32(c) case c:
672 #define CASE_PPC64(c)
676 is_regsize_var (MonoType *t) {
679 t = mini_type_get_underlying_type (NULL, t);
683 CASE_PPC64 (MONO_TYPE_I8)
684 CASE_PPC64 (MONO_TYPE_U8)
688 case MONO_TYPE_FNPTR:
690 case MONO_TYPE_OBJECT:
691 case MONO_TYPE_STRING:
692 case MONO_TYPE_CLASS:
693 case MONO_TYPE_SZARRAY:
694 case MONO_TYPE_ARRAY:
696 case MONO_TYPE_GENERICINST:
697 if (!mono_type_generic_inst_is_valuetype (t))
700 case MONO_TYPE_VALUETYPE:
708 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
713 for (i = 0; i < cfg->num_varinfo; i++) {
714 MonoInst *ins = cfg->varinfo [i];
715 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
718 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
721 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
724 /* we can only allocate 32 bit values */
725 if (is_regsize_var (ins->inst_vtype)) {
726 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
727 g_assert (i == vmv->idx);
728 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
734 #endif /* ifndef DISABLE_JIT */
737 mono_arch_get_global_int_regs (MonoCompile *cfg)
741 if (cfg->frame_reg != ppc_sp)
743 /* ppc_r13 is used by the system on PPC EABI */
744 for (i = 14; i < top; ++i) {
746 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
747 * since the trampolines can clobber r12.
749 if (!(cfg->compile_aot && i == 29))
750 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
757 * mono_arch_regalloc_cost:
759 * Return the cost, in number of memory references, of the action of
760 * allocating the variable VMV into a register during global register
764 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
771 mono_arch_flush_icache (guint8 *code, gint size)
773 #ifdef MONO_CROSS_COMPILE
776 guint8 *endp, *start;
780 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
781 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
782 #if defined(G_COMPILER_CODEWARRIOR)
783 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
784 for (p = start; p < endp; p += cachelineinc) {
788 for (p = start; p < endp; p += cachelineinc) {
794 for (p = start; p < endp; p += cachelineinc) {
805 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
806 * The sync is required to insure that the store queue is completely empty.
807 * While the icbi performs no cache operations, icbi/isync is required to
808 * kill local prefetch.
810 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
812 asm ("icbi 0,%0;" : : "r"(code) : "memory");
816 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
817 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
818 for (p = start; p < endp; p += cachelineinc) {
819 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
822 for (p = start; p < endp; p += cachelineinc) {
823 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
828 for (p = start; p < endp; p += cachelineinc) {
829 /* for ISA2.0+ implementations we should not need any extra sync between the
830 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
831 * So I am not sure which chip had this problem but its not an issue on
832 * of the ISA V2 chips.
834 if (cpu_hw_caps & PPC_ISA_2X)
835 asm ("icbi 0,%0;" : : "r"(p) : "memory");
837 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
839 if (!(cpu_hw_caps & PPC_ISA_2X))
847 mono_arch_flush_register_windows (void)
852 #define ALWAYS_ON_STACK(s) s
853 #define FP_ALSO_IN_REG(s) s
855 #ifdef __mono_ppc64__
856 #define ALWAYS_ON_STACK(s) s
857 #define FP_ALSO_IN_REG(s) s
859 #define ALWAYS_ON_STACK(s)
860 #define FP_ALSO_IN_REG(s)
862 #define ALIGN_DOUBLES
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 (MonoGenericSharingContext *gsctx, 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_type_get_underlying_type (gsctx, 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_type_get_underlying_type (NULL, 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_type_get_underlying_type (NULL, 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 (NULL, caller_sig);
1271 c2 = get_call_info (NULL, 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_type_get_underlying_type (m->generic_sharing_context, 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->generic_sharing_context, 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 (cfg->generic_sharing_context, 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_type_get_underlying_type (cfg->generic_sharing_context, 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 (cfg->generic_sharing_context, &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_type_get_underlying_type (cfg->generic_sharing_context,
1750 mono_method_signature (method)->ret);
1753 #ifndef __mono_ppc64__
1754 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1757 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1758 ins->sreg1 = val->dreg + 1;
1759 ins->sreg2 = val->dreg + 2;
1760 MONO_ADD_INS (cfg->cbb, ins);
1764 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1765 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1769 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1772 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1774 mono_arch_is_inst_imm (gint64 imm)
1779 #endif /* DISABLE_JIT */
1782 * Allow tracing to work with this interface (with an optional argument)
1786 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1790 ppc_load_ptr (code, ppc_r3, cfg->method);
1791 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1792 ppc_load_func (code, PPC_CALL_REG, func);
1793 ppc_mtlr (code, PPC_CALL_REG);
1807 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1810 int save_mode = SAVE_NONE;
1812 MonoMethod *method = cfg->method;
1813 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1814 mono_method_signature (method)->ret)->type;
1815 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1819 offset = code - cfg->native_code;
1820 /* we need about 16 instructions */
1821 if (offset > (cfg->code_size - 16 * 4)) {
1822 cfg->code_size *= 2;
1823 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1824 code = cfg->native_code + offset;
1828 case MONO_TYPE_VOID:
1829 /* special case string .ctor icall */
1830 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1831 save_mode = SAVE_ONE;
1833 save_mode = SAVE_NONE;
1835 #ifndef __mono_ppc64__
1838 save_mode = SAVE_TWO;
1843 save_mode = SAVE_FP;
1845 case MONO_TYPE_VALUETYPE:
1846 save_mode = SAVE_STRUCT;
1849 save_mode = SAVE_ONE;
1853 switch (save_mode) {
1855 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1856 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1857 if (enable_arguments) {
1858 ppc_mr (code, ppc_r5, ppc_r4);
1859 ppc_mr (code, ppc_r4, ppc_r3);
1863 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1864 if (enable_arguments) {
1865 ppc_mr (code, ppc_r4, ppc_r3);
1869 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1870 if (enable_arguments) {
1871 /* FIXME: what reg? */
1872 ppc_fmr (code, ppc_f3, ppc_f1);
1873 /* FIXME: use 8 byte load on PPC64 */
1874 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1875 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1879 if (enable_arguments) {
1880 /* FIXME: get the actual address */
1881 ppc_mr (code, ppc_r4, ppc_r3);
1889 ppc_load_ptr (code, ppc_r3, cfg->method);
1890 ppc_load_func (code, PPC_CALL_REG, func);
1891 ppc_mtlr (code, PPC_CALL_REG);
1894 switch (save_mode) {
1896 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1897 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1900 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1903 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1913 * Conditional branches have a small offset, so if it is likely overflowed,
1914 * we do a branch to the end of the method (uncond branches have much larger
1915 * offsets) where we perform the conditional and jump back unconditionally.
1916 * It's slightly slower, since we add two uncond branches, but it's very simple
1917 * with the current patch implementation and such large methods are likely not
1918 * going to be perf critical anyway.
1923 const char *exception;
1930 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1931 if (0 && ins->inst_true_bb->native_offset) { \
1932 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1934 int br_disp = ins->inst_true_bb->max_offset - offset; \
1935 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1936 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1937 ovfj->data.bb = ins->inst_true_bb; \
1938 ovfj->ip_offset = 0; \
1939 ovfj->b0_cond = (b0); \
1940 ovfj->b1_cond = (b1); \
1941 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1944 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1945 ppc_bc (code, (b0), (b1), 0); \
1949 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1951 /* emit an exception if condition is fail
1953 * We assign the extra code used to throw the implicit exceptions
1954 * to cfg->bb_exit as far as the big branch handling is concerned
1956 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1958 int br_disp = cfg->bb_exit->max_offset - offset; \
1959 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1960 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1961 ovfj->data.exception = (exc_name); \
1962 ovfj->ip_offset = code - cfg->native_code; \
1963 ovfj->b0_cond = (b0); \
1964 ovfj->b1_cond = (b1); \
1965 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1967 cfg->bb_exit->max_offset += 24; \
1969 mono_add_patch_info (cfg, code - cfg->native_code, \
1970 MONO_PATCH_INFO_EXC, exc_name); \
1971 ppc_bcl (code, (b0), (b1), 0); \
1975 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1978 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1983 normalize_opcode (int opcode)
1986 #ifndef __mono_ilp32__
1987 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1988 return OP_LOAD_MEMBASE;
1989 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1990 return OP_LOAD_MEMINDEX;
1991 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1992 return OP_STORE_MEMBASE_REG;
1993 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1994 return OP_STORE_MEMBASE_IMM;
1995 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1996 return OP_STORE_MEMINDEX;
1998 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2000 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2001 return OP_SHR_UN_IMM;
2008 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2010 MonoInst *ins, *n, *last_ins = NULL;
2012 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2013 switch (normalize_opcode (ins->opcode)) {
2015 /* remove unnecessary multiplication with 1 */
2016 if (ins->inst_imm == 1) {
2017 if (ins->dreg != ins->sreg1) {
2018 ins->opcode = OP_MOVE;
2020 MONO_DELETE_INS (bb, ins);
2024 int power2 = mono_is_power_of_two (ins->inst_imm);
2026 ins->opcode = OP_SHL_IMM;
2027 ins->inst_imm = power2;
2031 case OP_LOAD_MEMBASE:
2033 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2034 * OP_LOAD_MEMBASE offset(basereg), reg
2036 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2037 ins->inst_basereg == last_ins->inst_destbasereg &&
2038 ins->inst_offset == last_ins->inst_offset) {
2039 if (ins->dreg == last_ins->sreg1) {
2040 MONO_DELETE_INS (bb, ins);
2043 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2044 ins->opcode = OP_MOVE;
2045 ins->sreg1 = last_ins->sreg1;
2049 * Note: reg1 must be different from the basereg in the second load
2050 * OP_LOAD_MEMBASE offset(basereg), reg1
2051 * OP_LOAD_MEMBASE offset(basereg), reg2
2053 * OP_LOAD_MEMBASE offset(basereg), reg1
2054 * OP_MOVE reg1, reg2
2056 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2057 ins->inst_basereg != last_ins->dreg &&
2058 ins->inst_basereg == last_ins->inst_basereg &&
2059 ins->inst_offset == last_ins->inst_offset) {
2061 if (ins->dreg == last_ins->dreg) {
2062 MONO_DELETE_INS (bb, ins);
2065 ins->opcode = OP_MOVE;
2066 ins->sreg1 = last_ins->dreg;
2069 //g_assert_not_reached ();
2073 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2074 * OP_LOAD_MEMBASE offset(basereg), reg
2076 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2077 * OP_ICONST reg, imm
2079 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2080 ins->inst_basereg == last_ins->inst_destbasereg &&
2081 ins->inst_offset == last_ins->inst_offset) {
2082 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2083 ins->opcode = OP_ICONST;
2084 ins->inst_c0 = last_ins->inst_imm;
2085 g_assert_not_reached (); // check this rule
2089 case OP_LOADU1_MEMBASE:
2090 case OP_LOADI1_MEMBASE:
2091 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2092 ins->inst_basereg == last_ins->inst_destbasereg &&
2093 ins->inst_offset == last_ins->inst_offset) {
2094 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2095 ins->sreg1 = last_ins->sreg1;
2098 case OP_LOADU2_MEMBASE:
2099 case OP_LOADI2_MEMBASE:
2100 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2101 ins->inst_basereg == last_ins->inst_destbasereg &&
2102 ins->inst_offset == last_ins->inst_offset) {
2103 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2104 ins->sreg1 = last_ins->sreg1;
2107 #ifdef __mono_ppc64__
2108 case OP_LOADU4_MEMBASE:
2109 case OP_LOADI4_MEMBASE:
2110 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2111 ins->inst_basereg == last_ins->inst_destbasereg &&
2112 ins->inst_offset == last_ins->inst_offset) {
2113 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2114 ins->sreg1 = last_ins->sreg1;
2119 ins->opcode = OP_MOVE;
2123 if (ins->dreg == ins->sreg1) {
2124 MONO_DELETE_INS (bb, ins);
2128 * OP_MOVE sreg, dreg
2129 * OP_MOVE dreg, sreg
2131 if (last_ins && last_ins->opcode == OP_MOVE &&
2132 ins->sreg1 == last_ins->dreg &&
2133 ins->dreg == last_ins->sreg1) {
2134 MONO_DELETE_INS (bb, ins);
2142 bb->last_ins = last_ins;
2146 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2148 switch (ins->opcode) {
2149 case OP_ICONV_TO_R_UN: {
2150 #if G_BYTE_ORDER == G_BIG_ENDIAN
2151 static const guint64 adjust_val = 0x4330000000000000ULL;
2153 static const guint64 adjust_val = 0x0000000000003043ULL;
2155 int msw_reg = mono_alloc_ireg (cfg);
2156 int adj_reg = mono_alloc_freg (cfg);
2157 int tmp_reg = mono_alloc_freg (cfg);
2158 int basereg = ppc_sp;
2160 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2161 if (!ppc_is_imm16 (offset + 4)) {
2162 basereg = mono_alloc_ireg (cfg);
2163 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2165 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2166 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2167 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2168 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2169 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2170 ins->opcode = OP_NOP;
2173 #ifndef __mono_ppc64__
2174 case OP_ICONV_TO_R4:
2175 case OP_ICONV_TO_R8: {
2176 /* If we have a PPC_FEATURE_64 machine we can avoid
2177 this and use the fcfid instruction. Otherwise
2178 on an old 32-bit chip and we have to do this the
2180 if (!(cpu_hw_caps & PPC_ISA_64)) {
2181 /* FIXME: change precision for CEE_CONV_R4 */
2182 static const guint64 adjust_val = 0x4330000080000000ULL;
2183 int msw_reg = mono_alloc_ireg (cfg);
2184 int xored = mono_alloc_ireg (cfg);
2185 int adj_reg = mono_alloc_freg (cfg);
2186 int tmp_reg = mono_alloc_freg (cfg);
2187 int basereg = ppc_sp;
2189 if (!ppc_is_imm16 (offset + 4)) {
2190 basereg = mono_alloc_ireg (cfg);
2191 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2193 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2194 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2195 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2196 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2197 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2198 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2200 if (ins->opcode == OP_ICONV_TO_R4)
2201 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2202 ins->opcode = OP_NOP;
2208 int msw_reg = mono_alloc_ireg (cfg);
2209 int basereg = ppc_sp;
2211 if (!ppc_is_imm16 (offset + 4)) {
2212 basereg = mono_alloc_ireg (cfg);
2213 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2215 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2216 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2217 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2218 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2219 ins->opcode = OP_NOP;
2222 #ifdef __mono_ppc64__
2224 case OP_IADD_OVF_UN:
2226 int shifted1_reg = mono_alloc_ireg (cfg);
2227 int shifted2_reg = mono_alloc_ireg (cfg);
2228 int result_shifted_reg = mono_alloc_ireg (cfg);
2230 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2231 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2232 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2233 if (ins->opcode == OP_IADD_OVF_UN)
2234 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2236 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2237 ins->opcode = OP_NOP;
2244 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2246 switch (ins->opcode) {
2248 /* ADC sets the condition code */
2249 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2250 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2253 case OP_LADD_OVF_UN:
2254 /* ADC sets the condition code */
2255 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2256 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2260 /* SBB sets the condition code */
2261 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2265 case OP_LSUB_OVF_UN:
2266 /* SBB sets the condition code */
2267 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2272 /* From gcc generated code */
2273 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2274 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2283 * the branch_b0_table should maintain the order of these
2297 branch_b0_table [] = {
2312 branch_b1_table [] = {
2326 #define NEW_INS(cfg,dest,op) do { \
2327 MONO_INST_NEW((cfg), (dest), (op)); \
2328 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2332 map_to_reg_reg_op (int op)
2341 case OP_COMPARE_IMM:
2343 case OP_ICOMPARE_IMM:
2345 case OP_LCOMPARE_IMM:
2361 case OP_LOAD_MEMBASE:
2362 return OP_LOAD_MEMINDEX;
2363 case OP_LOADI4_MEMBASE:
2364 return OP_LOADI4_MEMINDEX;
2365 case OP_LOADU4_MEMBASE:
2366 return OP_LOADU4_MEMINDEX;
2367 case OP_LOADI8_MEMBASE:
2368 return OP_LOADI8_MEMINDEX;
2369 case OP_LOADU1_MEMBASE:
2370 return OP_LOADU1_MEMINDEX;
2371 case OP_LOADI2_MEMBASE:
2372 return OP_LOADI2_MEMINDEX;
2373 case OP_LOADU2_MEMBASE:
2374 return OP_LOADU2_MEMINDEX;
2375 case OP_LOADI1_MEMBASE:
2376 return OP_LOADI1_MEMINDEX;
2377 case OP_LOADR4_MEMBASE:
2378 return OP_LOADR4_MEMINDEX;
2379 case OP_LOADR8_MEMBASE:
2380 return OP_LOADR8_MEMINDEX;
2381 case OP_STOREI1_MEMBASE_REG:
2382 return OP_STOREI1_MEMINDEX;
2383 case OP_STOREI2_MEMBASE_REG:
2384 return OP_STOREI2_MEMINDEX;
2385 case OP_STOREI4_MEMBASE_REG:
2386 return OP_STOREI4_MEMINDEX;
2387 case OP_STOREI8_MEMBASE_REG:
2388 return OP_STOREI8_MEMINDEX;
2389 case OP_STORE_MEMBASE_REG:
2390 return OP_STORE_MEMINDEX;
2391 case OP_STORER4_MEMBASE_REG:
2392 return OP_STORER4_MEMINDEX;
2393 case OP_STORER8_MEMBASE_REG:
2394 return OP_STORER8_MEMINDEX;
2395 case OP_STORE_MEMBASE_IMM:
2396 return OP_STORE_MEMBASE_REG;
2397 case OP_STOREI1_MEMBASE_IMM:
2398 return OP_STOREI1_MEMBASE_REG;
2399 case OP_STOREI2_MEMBASE_IMM:
2400 return OP_STOREI2_MEMBASE_REG;
2401 case OP_STOREI4_MEMBASE_IMM:
2402 return OP_STOREI4_MEMBASE_REG;
2403 case OP_STOREI8_MEMBASE_IMM:
2404 return OP_STOREI8_MEMBASE_REG;
2406 return mono_op_imm_to_op (op);
2409 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2411 #define compare_opcode_is_unsigned(opcode) \
2412 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2413 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2414 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2415 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2416 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2417 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2418 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2419 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2422 * Remove from the instruction list the instructions that can't be
2423 * represented with very simple instructions with no register
2427 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2429 MonoInst *ins, *next, *temp, *last_ins = NULL;
2432 MONO_BB_FOR_EACH_INS (bb, ins) {
2434 switch (ins->opcode) {
2435 case OP_IDIV_UN_IMM:
2438 case OP_IREM_UN_IMM:
2439 CASE_PPC64 (OP_LREM_IMM) {
2440 NEW_INS (cfg, temp, OP_ICONST);
2441 temp->inst_c0 = ins->inst_imm;
2442 temp->dreg = mono_alloc_ireg (cfg);
2443 ins->sreg2 = temp->dreg;
2444 if (ins->opcode == OP_IDIV_IMM)
2445 ins->opcode = OP_IDIV;
2446 else if (ins->opcode == OP_IREM_IMM)
2447 ins->opcode = OP_IREM;
2448 else if (ins->opcode == OP_IDIV_UN_IMM)
2449 ins->opcode = OP_IDIV_UN;
2450 else if (ins->opcode == OP_IREM_UN_IMM)
2451 ins->opcode = OP_IREM_UN;
2452 else if (ins->opcode == OP_LREM_IMM)
2453 ins->opcode = OP_LREM;
2455 /* handle rem separately */
2460 CASE_PPC64 (OP_LREM)
2461 CASE_PPC64 (OP_LREM_UN) {
2463 /* we change a rem dest, src1, src2 to
2464 * div temp1, src1, src2
2465 * mul temp2, temp1, src2
2466 * sub dest, src1, temp2
2468 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2469 NEW_INS (cfg, mul, OP_IMUL);
2470 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2471 ins->opcode = OP_ISUB;
2473 NEW_INS (cfg, mul, OP_LMUL);
2474 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2475 ins->opcode = OP_LSUB;
2477 temp->sreg1 = ins->sreg1;
2478 temp->sreg2 = ins->sreg2;
2479 temp->dreg = mono_alloc_ireg (cfg);
2480 mul->sreg1 = temp->dreg;
2481 mul->sreg2 = ins->sreg2;
2482 mul->dreg = mono_alloc_ireg (cfg);
2483 ins->sreg2 = mul->dreg;
2487 CASE_PPC64 (OP_LADD_IMM)
2490 if (!ppc_is_imm16 (ins->inst_imm)) {
2491 NEW_INS (cfg, temp, OP_ICONST);
2492 temp->inst_c0 = ins->inst_imm;
2493 temp->dreg = mono_alloc_ireg (cfg);
2494 ins->sreg2 = temp->dreg;
2495 ins->opcode = map_to_reg_reg_op (ins->opcode);
2499 CASE_PPC64 (OP_LSUB_IMM)
2501 if (!ppc_is_imm16 (-ins->inst_imm)) {
2502 NEW_INS (cfg, temp, OP_ICONST);
2503 temp->inst_c0 = ins->inst_imm;
2504 temp->dreg = mono_alloc_ireg (cfg);
2505 ins->sreg2 = temp->dreg;
2506 ins->opcode = map_to_reg_reg_op (ins->opcode);
2518 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2519 #ifdef __mono_ppc64__
2520 if (ins->inst_imm & 0xffffffff00000000ULL)
2524 NEW_INS (cfg, temp, OP_ICONST);
2525 temp->inst_c0 = ins->inst_imm;
2526 temp->dreg = mono_alloc_ireg (cfg);
2527 ins->sreg2 = temp->dreg;
2528 ins->opcode = map_to_reg_reg_op (ins->opcode);
2537 NEW_INS (cfg, temp, OP_ICONST);
2538 temp->inst_c0 = ins->inst_imm;
2539 temp->dreg = mono_alloc_ireg (cfg);
2540 ins->sreg2 = temp->dreg;
2541 ins->opcode = map_to_reg_reg_op (ins->opcode);
2543 case OP_COMPARE_IMM:
2544 case OP_ICOMPARE_IMM:
2545 CASE_PPC64 (OP_LCOMPARE_IMM)
2547 /* Branch opts can eliminate the branch */
2548 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2549 ins->opcode = OP_NOP;
2553 if (compare_opcode_is_unsigned (next->opcode)) {
2554 if (!ppc_is_uimm16 (ins->inst_imm)) {
2555 NEW_INS (cfg, temp, OP_ICONST);
2556 temp->inst_c0 = ins->inst_imm;
2557 temp->dreg = mono_alloc_ireg (cfg);
2558 ins->sreg2 = temp->dreg;
2559 ins->opcode = map_to_reg_reg_op (ins->opcode);
2562 if (!ppc_is_imm16 (ins->inst_imm)) {
2563 NEW_INS (cfg, temp, OP_ICONST);
2564 temp->inst_c0 = ins->inst_imm;
2565 temp->dreg = mono_alloc_ireg (cfg);
2566 ins->sreg2 = temp->dreg;
2567 ins->opcode = map_to_reg_reg_op (ins->opcode);
2573 if (ins->inst_imm == 1) {
2574 ins->opcode = OP_MOVE;
2577 if (ins->inst_imm == 0) {
2578 ins->opcode = OP_ICONST;
2582 imm = mono_is_power_of_two (ins->inst_imm);
2584 ins->opcode = OP_SHL_IMM;
2585 ins->inst_imm = imm;
2588 if (!ppc_is_imm16 (ins->inst_imm)) {
2589 NEW_INS (cfg, temp, OP_ICONST);
2590 temp->inst_c0 = ins->inst_imm;
2591 temp->dreg = mono_alloc_ireg (cfg);
2592 ins->sreg2 = temp->dreg;
2593 ins->opcode = map_to_reg_reg_op (ins->opcode);
2596 case OP_LOCALLOC_IMM:
2597 NEW_INS (cfg, temp, OP_ICONST);
2598 temp->inst_c0 = ins->inst_imm;
2599 temp->dreg = mono_alloc_ireg (cfg);
2600 ins->sreg1 = temp->dreg;
2601 ins->opcode = OP_LOCALLOC;
2603 case OP_LOAD_MEMBASE:
2604 case OP_LOADI4_MEMBASE:
2605 CASE_PPC64 (OP_LOADI8_MEMBASE)
2606 case OP_LOADU4_MEMBASE:
2607 case OP_LOADI2_MEMBASE:
2608 case OP_LOADU2_MEMBASE:
2609 case OP_LOADI1_MEMBASE:
2610 case OP_LOADU1_MEMBASE:
2611 case OP_LOADR4_MEMBASE:
2612 case OP_LOADR8_MEMBASE:
2613 case OP_STORE_MEMBASE_REG:
2614 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2615 case OP_STOREI4_MEMBASE_REG:
2616 case OP_STOREI2_MEMBASE_REG:
2617 case OP_STOREI1_MEMBASE_REG:
2618 case OP_STORER4_MEMBASE_REG:
2619 case OP_STORER8_MEMBASE_REG:
2620 /* we can do two things: load the immed in a register
2621 * and use an indexed load, or see if the immed can be
2622 * represented as an ad_imm + a load with a smaller offset
2623 * that fits. We just do the first for now, optimize later.
2625 if (ppc_is_imm16 (ins->inst_offset))
2627 NEW_INS (cfg, temp, OP_ICONST);
2628 temp->inst_c0 = ins->inst_offset;
2629 temp->dreg = mono_alloc_ireg (cfg);
2630 ins->sreg2 = temp->dreg;
2631 ins->opcode = map_to_reg_reg_op (ins->opcode);
2633 case OP_STORE_MEMBASE_IMM:
2634 case OP_STOREI1_MEMBASE_IMM:
2635 case OP_STOREI2_MEMBASE_IMM:
2636 case OP_STOREI4_MEMBASE_IMM:
2637 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2638 NEW_INS (cfg, temp, OP_ICONST);
2639 temp->inst_c0 = ins->inst_imm;
2640 temp->dreg = mono_alloc_ireg (cfg);
2641 ins->sreg1 = temp->dreg;
2642 ins->opcode = map_to_reg_reg_op (ins->opcode);
2644 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2647 if (cfg->compile_aot) {
2648 /* Keep these in the aot case */
2651 NEW_INS (cfg, temp, OP_ICONST);
2652 temp->inst_c0 = (gulong)ins->inst_p0;
2653 temp->dreg = mono_alloc_ireg (cfg);
2654 ins->inst_basereg = temp->dreg;
2655 ins->inst_offset = 0;
2656 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2658 /* make it handle the possibly big ins->inst_offset
2659 * later optimize to use lis + load_membase
2665 bb->last_ins = last_ins;
2666 bb->max_vreg = cfg->next_vreg;
2670 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2672 long offset = cfg->arch.fp_conv_var_offset;
2674 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2675 #ifdef __mono_ppc64__
2677 ppc_fctidz (code, ppc_f0, sreg);
2682 ppc_fctiwz (code, ppc_f0, sreg);
2685 if (ppc_is_imm16 (offset + sub_offset)) {
2686 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2688 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2690 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2692 ppc_load (code, dreg, offset);
2693 ppc_add (code, dreg, dreg, cfg->frame_reg);
2694 ppc_stfd (code, ppc_f0, 0, dreg);
2696 ppc_ldr (code, dreg, sub_offset, dreg);
2698 ppc_lwz (code, dreg, sub_offset, dreg);
2702 ppc_andid (code, dreg, dreg, 0xff);
2704 ppc_andid (code, dreg, dreg, 0xffff);
2705 #ifdef __mono_ppc64__
2707 ppc_clrldi (code, dreg, dreg, 32);
2711 ppc_extsb (code, dreg, dreg);
2713 ppc_extsh (code, dreg, dreg);
2714 #ifdef __mono_ppc64__
2716 ppc_extsw (code, dreg, dreg);
2724 const guchar *target;
2729 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2732 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2733 #ifdef __mono_ppc64__
2734 g_assert_not_reached ();
2736 PatchData *pdata = (PatchData*)user_data;
2737 guchar *code = data;
2738 guint32 *thunks = data;
2739 guint32 *endthunks = (guint32*)(code + bsize);
2743 int difflow, diffhigh;
2745 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2746 difflow = (char*)pdata->code - (char*)thunks;
2747 diffhigh = (char*)pdata->code - (char*)endthunks;
2748 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2751 templ = (guchar*)load;
2752 ppc_load_sequence (templ, ppc_r0, pdata->target);
2754 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2755 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2756 while (thunks < endthunks) {
2757 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2758 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2759 ppc_patch (pdata->code, (guchar*)thunks);
2762 static int num_thunks = 0;
2764 if ((num_thunks % 20) == 0)
2765 g_print ("num_thunks lookup: %d\n", num_thunks);
2768 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2769 /* found a free slot instead: emit thunk */
2770 code = (guchar*)thunks;
2771 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2772 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2773 ppc_mtctr (code, ppc_r0);
2774 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2775 mono_arch_flush_icache ((guchar*)thunks, 16);
2777 ppc_patch (pdata->code, (guchar*)thunks);
2780 static int num_thunks = 0;
2782 if ((num_thunks % 20) == 0)
2783 g_print ("num_thunks: %d\n", num_thunks);
2787 /* skip 16 bytes, the size of the thunk */
2791 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2798 handle_thunk (int absolute, guchar *code, const guchar *target) {
2799 MonoDomain *domain = mono_domain_get ();
2803 pdata.target = target;
2804 pdata.absolute = absolute;
2807 mono_domain_lock (domain);
2808 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2811 /* this uses the first available slot */
2813 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2815 mono_domain_unlock (domain);
2817 if (pdata.found != 1)
2818 g_print ("thunk failed for %p from %p\n", target, code);
2819 g_assert (pdata.found == 1);
2823 patch_ins (guint8 *code, guint32 ins)
2825 *(guint32*)code = ins;
2826 mono_arch_flush_icache (code, 4);
2830 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2832 guint32 ins = *(guint32*)code;
2833 guint32 prim = ins >> 26;
2836 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2838 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2839 gint diff = target - code;
2842 if (diff <= 33554431){
2843 ins = (18 << 26) | (diff) | (ins & 1);
2844 patch_ins (code, ins);
2848 /* diff between 0 and -33554432 */
2849 if (diff >= -33554432){
2850 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2851 patch_ins (code, ins);
2856 if ((glong)target >= 0){
2857 if ((glong)target <= 33554431){
2858 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2859 patch_ins (code, ins);
2863 if ((glong)target >= -33554432){
2864 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2865 patch_ins (code, ins);
2870 handle_thunk (TRUE, code, target);
2873 g_assert_not_reached ();
2881 guint32 li = (gulong)target;
2882 ins = (ins & 0xffff0000) | (ins & 3);
2883 ovf = li & 0xffff0000;
2884 if (ovf != 0 && ovf != 0xffff0000)
2885 g_assert_not_reached ();
2888 // FIXME: assert the top bits of li are 0
2890 gint diff = target - code;
2891 ins = (ins & 0xffff0000) | (ins & 3);
2892 ovf = diff & 0xffff0000;
2893 if (ovf != 0 && ovf != 0xffff0000)
2894 g_assert_not_reached ();
2898 patch_ins (code, ins);
2902 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2903 #ifdef __mono_ppc64__
2904 guint32 *seq = (guint32*)code;
2905 guint32 *branch_ins;
2907 /* the trampoline code will try to patch the blrl, blr, bcctr */
2908 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2910 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2915 if (ppc_is_load_op (seq [5])
2916 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2917 /* With function descs we need to do more careful
2919 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
2922 branch_ins = seq + 8;
2924 branch_ins = seq + 6;
2927 seq = (guint32*)code;
2928 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2929 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2931 if (ppc_is_load_op (seq [5])) {
2932 g_assert (ppc_is_load_op (seq [6]));
2935 guint8 *buf = (guint8*)&seq [5];
2936 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
2941 target = mono_get_addr_from_ftnptr ((gpointer)target);
2944 /* FIXME: make this thread safe */
2945 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2946 /* FIXME: we're assuming we're using r12 here */
2947 ppc_load_ptr_sequence (code, ppc_r12, target);
2949 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
2951 mono_arch_flush_icache ((guint8*)seq, 28);
2954 /* the trampoline code will try to patch the blrl, blr, bcctr */
2955 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2958 /* this is the lis/ori/mtlr/blrl sequence */
2959 seq = (guint32*)code;
2960 g_assert ((seq [0] >> 26) == 15);
2961 g_assert ((seq [1] >> 26) == 24);
2962 g_assert ((seq [2] >> 26) == 31);
2963 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2964 /* FIXME: make this thread safe */
2965 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
2966 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
2967 mono_arch_flush_icache (code - 8, 8);
2970 g_assert_not_reached ();
2972 // g_print ("patched with 0x%08x\n", ins);
2976 ppc_patch (guchar *code, const guchar *target)
2978 ppc_patch_full (code, target, FALSE);
2982 mono_ppc_patch (guchar *code, const guchar *target)
2984 ppc_patch (code, target);
2988 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2990 switch (ins->opcode) {
2993 case OP_FCALL_MEMBASE:
2994 if (ins->dreg != ppc_f1)
2995 ppc_fmr (code, ins->dreg, ppc_f1);
3003 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3005 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3009 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3011 long size = cfg->param_area;
3013 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3014 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3019 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3020 if (ppc_is_imm16 (-size)) {
3021 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3023 ppc_load (code, ppc_r12, -size);
3024 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3031 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3033 long size = cfg->param_area;
3035 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3036 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3041 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3042 if (ppc_is_imm16 (size)) {
3043 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3045 ppc_load (code, ppc_r12, size);
3046 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3052 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3056 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3058 MonoInst *ins, *next;
3061 guint8 *code = cfg->native_code + cfg->code_len;
3062 MonoInst *last_ins = NULL;
3063 guint last_offset = 0;
3067 /* we don't align basic blocks of loops on ppc */
3069 if (cfg->verbose_level > 2)
3070 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3072 cpos = bb->max_offset;
3074 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3075 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3076 //g_assert (!mono_compile_aot);
3079 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3080 /* this is not thread save, but good enough */
3081 /* fixme: howto handle overflows? */
3082 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3085 MONO_BB_FOR_EACH_INS (bb, ins) {
3086 offset = code - cfg->native_code;
3088 max_len = ins_native_length (cfg, ins);
3090 if (offset > (cfg->code_size - max_len - 16)) {
3091 cfg->code_size *= 2;
3092 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3093 code = cfg->native_code + offset;
3095 // if (ins->cil_code)
3096 // g_print ("cil code\n");
3097 mono_debug_record_line_number (cfg, ins, offset);
3099 switch (normalize_opcode (ins->opcode)) {
3100 case OP_RELAXED_NOP:
3103 case OP_DUMMY_STORE:
3104 case OP_NOT_REACHED:
3107 case OP_IL_SEQ_POINT:
3108 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3110 case OP_SEQ_POINT: {
3113 if (cfg->compile_aot)
3117 * Read from the single stepping trigger page. This will cause a
3118 * SIGSEGV when single stepping is enabled.
3119 * We do this _before_ the breakpoint, so single stepping after
3120 * a breakpoint is hit will step to the next IL offset.
3122 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3123 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3124 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3127 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3130 * A placeholder for a possible breakpoint inserted by
3131 * mono_arch_set_breakpoint ().
3133 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3138 emit_tls_access (code, ins->dreg, ins->inst_offset);
3141 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3142 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3143 ppc_mr (code, ppc_r4, ppc_r0);
3146 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3147 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3148 ppc_mr (code, ppc_r4, ppc_r0);
3150 case OP_MEMORY_BARRIER:
3153 case OP_STOREI1_MEMBASE_REG:
3154 if (ppc_is_imm16 (ins->inst_offset)) {
3155 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3157 if (ppc_is_imm32 (ins->inst_offset)) {
3158 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3159 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3161 ppc_load (code, ppc_r0, ins->inst_offset);
3162 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3166 case OP_STOREI2_MEMBASE_REG:
3167 if (ppc_is_imm16 (ins->inst_offset)) {
3168 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3170 if (ppc_is_imm32 (ins->inst_offset)) {
3171 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3172 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3174 ppc_load (code, ppc_r0, ins->inst_offset);
3175 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3179 case OP_STORE_MEMBASE_REG:
3180 if (ppc_is_imm16 (ins->inst_offset)) {
3181 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3183 if (ppc_is_imm32 (ins->inst_offset)) {
3184 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3185 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3187 ppc_load (code, ppc_r0, ins->inst_offset);
3188 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3192 #ifdef __mono_ilp32__
3193 case OP_STOREI8_MEMBASE_REG:
3194 if (ppc_is_imm16 (ins->inst_offset)) {
3195 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3197 ppc_load (code, ppc_r0, ins->inst_offset);
3198 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3202 case OP_STOREI1_MEMINDEX:
3203 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3205 case OP_STOREI2_MEMINDEX:
3206 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3208 case OP_STORE_MEMINDEX:
3209 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3212 g_assert_not_reached ();
3214 case OP_LOAD_MEMBASE:
3215 if (ppc_is_imm16 (ins->inst_offset)) {
3216 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3218 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3219 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3220 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3222 ppc_load (code, ppc_r0, ins->inst_offset);
3223 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3227 case OP_LOADI4_MEMBASE:
3228 #ifdef __mono_ppc64__
3229 if (ppc_is_imm16 (ins->inst_offset)) {
3230 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3232 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3233 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3234 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3236 ppc_load (code, ppc_r0, ins->inst_offset);
3237 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3242 case OP_LOADU4_MEMBASE:
3243 if (ppc_is_imm16 (ins->inst_offset)) {
3244 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3246 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3247 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3248 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3250 ppc_load (code, ppc_r0, ins->inst_offset);
3251 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3255 case OP_LOADI1_MEMBASE:
3256 case OP_LOADU1_MEMBASE:
3257 if (ppc_is_imm16 (ins->inst_offset)) {
3258 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3260 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3261 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3262 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3264 ppc_load (code, ppc_r0, ins->inst_offset);
3265 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3268 if (ins->opcode == OP_LOADI1_MEMBASE)
3269 ppc_extsb (code, ins->dreg, ins->dreg);
3271 case OP_LOADU2_MEMBASE:
3272 if (ppc_is_imm16 (ins->inst_offset)) {
3273 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3275 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3276 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3277 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3279 ppc_load (code, ppc_r0, ins->inst_offset);
3280 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3284 case OP_LOADI2_MEMBASE:
3285 if (ppc_is_imm16 (ins->inst_offset)) {
3286 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3288 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3289 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3290 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3292 ppc_load (code, ppc_r0, ins->inst_offset);
3293 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3297 #ifdef __mono_ilp32__
3298 case OP_LOADI8_MEMBASE:
3299 if (ppc_is_imm16 (ins->inst_offset)) {
3300 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3302 ppc_load (code, ppc_r0, ins->inst_offset);
3303 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3307 case OP_LOAD_MEMINDEX:
3308 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3310 case OP_LOADI4_MEMINDEX:
3311 #ifdef __mono_ppc64__
3312 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3315 case OP_LOADU4_MEMINDEX:
3316 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3318 case OP_LOADU2_MEMINDEX:
3319 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3321 case OP_LOADI2_MEMINDEX:
3322 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3324 case OP_LOADU1_MEMINDEX:
3325 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3327 case OP_LOADI1_MEMINDEX:
3328 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3329 ppc_extsb (code, ins->dreg, ins->dreg);
3331 case OP_ICONV_TO_I1:
3332 CASE_PPC64 (OP_LCONV_TO_I1)
3333 ppc_extsb (code, ins->dreg, ins->sreg1);
3335 case OP_ICONV_TO_I2:
3336 CASE_PPC64 (OP_LCONV_TO_I2)
3337 ppc_extsh (code, ins->dreg, ins->sreg1);
3339 case OP_ICONV_TO_U1:
3340 CASE_PPC64 (OP_LCONV_TO_U1)
3341 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3343 case OP_ICONV_TO_U2:
3344 CASE_PPC64 (OP_LCONV_TO_U2)
3345 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3349 CASE_PPC64 (OP_LCOMPARE)
3350 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3352 if (next && compare_opcode_is_unsigned (next->opcode))
3353 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3355 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3357 case OP_COMPARE_IMM:
3358 case OP_ICOMPARE_IMM:
3359 CASE_PPC64 (OP_LCOMPARE_IMM)
3360 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3362 if (next && compare_opcode_is_unsigned (next->opcode)) {
3363 if (ppc_is_uimm16 (ins->inst_imm)) {
3364 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3366 g_assert_not_reached ();
3369 if (ppc_is_imm16 (ins->inst_imm)) {
3370 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3372 g_assert_not_reached ();
3378 * gdb does not like encountering a trap in the debugged code. So
3379 * instead of emitting a trap, we emit a call a C function and place a
3383 ppc_mr (code, ppc_r3, ins->sreg1);
3384 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3385 (gpointer)"mono_break");
3386 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3387 ppc_load_func (code, PPC_CALL_REG, 0);
3388 ppc_mtlr (code, PPC_CALL_REG);
3396 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3399 CASE_PPC64 (OP_LADD)
3400 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3404 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3407 if (ppc_is_imm16 (ins->inst_imm)) {
3408 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3410 g_assert_not_reached ();
3415 CASE_PPC64 (OP_LADD_IMM)
3416 if (ppc_is_imm16 (ins->inst_imm)) {
3417 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3419 g_assert_not_reached ();
3423 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3425 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3426 ppc_mfspr (code, ppc_r0, ppc_xer);
3427 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3428 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3430 case OP_IADD_OVF_UN:
3431 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3433 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3434 ppc_mfspr (code, ppc_r0, ppc_xer);
3435 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3436 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3439 CASE_PPC64 (OP_LSUB_OVF)
3440 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3442 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3443 ppc_mfspr (code, ppc_r0, ppc_xer);
3444 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3445 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3447 case OP_ISUB_OVF_UN:
3448 CASE_PPC64 (OP_LSUB_OVF_UN)
3449 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3451 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3452 ppc_mfspr (code, ppc_r0, ppc_xer);
3453 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3454 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3456 case OP_ADD_OVF_CARRY:
3457 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3459 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3460 ppc_mfspr (code, ppc_r0, ppc_xer);
3461 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3462 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3464 case OP_ADD_OVF_UN_CARRY:
3465 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3467 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 ppc_mfspr (code, ppc_r0, ppc_xer);
3469 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3470 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3472 case OP_SUB_OVF_CARRY:
3473 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3475 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3476 ppc_mfspr (code, ppc_r0, ppc_xer);
3477 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3478 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3480 case OP_SUB_OVF_UN_CARRY:
3481 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3483 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3484 ppc_mfspr (code, ppc_r0, ppc_xer);
3485 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3486 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3490 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3493 CASE_PPC64 (OP_LSUB)
3494 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3498 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3502 CASE_PPC64 (OP_LSUB_IMM)
3503 // we add the negated value
3504 if (ppc_is_imm16 (-ins->inst_imm))
3505 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3507 g_assert_not_reached ();
3511 g_assert (ppc_is_imm16 (ins->inst_imm));
3512 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3515 ppc_subfze (code, ins->dreg, ins->sreg1);
3518 CASE_PPC64 (OP_LAND)
3519 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3520 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3524 CASE_PPC64 (OP_LAND_IMM)
3525 if (!(ins->inst_imm & 0xffff0000)) {
3526 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3527 } else if (!(ins->inst_imm & 0xffff)) {
3528 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3530 g_assert_not_reached ();
3534 CASE_PPC64 (OP_LDIV) {
3535 guint8 *divisor_is_m1;
3536 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3538 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3539 divisor_is_m1 = code;
3540 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3541 ppc_lis (code, ppc_r0, 0x8000);
3542 #ifdef __mono_ppc64__
3543 if (ins->opcode == OP_LDIV)
3544 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3546 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3547 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3548 ppc_patch (divisor_is_m1, code);
3549 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3551 if (ins->opcode == OP_IDIV)
3552 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3553 #ifdef __mono_ppc64__
3555 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3557 ppc_mfspr (code, ppc_r0, ppc_xer);
3558 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3559 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3563 CASE_PPC64 (OP_LDIV_UN)
3564 if (ins->opcode == OP_IDIV_UN)
3565 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 #ifdef __mono_ppc64__
3568 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3570 ppc_mfspr (code, ppc_r0, ppc_xer);
3571 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3572 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3578 g_assert_not_reached ();
3581 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3585 CASE_PPC64 (OP_LOR_IMM)
3586 if (!(ins->inst_imm & 0xffff0000)) {
3587 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3588 } else if (!(ins->inst_imm & 0xffff)) {
3589 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3591 g_assert_not_reached ();
3595 CASE_PPC64 (OP_LXOR)
3596 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3600 CASE_PPC64 (OP_LXOR_IMM)
3601 if (!(ins->inst_imm & 0xffff0000)) {
3602 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3603 } else if (!(ins->inst_imm & 0xffff)) {
3604 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3606 g_assert_not_reached ();
3610 CASE_PPC64 (OP_LSHL)
3611 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 CASE_PPC64 (OP_LSHL_IMM)
3616 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3619 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3622 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3625 if (MASK_SHIFT_IMM (ins->inst_imm))
3626 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3628 ppc_mr (code, ins->dreg, ins->sreg1);
3631 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3634 CASE_PPC64 (OP_LNOT)
3635 ppc_not (code, ins->dreg, ins->sreg1);
3638 CASE_PPC64 (OP_LNEG)
3639 ppc_neg (code, ins->dreg, ins->sreg1);
3642 CASE_PPC64 (OP_LMUL)
3643 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3647 CASE_PPC64 (OP_LMUL_IMM)
3648 if (ppc_is_imm16 (ins->inst_imm)) {
3649 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3651 g_assert_not_reached ();
3655 CASE_PPC64 (OP_LMUL_OVF)
3656 /* we annot use mcrxr, since it's not implemented on some processors
3657 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3659 if (ins->opcode == OP_IMUL_OVF)
3660 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 #ifdef __mono_ppc64__
3663 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3665 ppc_mfspr (code, ppc_r0, ppc_xer);
3666 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3667 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3669 case OP_IMUL_OVF_UN:
3670 CASE_PPC64 (OP_LMUL_OVF_UN)
3671 /* we first multiply to get the high word and compare to 0
3672 * to set the flags, then the result is discarded and then
3673 * we multiply to get the lower * bits result
3675 if (ins->opcode == OP_IMUL_OVF_UN)
3676 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3677 #ifdef __mono_ppc64__
3679 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3681 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3682 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3683 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3686 ppc_load (code, ins->dreg, ins->inst_c0);
3689 ppc_load (code, ins->dreg, ins->inst_l);
3692 case OP_LOAD_GOTADDR:
3693 /* The PLT implementation depends on this */
3694 g_assert (ins->dreg == ppc_r30);
3696 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3699 // FIXME: Fix max instruction length
3700 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3701 /* arch_emit_got_access () patches this */
3702 ppc_load32 (code, ppc_r0, 0);
3703 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3706 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3707 ppc_load_sequence (code, ins->dreg, 0);
3709 CASE_PPC32 (OP_ICONV_TO_I4)
3710 CASE_PPC32 (OP_ICONV_TO_U4)
3712 if (ins->dreg != ins->sreg1)
3713 ppc_mr (code, ins->dreg, ins->sreg1);
3716 int saved = ins->sreg1;
3717 if (ins->sreg1 == ppc_r3) {
3718 ppc_mr (code, ppc_r0, ins->sreg1);
3721 if (ins->sreg2 != ppc_r3)
3722 ppc_mr (code, ppc_r3, ins->sreg2);
3723 if (saved != ppc_r4)
3724 ppc_mr (code, ppc_r4, saved);
3728 if (ins->dreg != ins->sreg1)
3729 ppc_fmr (code, ins->dreg, ins->sreg1);
3731 case OP_FCONV_TO_R4:
3732 ppc_frsp (code, ins->dreg, ins->sreg1);
3736 MonoCallInst *call = (MonoCallInst*)ins;
3739 * Keep in sync with mono_arch_emit_epilog
3741 g_assert (!cfg->method->save_lmf);
3743 * Note: we can use ppc_r12 here because it is dead anyway:
3744 * we're leaving the method.
3746 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3747 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3748 if (ppc_is_imm16 (ret_offset)) {
3749 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3751 ppc_load (code, ppc_r12, ret_offset);
3752 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3754 ppc_mtlr (code, ppc_r0);
3757 if (ppc_is_imm16 (cfg->stack_usage)) {
3758 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3760 /* cfg->stack_usage is an int, so we can use
3761 * an addis/addi sequence here even in 64-bit. */
3762 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3763 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3765 if (!cfg->method->save_lmf) {
3767 for (i = 31; i >= 13; --i) {
3768 if (cfg->used_int_regs & (1 << i)) {
3769 pos += sizeof (gpointer);
3770 ppc_ldptr (code, i, -pos, ppc_r12);
3774 /* FIXME restore from MonoLMF: though this can't happen yet */
3777 /* Copy arguments on the stack to our argument area */
3778 if (call->stack_usage) {
3779 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3780 /* r12 was clobbered */
3781 g_assert (cfg->frame_reg == ppc_sp);
3782 if (ppc_is_imm16 (cfg->stack_usage)) {
3783 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3785 /* cfg->stack_usage is an int, so we can use
3786 * an addis/addi sequence here even in 64-bit. */
3787 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3788 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3792 ppc_mr (code, ppc_sp, ppc_r12);
3793 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3794 if (cfg->compile_aot) {
3795 /* arch_emit_got_access () patches this */
3796 ppc_load32 (code, ppc_r0, 0);
3797 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3798 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3799 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3801 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3803 ppc_mtctr (code, ppc_r0);
3804 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3811 /* ensure ins->sreg1 is not NULL */
3812 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3815 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3816 if (ppc_is_imm16 (cookie_offset)) {
3817 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3819 ppc_load (code, ppc_r0, cookie_offset);
3820 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3822 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3831 call = (MonoCallInst*)ins;
3832 if (ins->flags & MONO_INST_HAS_METHOD)
3833 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3835 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3836 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3837 ppc_load_func (code, PPC_CALL_REG, 0);
3838 ppc_mtlr (code, PPC_CALL_REG);
3843 /* FIXME: this should be handled somewhere else in the new jit */
3844 code = emit_move_return_value (cfg, ins, code);
3850 case OP_VOIDCALL_REG:
3852 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3853 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3854 /* FIXME: if we know that this is a method, we
3855 can omit this load */
3856 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3857 ppc_mtlr (code, ppc_r0);
3859 ppc_mtlr (code, ins->sreg1);
3862 /* FIXME: this should be handled somewhere else in the new jit */
3863 code = emit_move_return_value (cfg, ins, code);
3865 case OP_FCALL_MEMBASE:
3866 case OP_LCALL_MEMBASE:
3867 case OP_VCALL_MEMBASE:
3868 case OP_VCALL2_MEMBASE:
3869 case OP_VOIDCALL_MEMBASE:
3870 case OP_CALL_MEMBASE:
3871 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3872 /* The trampolines clobber this */
3873 ppc_mr (code, ppc_r29, ins->sreg1);
3874 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3876 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3878 ppc_mtlr (code, ppc_r0);
3880 /* FIXME: this should be handled somewhere else in the new jit */
3881 code = emit_move_return_value (cfg, ins, code);
3884 guint8 * zero_loop_jump, * zero_loop_start;
3885 /* keep alignment */
3886 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3887 int area_offset = alloca_waste;
3889 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3890 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3891 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3892 /* use ctr to store the number of words to 0 if needed */
3893 if (ins->flags & MONO_INST_INIT) {
3894 /* we zero 4 bytes at a time:
3895 * we add 7 instead of 3 so that we set the counter to
3896 * at least 1, otherwise the bdnz instruction will make
3897 * it negative and iterate billions of times.
3899 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3900 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3901 ppc_mtctr (code, ppc_r0);
3903 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3904 ppc_neg (code, ppc_r12, ppc_r12);
3905 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3907 /* FIXME: make this loop work in 8 byte
3908 increments on PPC64 */
3909 if (ins->flags & MONO_INST_INIT) {
3910 /* adjust the dest reg by -4 so we can use stwu */
3911 /* we actually adjust -8 because we let the loop
3914 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3915 ppc_li (code, ppc_r12, 0);
3916 zero_loop_start = code;
3917 ppc_stwu (code, ppc_r12, 4, ins->dreg);
3918 zero_loop_jump = code;
3919 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3920 ppc_patch (zero_loop_jump, zero_loop_start);
3922 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3927 ppc_mr (code, ppc_r3, ins->sreg1);
3928 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3929 (gpointer)"mono_arch_throw_exception");
3930 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3931 ppc_load_func (code, PPC_CALL_REG, 0);
3932 ppc_mtlr (code, PPC_CALL_REG);
3941 ppc_mr (code, ppc_r3, ins->sreg1);
3942 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3943 (gpointer)"mono_arch_rethrow_exception");
3944 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3945 ppc_load_func (code, PPC_CALL_REG, 0);
3946 ppc_mtlr (code, PPC_CALL_REG);
3953 case OP_START_HANDLER: {
3954 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3955 g_assert (spvar->inst_basereg != ppc_sp);
3956 code = emit_reserve_param_area (cfg, code);
3957 ppc_mflr (code, ppc_r0);
3958 if (ppc_is_imm16 (spvar->inst_offset)) {
3959 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3961 ppc_load (code, ppc_r12, spvar->inst_offset);
3962 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
3966 case OP_ENDFILTER: {
3967 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3968 g_assert (spvar->inst_basereg != ppc_sp);
3969 code = emit_unreserve_param_area (cfg, code);
3970 if (ins->sreg1 != ppc_r3)
3971 ppc_mr (code, ppc_r3, ins->sreg1);
3972 if (ppc_is_imm16 (spvar->inst_offset)) {
3973 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3975 ppc_load (code, ppc_r12, spvar->inst_offset);
3976 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
3978 ppc_mtlr (code, ppc_r0);
3982 case OP_ENDFINALLY: {
3983 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3984 g_assert (spvar->inst_basereg != ppc_sp);
3985 code = emit_unreserve_param_area (cfg, code);
3986 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3987 ppc_mtlr (code, ppc_r0);
3991 case OP_CALL_HANDLER:
3992 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3994 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3997 ins->inst_c0 = code - cfg->native_code;
4000 /*if (ins->inst_target_bb->native_offset) {
4002 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4004 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4009 ppc_mtctr (code, ins->sreg1);
4010 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4014 CASE_PPC64 (OP_LCEQ)
4015 ppc_li (code, ins->dreg, 0);
4016 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4017 ppc_li (code, ins->dreg, 1);
4023 CASE_PPC64 (OP_LCLT)
4024 CASE_PPC64 (OP_LCLT_UN)
4025 ppc_li (code, ins->dreg, 1);
4026 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4027 ppc_li (code, ins->dreg, 0);
4033 CASE_PPC64 (OP_LCGT)
4034 CASE_PPC64 (OP_LCGT_UN)
4035 ppc_li (code, ins->dreg, 1);
4036 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4037 ppc_li (code, ins->dreg, 0);
4039 case OP_COND_EXC_EQ:
4040 case OP_COND_EXC_NE_UN:
4041 case OP_COND_EXC_LT:
4042 case OP_COND_EXC_LT_UN:
4043 case OP_COND_EXC_GT:
4044 case OP_COND_EXC_GT_UN:
4045 case OP_COND_EXC_GE:
4046 case OP_COND_EXC_GE_UN:
4047 case OP_COND_EXC_LE:
4048 case OP_COND_EXC_LE_UN:
4049 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4051 case OP_COND_EXC_IEQ:
4052 case OP_COND_EXC_INE_UN:
4053 case OP_COND_EXC_ILT:
4054 case OP_COND_EXC_ILT_UN:
4055 case OP_COND_EXC_IGT:
4056 case OP_COND_EXC_IGT_UN:
4057 case OP_COND_EXC_IGE:
4058 case OP_COND_EXC_IGE_UN:
4059 case OP_COND_EXC_ILE:
4060 case OP_COND_EXC_ILE_UN:
4061 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4073 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4076 /* floating point opcodes */
4078 g_assert (cfg->compile_aot);
4080 /* FIXME: Optimize this */
4082 ppc_mflr (code, ppc_r12);
4084 *(double*)code = *(double*)ins->inst_p0;
4086 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4089 g_assert_not_reached ();
4091 case OP_STORER8_MEMBASE_REG:
4092 if (ppc_is_imm16 (ins->inst_offset)) {
4093 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4095 if (ppc_is_imm32 (ins->inst_offset)) {
4096 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4097 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4099 ppc_load (code, ppc_r0, ins->inst_offset);
4100 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4104 case OP_LOADR8_MEMBASE:
4105 if (ppc_is_imm16 (ins->inst_offset)) {
4106 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4108 if (ppc_is_imm32 (ins->inst_offset)) {
4109 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4110 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4112 ppc_load (code, ppc_r0, ins->inst_offset);
4113 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4117 case OP_STORER4_MEMBASE_REG:
4118 ppc_frsp (code, ins->sreg1, ins->sreg1);
4119 if (ppc_is_imm16 (ins->inst_offset)) {
4120 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4122 if (ppc_is_imm32 (ins->inst_offset)) {
4123 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4124 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4126 ppc_load (code, ppc_r0, ins->inst_offset);
4127 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4131 case OP_LOADR4_MEMBASE:
4132 if (ppc_is_imm16 (ins->inst_offset)) {
4133 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4135 if (ppc_is_imm32 (ins->inst_offset)) {
4136 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4137 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4139 ppc_load (code, ppc_r0, ins->inst_offset);
4140 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4144 case OP_LOADR4_MEMINDEX:
4145 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4147 case OP_LOADR8_MEMINDEX:
4148 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4150 case OP_STORER4_MEMINDEX:
4151 ppc_frsp (code, ins->sreg1, ins->sreg1);
4152 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4154 case OP_STORER8_MEMINDEX:
4155 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4158 case CEE_CONV_R4: /* FIXME: change precision */
4160 g_assert_not_reached ();
4161 case OP_FCONV_TO_I1:
4162 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4164 case OP_FCONV_TO_U1:
4165 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4167 case OP_FCONV_TO_I2:
4168 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4170 case OP_FCONV_TO_U2:
4171 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4173 case OP_FCONV_TO_I4:
4175 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4177 case OP_FCONV_TO_U4:
4179 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4181 case OP_LCONV_TO_R_UN:
4182 g_assert_not_reached ();
4183 /* Implemented as helper calls */
4185 case OP_LCONV_TO_OVF_I4_2:
4186 case OP_LCONV_TO_OVF_I: {
4187 #ifdef __mono_ppc64__
4190 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4191 // Check if its negative
4192 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4193 negative_branch = code;
4194 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4195 // Its positive msword == 0
4196 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4197 msword_positive_branch = code;
4198 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4200 ovf_ex_target = code;
4201 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4203 ppc_patch (negative_branch, code);
4204 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4205 msword_negative_branch = code;
4206 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4207 ppc_patch (msword_negative_branch, ovf_ex_target);
4209 ppc_patch (msword_positive_branch, code);
4210 if (ins->dreg != ins->sreg1)
4211 ppc_mr (code, ins->dreg, ins->sreg1);
4216 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4219 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4222 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4225 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4228 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4231 ppc_fneg (code, ins->dreg, ins->sreg1);
4235 g_assert_not_reached ();
4238 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4241 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4242 ppc_li (code, ins->dreg, 0);
4243 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4244 ppc_li (code, ins->dreg, 1);
4247 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4248 ppc_li (code, ins->dreg, 1);
4249 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4250 ppc_li (code, ins->dreg, 0);
4253 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4254 ppc_li (code, ins->dreg, 1);
4255 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4256 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4257 ppc_li (code, ins->dreg, 0);
4260 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4261 ppc_li (code, ins->dreg, 1);
4262 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4263 ppc_li (code, ins->dreg, 0);
4266 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4267 ppc_li (code, ins->dreg, 1);
4268 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4269 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4270 ppc_li (code, ins->dreg, 0);
4273 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4276 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4279 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4280 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4283 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4284 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4287 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4288 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4291 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4292 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4295 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4296 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4299 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4302 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4303 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4306 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4309 g_assert_not_reached ();
4310 case OP_CHECK_FINITE: {
4311 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4312 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4313 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4314 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4317 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4318 #ifdef __mono_ppc64__
4319 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4321 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4326 #ifdef __mono_ppc64__
4327 case OP_ICONV_TO_I4:
4329 ppc_extsw (code, ins->dreg, ins->sreg1);
4331 case OP_ICONV_TO_U4:
4333 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4335 case OP_ICONV_TO_R4:
4336 case OP_ICONV_TO_R8:
4337 case OP_LCONV_TO_R4:
4338 case OP_LCONV_TO_R8: {
4340 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4341 ppc_extsw (code, ppc_r0, ins->sreg1);
4346 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4347 ppc_mffgpr (code, ins->dreg, tmp);
4349 ppc_str (code, tmp, -8, ppc_r1);
4350 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4352 ppc_fcfid (code, ins->dreg, ins->dreg);
4353 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4354 ppc_frsp (code, ins->dreg, ins->dreg);
4358 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4361 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4364 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4366 ppc_mfspr (code, ppc_r0, ppc_xer);
4367 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4368 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4370 case OP_COND_EXC_OV:
4371 ppc_mfspr (code, ppc_r0, ppc_xer);
4372 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4373 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4385 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4387 case OP_FCONV_TO_I8:
4388 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4390 case OP_FCONV_TO_U8:
4391 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4393 case OP_STOREI4_MEMBASE_REG:
4394 if (ppc_is_imm16 (ins->inst_offset)) {
4395 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4397 ppc_load (code, ppc_r0, ins->inst_offset);
4398 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4401 case OP_STOREI4_MEMINDEX:
4402 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4405 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4407 case OP_ISHR_UN_IMM:
4408 if (ins->inst_imm & 0x1f)
4409 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4411 ppc_mr (code, ins->dreg, ins->sreg1);
4413 case OP_ATOMIC_ADD_I4:
4414 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4415 int location = ins->inst_basereg;
4416 int addend = ins->sreg2;
4417 guint8 *loop, *branch;
4418 g_assert (ins->inst_offset == 0);
4422 if (ins->opcode == OP_ATOMIC_ADD_I4)
4423 ppc_lwarx (code, ppc_r0, 0, location);
4424 #ifdef __mono_ppc64__
4426 ppc_ldarx (code, ppc_r0, 0, location);
4429 ppc_add (code, ppc_r0, ppc_r0, addend);
4431 if (ins->opcode == OP_ATOMIC_ADD_I4)
4432 ppc_stwcxd (code, ppc_r0, 0, location);
4433 #ifdef __mono_ppc64__
4435 ppc_stdcxd (code, ppc_r0, 0, location);
4439 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4440 ppc_patch (branch, loop);
4443 ppc_mr (code, ins->dreg, ppc_r0);
4447 case OP_ICONV_TO_R4:
4448 case OP_ICONV_TO_R8: {
4449 if (cpu_hw_caps & PPC_ISA_64) {
4450 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4451 ppc_stw (code, ppc_r0, -8, ppc_r1);
4452 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4453 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4454 ppc_fcfid (code, ins->dreg, ins->dreg);
4455 if (ins->opcode == OP_ICONV_TO_R4)
4456 ppc_frsp (code, ins->dreg, ins->dreg);
4461 case OP_ATOMIC_CAS_I4:
4462 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4463 int location = ins->sreg1;
4464 int value = ins->sreg2;
4465 int comparand = ins->sreg3;
4466 guint8 *start, *not_equal, *lost_reservation;
4470 if (ins->opcode == OP_ATOMIC_CAS_I4)
4471 ppc_lwarx (code, ppc_r0, 0, location);
4472 #ifdef __mono_ppc64__
4474 ppc_ldarx (code, ppc_r0, 0, location);
4477 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4479 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4481 if (ins->opcode == OP_ATOMIC_CAS_I4)
4482 ppc_stwcxd (code, value, 0, location);
4483 #ifdef __mono_ppc64__
4485 ppc_stdcxd (code, value, 0, location);
4488 lost_reservation = code;
4489 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4490 ppc_patch (lost_reservation, start);
4491 ppc_patch (not_equal, code);
4494 ppc_mr (code, ins->dreg, ppc_r0);
4499 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4500 g_assert_not_reached ();
4503 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4504 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4505 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4506 g_assert_not_reached ();
4512 last_offset = offset;
4515 cfg->code_len = code - cfg->native_code;
4517 #endif /* !DISABLE_JIT */
4520 mono_arch_register_lowlevel_calls (void)
4522 /* The signature doesn't matter */
4523 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4526 #ifdef __mono_ppc64__
4527 #ifdef _LITTLE_ENDIAN
4528 #define patch_load_sequence(ip,val) do {\
4529 guint16 *__load = (guint16*)(ip); \
4530 g_assert (sizeof (val) == sizeof (gsize)); \
4531 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4532 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4533 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4534 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4536 #elif defined _BIG_ENDIAN
4537 #define patch_load_sequence(ip,val) do {\
4538 guint16 *__load = (guint16*)(ip); \
4539 g_assert (sizeof (val) == sizeof (gsize)); \
4540 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4541 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4542 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4543 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4546 #error huh? No endianess defined by compiler
4549 #define patch_load_sequence(ip,val) do {\
4550 guint16 *__lis_ori = (guint16*)(ip); \
4551 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4552 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4558 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4560 MonoJumpInfo *patch_info;
4561 gboolean compile_aot = !run_cctors;
4563 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4564 unsigned char *ip = patch_info->ip.i + code;
4565 unsigned char *target;
4566 gboolean is_fd = FALSE;
4568 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4571 switch (patch_info->type) {
4572 case MONO_PATCH_INFO_BB:
4573 case MONO_PATCH_INFO_LABEL:
4576 /* No need to patch these */
4581 switch (patch_info->type) {
4582 case MONO_PATCH_INFO_IP:
4583 patch_load_sequence (ip, ip);
4585 case MONO_PATCH_INFO_METHOD_REL:
4586 g_assert_not_reached ();
4587 *((gpointer *)(ip)) = code + patch_info->data.offset;
4589 case MONO_PATCH_INFO_SWITCH: {
4590 gpointer *table = (gpointer *)patch_info->data.table->table;
4593 patch_load_sequence (ip, table);
4595 for (i = 0; i < patch_info->data.table->table_size; i++) {
4596 table [i] = (glong)patch_info->data.table->table [i] + code;
4598 /* we put into the table the absolute address, no need for ppc_patch in this case */
4601 case MONO_PATCH_INFO_METHODCONST:
4602 case MONO_PATCH_INFO_CLASS:
4603 case MONO_PATCH_INFO_IMAGE:
4604 case MONO_PATCH_INFO_FIELD:
4605 case MONO_PATCH_INFO_VTABLE:
4606 case MONO_PATCH_INFO_IID:
4607 case MONO_PATCH_INFO_SFLDA:
4608 case MONO_PATCH_INFO_LDSTR:
4609 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4610 case MONO_PATCH_INFO_LDTOKEN:
4611 /* from OP_AOTCONST : lis + ori */
4612 patch_load_sequence (ip, target);
4614 case MONO_PATCH_INFO_R4:
4615 case MONO_PATCH_INFO_R8:
4616 g_assert_not_reached ();
4617 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4619 case MONO_PATCH_INFO_EXC_NAME:
4620 g_assert_not_reached ();
4621 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4623 case MONO_PATCH_INFO_NONE:
4624 case MONO_PATCH_INFO_BB_OVF:
4625 case MONO_PATCH_INFO_EXC_OVF:
4626 /* everything is dealt with at epilog output time */
4628 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4629 case MONO_PATCH_INFO_INTERNAL_METHOD:
4630 case MONO_PATCH_INFO_ABS:
4631 case MONO_PATCH_INFO_CLASS_INIT:
4632 case MONO_PATCH_INFO_RGCTX_FETCH:
4633 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4640 ppc_patch_full (ip, target, is_fd);
4645 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4646 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4647 * the instruction offset immediate for all the registers.
4650 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4654 for (i = 13; i <= 31; i++) {
4655 if (used_int_regs & (1 << i)) {
4656 ppc_str (code, i, pos, base_reg);
4657 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4658 pos += sizeof (mgreg_t);
4662 /* pos is the start of the MonoLMF structure */
4663 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4664 for (i = 13; i <= 31; i++) {
4665 ppc_str (code, i, offset, base_reg);
4666 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4667 offset += sizeof (mgreg_t);
4669 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4670 for (i = 14; i < 32; i++) {
4671 ppc_stfd (code, i, offset, base_reg);
4672 offset += sizeof (gdouble);
4679 * Stack frame layout:
4681 * ------------------- sp
4682 * MonoLMF structure or saved registers
4683 * -------------------
4685 * -------------------
4687 * -------------------
4688 * optional 8 bytes for tracing
4689 * -------------------
4690 * param area size is cfg->param_area
4691 * -------------------
4692 * linkage area size is PPC_STACK_PARAM_OFFSET
4693 * ------------------- sp
4697 mono_arch_emit_prolog (MonoCompile *cfg)
4699 MonoMethod *method = cfg->method;
4701 MonoMethodSignature *sig;
4703 long alloc_size, pos, max_offset, cfa_offset;
4709 int tailcall_struct_index;
4711 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4714 sig = mono_method_signature (method);
4715 cfg->code_size = 512 + sig->param_count * 32;
4716 code = cfg->native_code = g_malloc (cfg->code_size);
4720 /* We currently emit unwind info for aot, but don't use it */
4721 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4723 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4724 ppc_mflr (code, ppc_r0);
4725 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4726 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4729 alloc_size = cfg->stack_offset;
4732 if (!method->save_lmf) {
4733 for (i = 31; i >= 13; --i) {
4734 if (cfg->used_int_regs & (1 << i)) {
4735 pos += sizeof (mgreg_t);
4739 pos += sizeof (MonoLMF);
4743 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4744 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4745 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4746 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4749 cfg->stack_usage = alloc_size;
4750 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4752 if (ppc_is_imm16 (-alloc_size)) {
4753 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4754 cfa_offset = alloc_size;
4755 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4756 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4759 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4760 ppc_load (code, ppc_r0, -alloc_size);
4761 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4762 cfa_offset = alloc_size;
4763 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4764 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4767 if (cfg->frame_reg != ppc_sp) {
4768 ppc_mr (code, cfg->frame_reg, ppc_sp);
4769 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4772 /* store runtime generic context */
4773 if (cfg->rgctx_var) {
4774 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4775 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4777 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4780 /* compute max_offset in order to use short forward jumps
4781 * we always do it on ppc because the immediate displacement
4782 * for jumps is too small
4785 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4787 bb->max_offset = max_offset;
4789 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4792 MONO_BB_FOR_EACH_INS (bb, ins)
4793 max_offset += ins_native_length (cfg, ins);
4796 /* load arguments allocated to register from the stack */
4799 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4801 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4802 ArgInfo *ainfo = &cinfo->ret;
4804 inst = cfg->vret_addr;
4807 if (ppc_is_imm16 (inst->inst_offset)) {
4808 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4810 ppc_load (code, ppc_r12, inst->inst_offset);
4811 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4815 tailcall_struct_index = 0;
4816 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4817 ArgInfo *ainfo = cinfo->args + i;
4818 inst = cfg->args [pos];
4820 if (cfg->verbose_level > 2)
4821 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4822 if (inst->opcode == OP_REGVAR) {
4823 if (ainfo->regtype == RegTypeGeneral)
4824 ppc_mr (code, inst->dreg, ainfo->reg);
4825 else if (ainfo->regtype == RegTypeFP)
4826 ppc_fmr (code, inst->dreg, ainfo->reg);
4827 else if (ainfo->regtype == RegTypeBase) {
4828 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4829 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4831 g_assert_not_reached ();
4833 if (cfg->verbose_level > 2)
4834 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4836 /* the argument should be put on the stack: FIXME handle size != word */
4837 if (ainfo->regtype == RegTypeGeneral) {
4838 switch (ainfo->size) {
4840 if (ppc_is_imm16 (inst->inst_offset)) {
4841 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4843 if (ppc_is_imm32 (inst->inst_offset)) {
4844 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4845 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4847 ppc_load (code, ppc_r12, inst->inst_offset);
4848 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4853 if (ppc_is_imm16 (inst->inst_offset)) {
4854 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4856 if (ppc_is_imm32 (inst->inst_offset)) {
4857 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4858 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4860 ppc_load (code, ppc_r12, inst->inst_offset);
4861 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4865 #ifdef __mono_ppc64__
4867 if (ppc_is_imm16 (inst->inst_offset)) {
4868 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4870 if (ppc_is_imm32 (inst->inst_offset)) {
4871 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4872 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4874 ppc_load (code, ppc_r12, inst->inst_offset);
4875 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4880 if (ppc_is_imm16 (inst->inst_offset)) {
4881 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4883 ppc_load (code, ppc_r12, inst->inst_offset);
4884 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4889 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4890 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4891 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4893 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4894 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4895 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4896 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4901 if (ppc_is_imm16 (inst->inst_offset)) {
4902 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4904 if (ppc_is_imm32 (inst->inst_offset)) {
4905 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4906 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
4908 ppc_load (code, ppc_r12, inst->inst_offset);
4909 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4914 } else if (ainfo->regtype == RegTypeBase) {
4915 g_assert (ppc_is_imm16 (ainfo->offset));
4916 /* load the previous stack pointer in r12 */
4917 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4918 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
4919 switch (ainfo->size) {
4921 if (ppc_is_imm16 (inst->inst_offset)) {
4922 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4924 if (ppc_is_imm32 (inst->inst_offset)) {
4925 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4926 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
4928 ppc_load (code, ppc_r12, inst->inst_offset);
4929 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4934 if (ppc_is_imm16 (inst->inst_offset)) {
4935 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4937 if (ppc_is_imm32 (inst->inst_offset)) {
4938 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4939 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
4941 ppc_load (code, ppc_r12, inst->inst_offset);
4942 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4946 #ifdef __mono_ppc64__
4948 if (ppc_is_imm16 (inst->inst_offset)) {
4949 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4951 if (ppc_is_imm32 (inst->inst_offset)) {
4952 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4953 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
4955 ppc_load (code, ppc_r12, inst->inst_offset);
4956 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4961 if (ppc_is_imm16 (inst->inst_offset)) {
4962 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4964 ppc_load (code, ppc_r12, inst->inst_offset);
4965 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
4970 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4971 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4972 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4973 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
4974 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4976 /* use r11 to load the 2nd half of the long before we clobber r12. */
4977 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
4978 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4979 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4980 ppc_stw (code, ppc_r0, 0, ppc_r12);
4981 ppc_stw (code, ppc_r11, 4, ppc_r12);
4986 if (ppc_is_imm16 (inst->inst_offset)) {
4987 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4989 if (ppc_is_imm32 (inst->inst_offset)) {
4990 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4991 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
4993 ppc_load (code, ppc_r12, inst->inst_offset);
4994 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
4999 } else if (ainfo->regtype == RegTypeFP) {
5000 g_assert (ppc_is_imm16 (inst->inst_offset));
5001 if (ainfo->size == 8)
5002 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5003 else if (ainfo->size == 4)
5004 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5006 g_assert_not_reached ();
5007 } else if (ainfo->regtype == RegTypeStructByVal) {
5008 int doffset = inst->inst_offset;
5012 g_assert (ppc_is_imm16 (inst->inst_offset));
5013 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5014 /* FIXME: what if there is no class? */
5015 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5016 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5017 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5020 * Darwin handles 1 and 2 byte
5021 * structs specially by
5022 * loading h/b into the arg
5023 * register. Only done for
5027 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5029 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5033 #ifdef __mono_ppc64__
5035 g_assert (cur_reg == 0);
5036 ppc_sldi (code, ppc_r0, ainfo->reg,
5037 (sizeof (gpointer) - ainfo->bytes) * 8);
5038 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5042 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5043 inst->inst_basereg);
5046 soffset += sizeof (gpointer);
5047 doffset += sizeof (gpointer);
5049 if (ainfo->vtsize) {
5050 /* FIXME: we need to do the shifting here, too */
5053 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5054 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5055 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5056 code = emit_memcpy (code, size - soffset,
5057 inst->inst_basereg, doffset,
5058 ppc_r12, ainfo->offset + soffset);
5060 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5061 inst->inst_basereg, doffset,
5062 ppc_r12, ainfo->offset + soffset);
5065 } else if (ainfo->regtype == RegTypeStructByAddr) {
5066 /* if it was originally a RegTypeBase */
5067 if (ainfo->offset) {
5068 /* load the previous stack pointer in r12 */
5069 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5070 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5072 ppc_mr (code, ppc_r12, ainfo->reg);
5075 if (cfg->tailcall_valuetype_addrs) {
5076 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5078 g_assert (ppc_is_imm16 (addr->inst_offset));
5079 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5081 tailcall_struct_index++;
5084 g_assert (ppc_is_imm16 (inst->inst_offset));
5085 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5086 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5088 g_assert_not_reached ();
5093 if (method->save_lmf) {
5094 if (lmf_pthread_key != -1) {
5095 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5096 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5097 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5099 if (cfg->compile_aot) {
5100 /* Compute the got address which is needed by the PLT entry */
5101 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5103 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5104 (gpointer)"mono_get_lmf_addr");
5105 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5106 ppc_load_func (code, PPC_CALL_REG, 0);
5107 ppc_mtlr (code, PPC_CALL_REG);
5113 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5114 /* lmf_offset is the offset from the previous stack pointer,
5115 * alloc_size is the total stack space allocated, so the offset
5116 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5117 * The pointer to the struct is put in ppc_r12 (new_lmf).
5118 * The callee-saved registers are already in the MonoLMF structure
5120 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5121 /* ppc_r3 is the result from mono_get_lmf_addr () */
5122 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5123 /* new_lmf->previous_lmf = *lmf_addr */
5124 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5125 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5126 /* *(lmf_addr) = r12 */
5127 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5128 /* save method info */
5129 if (cfg->compile_aot)
5131 ppc_load (code, ppc_r0, 0);
5133 ppc_load_ptr (code, ppc_r0, method);
5134 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5135 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5136 /* save the current IP */
5137 if (cfg->compile_aot) {
5139 ppc_mflr (code, ppc_r0);
5141 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5142 #ifdef __mono_ppc64__
5143 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5145 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5148 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5152 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5154 cfg->code_len = code - cfg->native_code;
5155 g_assert (cfg->code_len <= cfg->code_size);
5162 mono_arch_emit_epilog (MonoCompile *cfg)
5164 MonoMethod *method = cfg->method;
5166 int max_epilog_size = 16 + 20*4;
5169 if (cfg->method->save_lmf)
5170 max_epilog_size += 128;
5172 if (mono_jit_trace_calls != NULL)
5173 max_epilog_size += 50;
5175 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5176 max_epilog_size += 50;
5178 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5179 cfg->code_size *= 2;
5180 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5181 cfg->stat_code_reallocs++;
5185 * Keep in sync with OP_JMP
5187 code = cfg->native_code + cfg->code_len;
5189 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5190 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5194 if (method->save_lmf) {
5196 pos += sizeof (MonoLMF);
5198 /* save the frame reg in r8 */
5199 ppc_mr (code, ppc_r8, cfg->frame_reg);
5200 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5201 /* r5 = previous_lmf */
5202 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5204 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5205 /* *(lmf_addr) = previous_lmf */
5206 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5207 /* FIXME: speedup: there is no actual need to restore the registers if
5208 * we didn't actually change them (idea from Zoltan).
5211 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5213 /*for (i = 14; i < 32; i++) {
5214 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5216 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5217 /* use the saved copy of the frame reg in r8 */
5218 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5219 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5220 ppc_mtlr (code, ppc_r0);
5222 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5224 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5225 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5226 if (ppc_is_imm16 (return_offset)) {
5227 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5229 ppc_load (code, ppc_r12, return_offset);
5230 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5232 ppc_mtlr (code, ppc_r0);
5234 if (ppc_is_imm16 (cfg->stack_usage)) {
5235 int offset = cfg->stack_usage;
5236 for (i = 13; i <= 31; i++) {
5237 if (cfg->used_int_regs & (1 << i))
5238 offset -= sizeof (mgreg_t);
5240 if (cfg->frame_reg != ppc_sp)
5241 ppc_mr (code, ppc_r12, cfg->frame_reg);
5242 /* note r31 (possibly the frame register) is restored last */
5243 for (i = 13; i <= 31; i++) {
5244 if (cfg->used_int_regs & (1 << i)) {
5245 ppc_ldr (code, i, offset, cfg->frame_reg);
5246 offset += sizeof (mgreg_t);
5249 if (cfg->frame_reg != ppc_sp)
5250 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5252 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5254 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5255 if (cfg->used_int_regs) {
5256 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5257 for (i = 31; i >= 13; --i) {
5258 if (cfg->used_int_regs & (1 << i)) {
5259 pos += sizeof (mgreg_t);
5260 ppc_ldr (code, i, -pos, ppc_r12);
5263 ppc_mr (code, ppc_sp, ppc_r12);
5265 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5272 cfg->code_len = code - cfg->native_code;
5274 g_assert (cfg->code_len < cfg->code_size);
5277 #endif /* ifndef DISABLE_JIT */
5279 /* remove once throw_exception_by_name is eliminated */
5281 exception_id_by_name (const char *name)
5283 if (strcmp (name, "IndexOutOfRangeException") == 0)
5284 return MONO_EXC_INDEX_OUT_OF_RANGE;
5285 if (strcmp (name, "OverflowException") == 0)
5286 return MONO_EXC_OVERFLOW;
5287 if (strcmp (name, "ArithmeticException") == 0)
5288 return MONO_EXC_ARITHMETIC;
5289 if (strcmp (name, "DivideByZeroException") == 0)
5290 return MONO_EXC_DIVIDE_BY_ZERO;
5291 if (strcmp (name, "InvalidCastException") == 0)
5292 return MONO_EXC_INVALID_CAST;
5293 if (strcmp (name, "NullReferenceException") == 0)
5294 return MONO_EXC_NULL_REF;
5295 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5296 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5297 if (strcmp (name, "ArgumentException") == 0)
5298 return MONO_EXC_ARGUMENT;
5299 g_error ("Unknown intrinsic exception %s\n", name);
5305 mono_arch_emit_exceptions (MonoCompile *cfg)
5307 MonoJumpInfo *patch_info;
5310 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5311 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5312 int max_epilog_size = 50;
5314 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5315 exc_throw_pos [i] = NULL;
5316 exc_throw_found [i] = 0;
5319 /* count the number of exception infos */
5322 * make sure we have enough space for exceptions
5324 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5325 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5326 i = exception_id_by_name (patch_info->data.target);
5327 if (!exc_throw_found [i]) {
5328 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5329 exc_throw_found [i] = TRUE;
5331 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5332 max_epilog_size += 12;
5333 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5334 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5335 i = exception_id_by_name (ovfj->data.exception);
5336 if (!exc_throw_found [i]) {
5337 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5338 exc_throw_found [i] = TRUE;
5340 max_epilog_size += 8;
5344 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5345 cfg->code_size *= 2;
5346 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5347 cfg->stat_code_reallocs++;
5350 code = cfg->native_code + cfg->code_len;
5352 /* add code to raise exceptions */
5353 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5354 switch (patch_info->type) {
5355 case MONO_PATCH_INFO_BB_OVF: {
5356 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5357 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5358 /* patch the initial jump */
5359 ppc_patch (ip, code);
5360 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5362 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5363 /* jump back to the true target */
5365 ip = ovfj->data.bb->native_offset + cfg->native_code;
5366 ppc_patch (code - 4, ip);
5367 patch_info->type = MONO_PATCH_INFO_NONE;
5370 case MONO_PATCH_INFO_EXC_OVF: {
5371 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5372 MonoJumpInfo *newji;
5373 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5374 unsigned char *bcl = code;
5375 /* patch the initial jump: we arrived here with a call */
5376 ppc_patch (ip, code);
5377 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5379 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5380 /* patch the conditional jump to the right handler */
5381 /* make it processed next */
5382 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5383 newji->type = MONO_PATCH_INFO_EXC;
5384 newji->ip.i = bcl - cfg->native_code;
5385 newji->data.target = ovfj->data.exception;
5386 newji->next = patch_info->next;
5387 patch_info->next = newji;
5388 patch_info->type = MONO_PATCH_INFO_NONE;
5391 case MONO_PATCH_INFO_EXC: {
5392 MonoClass *exc_class;
5394 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5395 i = exception_id_by_name (patch_info->data.target);
5396 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5397 ppc_patch (ip, exc_throw_pos [i]);
5398 patch_info->type = MONO_PATCH_INFO_NONE;
5401 exc_throw_pos [i] = code;
5404 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5405 g_assert (exc_class);
5407 ppc_patch (ip, code);
5408 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5409 ppc_load (code, ppc_r3, exc_class->type_token);
5410 /* we got here from a conditional call, so the calling ip is set in lr */
5411 ppc_mflr (code, ppc_r4);
5412 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5413 patch_info->data.name = "mono_arch_throw_corlib_exception";
5414 patch_info->ip.i = code - cfg->native_code;
5415 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5416 ppc_load_func (code, PPC_CALL_REG, 0);
5417 ppc_mtctr (code, PPC_CALL_REG);
5418 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5430 cfg->code_len = code - cfg->native_code;
5432 g_assert (cfg->code_len <= cfg->code_size);
5438 try_offset_access (void *value, guint32 idx)
5440 register void* me __asm__ ("r2");
5441 void ***p = (void***)((char*)me + 284);
5442 int idx1 = idx / 32;
5443 int idx2 = idx % 32;
5446 if (value != p[idx1][idx2])
5453 setup_tls_access (void)
5455 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5456 size_t conf_size = 0;
5459 /* FIXME for darwin */
5460 guint32 *ins, *code;
5461 guint32 cmplwi_1023, li_0x48, blr_ins;
5465 tls_mode = TLS_MODE_FAILED;
5468 if (tls_mode == TLS_MODE_FAILED)
5470 if (g_getenv ("MONO_NO_TLS")) {
5471 tls_mode = TLS_MODE_FAILED;
5475 if (tls_mode == TLS_MODE_DETECT) {
5476 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5477 tls_mode = TLS_MODE_DARWIN_G4;
5478 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5479 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5480 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5481 tls_mode = TLS_MODE_NPTL;
5482 #elif !defined(TARGET_PS3)
5483 ins = (guint32*)pthread_getspecific;
5484 /* uncond branch to the real method */
5485 if ((*ins >> 26) == 18) {
5487 val = (*ins & ~3) << 6;
5491 ins = (guint32*)(long)val;
5493 ins = (guint32*) ((char*)ins + val);
5496 code = &cmplwi_1023;
5497 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5499 ppc_li (code, ppc_r4, 0x48);
5502 if (*ins == cmplwi_1023) {
5503 int found_lwz_284 = 0;
5505 for (ptk = 0; ptk < 20; ++ptk) {
5507 if (!*ins || *ins == blr_ins)
5509 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5514 if (!found_lwz_284) {
5515 tls_mode = TLS_MODE_FAILED;
5518 tls_mode = TLS_MODE_LTHREADS;
5519 } else if (*ins == li_0x48) {
5521 /* uncond branch to the real method */
5522 if ((*ins >> 26) == 18) {
5524 val = (*ins & ~3) << 6;
5528 ins = (guint32*)(long)val;
5530 ins = (guint32*) ((char*)ins + val);
5532 code = (guint32*)&val;
5533 ppc_li (code, ppc_r0, 0x7FF2);
5534 if (ins [1] == val) {
5535 /* Darwin on G4, implement */
5536 tls_mode = TLS_MODE_FAILED;
5539 code = (guint32*)&val;
5540 ppc_mfspr (code, ppc_r3, 104);
5541 if (ins [1] != val) {
5542 tls_mode = TLS_MODE_FAILED;
5545 tls_mode = TLS_MODE_DARWIN_G5;
5548 tls_mode = TLS_MODE_FAILED;
5552 tls_mode = TLS_MODE_FAILED;
5558 if (tls_mode == TLS_MODE_DETECT)
5559 tls_mode = TLS_MODE_FAILED;
5560 if (tls_mode == TLS_MODE_FAILED)
5562 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5563 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5567 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5568 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5569 if (lmf_pthread_key == -1) {
5570 guint32 ptk = mono_jit_tls_id;
5572 /*g_print ("MonoLMF at: %d\n", ptk);*/
5573 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5574 init_tls_failed = 1;
5577 lmf_pthread_key = ptk;
5586 mono_arch_finish_init (void)
5588 setup_tls_access ();
5592 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5596 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5598 #define LOADSTORE_SIZE 4
5599 #define JUMP_IMM_SIZE 12
5600 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5601 #define ENABLE_WRONG_METHOD_CHECK 0
5604 * LOCKING: called with the domain lock held
5607 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5608 gpointer fail_tramp)
5612 guint8 *code, *start;
5614 for (i = 0; i < count; ++i) {
5615 MonoIMTCheckItem *item = imt_entries [i];
5616 if (item->is_equals) {
5617 if (item->check_target_idx) {
5618 if (!item->compare_done)
5619 item->chunk_size += CMP_SIZE;
5620 if (item->has_target_code)
5621 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5623 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5626 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5627 if (!item->has_target_code)
5628 item->chunk_size += LOADSTORE_SIZE;
5630 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5631 #if ENABLE_WRONG_METHOD_CHECK
5632 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5637 item->chunk_size += CMP_SIZE + BR_SIZE;
5638 imt_entries [item->check_target_idx]->compare_done = TRUE;
5640 size += item->chunk_size;
5642 /* the initial load of the vtable address */
5643 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5645 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5647 code = mono_domain_code_reserve (domain, size);
5652 * We need to save and restore r12 because it might be
5653 * used by the caller as the vtable register, so
5654 * clobbering it will trip up the magic trampoline.
5656 * FIXME: Get rid of this by making sure that r12 is
5657 * not used as the vtable register in interface calls.
5659 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5660 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5662 for (i = 0; i < count; ++i) {
5663 MonoIMTCheckItem *item = imt_entries [i];
5664 item->code_target = code;
5665 if (item->is_equals) {
5666 if (item->check_target_idx) {
5667 if (!item->compare_done) {
5668 ppc_load (code, ppc_r0, (gsize)item->key);
5669 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5671 item->jmp_code = code;
5672 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5673 if (item->has_target_code) {
5674 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5676 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5677 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5679 ppc_mtctr (code, ppc_r0);
5680 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5683 ppc_load (code, ppc_r0, (gulong)item->key);
5684 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5685 item->jmp_code = code;
5686 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5687 if (item->has_target_code) {
5688 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5691 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5692 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5694 ppc_mtctr (code, ppc_r0);
5695 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5696 ppc_patch (item->jmp_code, code);
5697 ppc_load_ptr (code, ppc_r0, fail_tramp);
5698 ppc_mtctr (code, ppc_r0);
5699 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5700 item->jmp_code = NULL;
5702 /* enable the commented code to assert on wrong method */
5703 #if ENABLE_WRONG_METHOD_CHECK
5704 ppc_load (code, ppc_r0, (guint32)item->key);
5705 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5706 item->jmp_code = code;
5707 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5709 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5710 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5711 ppc_mtctr (code, ppc_r0);
5712 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5713 #if ENABLE_WRONG_METHOD_CHECK
5714 ppc_patch (item->jmp_code, code);
5716 item->jmp_code = NULL;
5721 ppc_load (code, ppc_r0, (gulong)item->key);
5722 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5723 item->jmp_code = code;
5724 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5727 /* patch the branches to get to the target items */
5728 for (i = 0; i < count; ++i) {
5729 MonoIMTCheckItem *item = imt_entries [i];
5730 if (item->jmp_code) {
5731 if (item->check_target_idx) {
5732 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5738 mono_stats.imt_thunks_size += code - start;
5739 g_assert (code - start <= size);
5740 mono_arch_flush_icache (start, size);
5745 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5747 mgreg_t *r = (mgreg_t*)regs;
5749 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5753 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5755 mgreg_t *r = (mgreg_t*)regs;
5757 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5761 mono_arch_get_cie_program (void)
5765 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5771 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5778 mono_arch_print_tree (MonoInst *tree, int arity)
5784 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5787 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5789 g_assert (reg >= ppc_r13);
5791 return ctx->regs [reg - ppc_r13];
5795 mono_arch_get_patch_offset (guint8 *code)
5801 * mono_aot_emit_load_got_addr:
5803 * Emit code to load the got address.
5804 * On PPC, the result is placed into r30.
5807 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5810 ppc_mflr (code, ppc_r30);
5812 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5814 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5815 /* arch_emit_got_address () patches this */
5816 #if defined(TARGET_POWERPC64)
5822 ppc_load32 (code, ppc_r0, 0);
5823 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5830 * mono_ppc_emit_load_aotconst:
5832 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5833 * TARGET from the mscorlib GOT in full-aot code.
5834 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5838 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5840 /* Load the mscorlib got address */
5841 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5842 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5843 /* arch_emit_got_access () patches this */
5844 ppc_load32 (code, ppc_r0, 0);
5845 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5850 /* Soft Debug support */
5851 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5858 * mono_arch_set_breakpoint:
5860 * See mini-amd64.c for docs.
5863 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5866 guint8 *orig_code = code;
5868 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5869 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5871 g_assert (code - orig_code == BREAKPOINT_SIZE);
5873 mono_arch_flush_icache (orig_code, code - orig_code);
5877 * mono_arch_clear_breakpoint:
5879 * See mini-amd64.c for docs.
5882 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5887 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5890 mono_arch_flush_icache (ip, code - ip);
5894 * mono_arch_is_breakpoint_event:
5896 * See mini-amd64.c for docs.
5899 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5901 siginfo_t* sinfo = (siginfo_t*) info;
5902 /* Sometimes the address is off by 4 */
5903 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5910 * mono_arch_skip_breakpoint:
5912 * See mini-amd64.c for docs.
5915 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5917 /* skip the ldptr */
5918 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5926 * mono_arch_start_single_stepping:
5928 * See mini-amd64.c for docs.
5931 mono_arch_start_single_stepping (void)
5933 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5937 * mono_arch_stop_single_stepping:
5939 * See mini-amd64.c for docs.
5942 mono_arch_stop_single_stepping (void)
5944 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5948 * mono_arch_is_single_step_event:
5950 * See mini-amd64.c for docs.
5953 mono_arch_is_single_step_event (void *info, void *sigctx)
5955 siginfo_t* sinfo = (siginfo_t*) info;
5956 /* Sometimes the address is off by 4 */
5957 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5964 * mono_arch_skip_single_step:
5966 * See mini-amd64.c for docs.
5969 mono_arch_skip_single_step (MonoContext *ctx)
5971 /* skip the ldptr */
5972 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5976 * mono_arch_create_seq_point_info:
5978 * See mini-amd64.c for docs.
5981 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5988 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5990 ext->lmf.previous_lmf = prev_lmf;
5991 /* Mark that this is a MonoLMFExt */
5992 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5993 ext->lmf.ebp = (gssize)ext;
5999 mono_arch_opcode_supported (int opcode)
6002 case OP_ATOMIC_ADD_I4:
6003 case OP_ATOMIC_CAS_I4:
6004 #ifdef TARGET_POWERPC64
6005 case OP_ATOMIC_ADD_I8:
6006 case OP_ATOMIC_CAS_I8: