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 // This value is OK as-is for both big and little endian because of how it is stored
2151 static const guint64 adjust_val = 0x4330000000000000ULL;
2152 int msw_reg = mono_alloc_ireg (cfg);
2153 int adj_reg = mono_alloc_freg (cfg);
2154 int tmp_reg = mono_alloc_freg (cfg);
2155 int basereg = ppc_sp;
2157 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2158 if (!ppc_is_imm16 (offset + 4)) {
2159 basereg = mono_alloc_ireg (cfg);
2160 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2162 #if G_BYTE_ORDER == G_BIG_ENDIAN
2163 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2164 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2166 // For little endian the words are reversed
2167 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2168 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2170 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2171 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2173 ins->opcode = OP_NOP;
2176 #ifndef __mono_ppc64__
2177 case OP_ICONV_TO_R4:
2178 case OP_ICONV_TO_R8: {
2179 /* If we have a PPC_FEATURE_64 machine we can avoid
2180 this and use the fcfid instruction. Otherwise
2181 on an old 32-bit chip and we have to do this the
2183 if (!(cpu_hw_caps & PPC_ISA_64)) {
2184 /* FIXME: change precision for CEE_CONV_R4 */
2185 static const guint64 adjust_val = 0x4330000080000000ULL;
2186 int msw_reg = mono_alloc_ireg (cfg);
2187 int xored = mono_alloc_ireg (cfg);
2188 int adj_reg = mono_alloc_freg (cfg);
2189 int tmp_reg = mono_alloc_freg (cfg);
2190 int basereg = ppc_sp;
2192 if (!ppc_is_imm16 (offset + 4)) {
2193 basereg = mono_alloc_ireg (cfg);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2196 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2197 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2199 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2200 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2201 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2203 if (ins->opcode == OP_ICONV_TO_R4)
2204 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2205 ins->opcode = OP_NOP;
2211 int msw_reg = mono_alloc_ireg (cfg);
2212 int basereg = ppc_sp;
2214 if (!ppc_is_imm16 (offset + 4)) {
2215 basereg = mono_alloc_ireg (cfg);
2216 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2218 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2219 #if G_BYTE_ORDER == G_BIG_ENDIAN
2220 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2222 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2224 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2225 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2226 ins->opcode = OP_NOP;
2229 #ifdef __mono_ppc64__
2231 case OP_IADD_OVF_UN:
2233 int shifted1_reg = mono_alloc_ireg (cfg);
2234 int shifted2_reg = mono_alloc_ireg (cfg);
2235 int result_shifted_reg = mono_alloc_ireg (cfg);
2237 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2238 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2239 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2240 if (ins->opcode == OP_IADD_OVF_UN)
2241 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2243 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2244 ins->opcode = OP_NOP;
2251 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2253 switch (ins->opcode) {
2255 /* ADC sets the condition code */
2256 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2257 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2260 case OP_LADD_OVF_UN:
2261 /* ADC sets the condition code */
2262 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2267 /* SBB sets the condition code */
2268 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2272 case OP_LSUB_OVF_UN:
2273 /* SBB sets the condition code */
2274 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2279 /* From gcc generated code */
2280 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2281 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2290 * the branch_b0_table should maintain the order of these
2304 branch_b0_table [] = {
2319 branch_b1_table [] = {
2333 #define NEW_INS(cfg,dest,op) do { \
2334 MONO_INST_NEW((cfg), (dest), (op)); \
2335 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2339 map_to_reg_reg_op (int op)
2348 case OP_COMPARE_IMM:
2350 case OP_ICOMPARE_IMM:
2352 case OP_LCOMPARE_IMM:
2368 case OP_LOAD_MEMBASE:
2369 return OP_LOAD_MEMINDEX;
2370 case OP_LOADI4_MEMBASE:
2371 return OP_LOADI4_MEMINDEX;
2372 case OP_LOADU4_MEMBASE:
2373 return OP_LOADU4_MEMINDEX;
2374 case OP_LOADI8_MEMBASE:
2375 return OP_LOADI8_MEMINDEX;
2376 case OP_LOADU1_MEMBASE:
2377 return OP_LOADU1_MEMINDEX;
2378 case OP_LOADI2_MEMBASE:
2379 return OP_LOADI2_MEMINDEX;
2380 case OP_LOADU2_MEMBASE:
2381 return OP_LOADU2_MEMINDEX;
2382 case OP_LOADI1_MEMBASE:
2383 return OP_LOADI1_MEMINDEX;
2384 case OP_LOADR4_MEMBASE:
2385 return OP_LOADR4_MEMINDEX;
2386 case OP_LOADR8_MEMBASE:
2387 return OP_LOADR8_MEMINDEX;
2388 case OP_STOREI1_MEMBASE_REG:
2389 return OP_STOREI1_MEMINDEX;
2390 case OP_STOREI2_MEMBASE_REG:
2391 return OP_STOREI2_MEMINDEX;
2392 case OP_STOREI4_MEMBASE_REG:
2393 return OP_STOREI4_MEMINDEX;
2394 case OP_STOREI8_MEMBASE_REG:
2395 return OP_STOREI8_MEMINDEX;
2396 case OP_STORE_MEMBASE_REG:
2397 return OP_STORE_MEMINDEX;
2398 case OP_STORER4_MEMBASE_REG:
2399 return OP_STORER4_MEMINDEX;
2400 case OP_STORER8_MEMBASE_REG:
2401 return OP_STORER8_MEMINDEX;
2402 case OP_STORE_MEMBASE_IMM:
2403 return OP_STORE_MEMBASE_REG;
2404 case OP_STOREI1_MEMBASE_IMM:
2405 return OP_STOREI1_MEMBASE_REG;
2406 case OP_STOREI2_MEMBASE_IMM:
2407 return OP_STOREI2_MEMBASE_REG;
2408 case OP_STOREI4_MEMBASE_IMM:
2409 return OP_STOREI4_MEMBASE_REG;
2410 case OP_STOREI8_MEMBASE_IMM:
2411 return OP_STOREI8_MEMBASE_REG;
2413 return mono_op_imm_to_op (op);
2416 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2418 #define compare_opcode_is_unsigned(opcode) \
2419 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2420 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2421 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2422 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2423 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2424 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2425 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2426 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2429 * Remove from the instruction list the instructions that can't be
2430 * represented with very simple instructions with no register
2434 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2436 MonoInst *ins, *next, *temp, *last_ins = NULL;
2439 MONO_BB_FOR_EACH_INS (bb, ins) {
2441 switch (ins->opcode) {
2442 case OP_IDIV_UN_IMM:
2445 case OP_IREM_UN_IMM:
2446 CASE_PPC64 (OP_LREM_IMM) {
2447 NEW_INS (cfg, temp, OP_ICONST);
2448 temp->inst_c0 = ins->inst_imm;
2449 temp->dreg = mono_alloc_ireg (cfg);
2450 ins->sreg2 = temp->dreg;
2451 if (ins->opcode == OP_IDIV_IMM)
2452 ins->opcode = OP_IDIV;
2453 else if (ins->opcode == OP_IREM_IMM)
2454 ins->opcode = OP_IREM;
2455 else if (ins->opcode == OP_IDIV_UN_IMM)
2456 ins->opcode = OP_IDIV_UN;
2457 else if (ins->opcode == OP_IREM_UN_IMM)
2458 ins->opcode = OP_IREM_UN;
2459 else if (ins->opcode == OP_LREM_IMM)
2460 ins->opcode = OP_LREM;
2462 /* handle rem separately */
2467 CASE_PPC64 (OP_LREM)
2468 CASE_PPC64 (OP_LREM_UN) {
2470 /* we change a rem dest, src1, src2 to
2471 * div temp1, src1, src2
2472 * mul temp2, temp1, src2
2473 * sub dest, src1, temp2
2475 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2476 NEW_INS (cfg, mul, OP_IMUL);
2477 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2478 ins->opcode = OP_ISUB;
2480 NEW_INS (cfg, mul, OP_LMUL);
2481 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2482 ins->opcode = OP_LSUB;
2484 temp->sreg1 = ins->sreg1;
2485 temp->sreg2 = ins->sreg2;
2486 temp->dreg = mono_alloc_ireg (cfg);
2487 mul->sreg1 = temp->dreg;
2488 mul->sreg2 = ins->sreg2;
2489 mul->dreg = mono_alloc_ireg (cfg);
2490 ins->sreg2 = mul->dreg;
2494 CASE_PPC64 (OP_LADD_IMM)
2497 if (!ppc_is_imm16 (ins->inst_imm)) {
2498 NEW_INS (cfg, temp, OP_ICONST);
2499 temp->inst_c0 = ins->inst_imm;
2500 temp->dreg = mono_alloc_ireg (cfg);
2501 ins->sreg2 = temp->dreg;
2502 ins->opcode = map_to_reg_reg_op (ins->opcode);
2506 CASE_PPC64 (OP_LSUB_IMM)
2508 if (!ppc_is_imm16 (-ins->inst_imm)) {
2509 NEW_INS (cfg, temp, OP_ICONST);
2510 temp->inst_c0 = ins->inst_imm;
2511 temp->dreg = mono_alloc_ireg (cfg);
2512 ins->sreg2 = temp->dreg;
2513 ins->opcode = map_to_reg_reg_op (ins->opcode);
2525 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2526 #ifdef __mono_ppc64__
2527 if (ins->inst_imm & 0xffffffff00000000ULL)
2531 NEW_INS (cfg, temp, OP_ICONST);
2532 temp->inst_c0 = ins->inst_imm;
2533 temp->dreg = mono_alloc_ireg (cfg);
2534 ins->sreg2 = temp->dreg;
2535 ins->opcode = map_to_reg_reg_op (ins->opcode);
2544 NEW_INS (cfg, temp, OP_ICONST);
2545 temp->inst_c0 = ins->inst_imm;
2546 temp->dreg = mono_alloc_ireg (cfg);
2547 ins->sreg2 = temp->dreg;
2548 ins->opcode = map_to_reg_reg_op (ins->opcode);
2550 case OP_COMPARE_IMM:
2551 case OP_ICOMPARE_IMM:
2552 CASE_PPC64 (OP_LCOMPARE_IMM)
2554 /* Branch opts can eliminate the branch */
2555 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2556 ins->opcode = OP_NOP;
2560 if (compare_opcode_is_unsigned (next->opcode)) {
2561 if (!ppc_is_uimm16 (ins->inst_imm)) {
2562 NEW_INS (cfg, temp, OP_ICONST);
2563 temp->inst_c0 = ins->inst_imm;
2564 temp->dreg = mono_alloc_ireg (cfg);
2565 ins->sreg2 = temp->dreg;
2566 ins->opcode = map_to_reg_reg_op (ins->opcode);
2569 if (!ppc_is_imm16 (ins->inst_imm)) {
2570 NEW_INS (cfg, temp, OP_ICONST);
2571 temp->inst_c0 = ins->inst_imm;
2572 temp->dreg = mono_alloc_ireg (cfg);
2573 ins->sreg2 = temp->dreg;
2574 ins->opcode = map_to_reg_reg_op (ins->opcode);
2580 if (ins->inst_imm == 1) {
2581 ins->opcode = OP_MOVE;
2584 if (ins->inst_imm == 0) {
2585 ins->opcode = OP_ICONST;
2589 imm = mono_is_power_of_two (ins->inst_imm);
2591 ins->opcode = OP_SHL_IMM;
2592 ins->inst_imm = imm;
2595 if (!ppc_is_imm16 (ins->inst_imm)) {
2596 NEW_INS (cfg, temp, OP_ICONST);
2597 temp->inst_c0 = ins->inst_imm;
2598 temp->dreg = mono_alloc_ireg (cfg);
2599 ins->sreg2 = temp->dreg;
2600 ins->opcode = map_to_reg_reg_op (ins->opcode);
2603 case OP_LOCALLOC_IMM:
2604 NEW_INS (cfg, temp, OP_ICONST);
2605 temp->inst_c0 = ins->inst_imm;
2606 temp->dreg = mono_alloc_ireg (cfg);
2607 ins->sreg1 = temp->dreg;
2608 ins->opcode = OP_LOCALLOC;
2610 case OP_LOAD_MEMBASE:
2611 case OP_LOADI4_MEMBASE:
2612 CASE_PPC64 (OP_LOADI8_MEMBASE)
2613 case OP_LOADU4_MEMBASE:
2614 case OP_LOADI2_MEMBASE:
2615 case OP_LOADU2_MEMBASE:
2616 case OP_LOADI1_MEMBASE:
2617 case OP_LOADU1_MEMBASE:
2618 case OP_LOADR4_MEMBASE:
2619 case OP_LOADR8_MEMBASE:
2620 case OP_STORE_MEMBASE_REG:
2621 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2622 case OP_STOREI4_MEMBASE_REG:
2623 case OP_STOREI2_MEMBASE_REG:
2624 case OP_STOREI1_MEMBASE_REG:
2625 case OP_STORER4_MEMBASE_REG:
2626 case OP_STORER8_MEMBASE_REG:
2627 /* we can do two things: load the immed in a register
2628 * and use an indexed load, or see if the immed can be
2629 * represented as an ad_imm + a load with a smaller offset
2630 * that fits. We just do the first for now, optimize later.
2632 if (ppc_is_imm16 (ins->inst_offset))
2634 NEW_INS (cfg, temp, OP_ICONST);
2635 temp->inst_c0 = ins->inst_offset;
2636 temp->dreg = mono_alloc_ireg (cfg);
2637 ins->sreg2 = temp->dreg;
2638 ins->opcode = map_to_reg_reg_op (ins->opcode);
2640 case OP_STORE_MEMBASE_IMM:
2641 case OP_STOREI1_MEMBASE_IMM:
2642 case OP_STOREI2_MEMBASE_IMM:
2643 case OP_STOREI4_MEMBASE_IMM:
2644 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2645 NEW_INS (cfg, temp, OP_ICONST);
2646 temp->inst_c0 = ins->inst_imm;
2647 temp->dreg = mono_alloc_ireg (cfg);
2648 ins->sreg1 = temp->dreg;
2649 ins->opcode = map_to_reg_reg_op (ins->opcode);
2651 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2654 if (cfg->compile_aot) {
2655 /* Keep these in the aot case */
2658 NEW_INS (cfg, temp, OP_ICONST);
2659 temp->inst_c0 = (gulong)ins->inst_p0;
2660 temp->dreg = mono_alloc_ireg (cfg);
2661 ins->inst_basereg = temp->dreg;
2662 ins->inst_offset = 0;
2663 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2665 /* make it handle the possibly big ins->inst_offset
2666 * later optimize to use lis + load_membase
2672 bb->last_ins = last_ins;
2673 bb->max_vreg = cfg->next_vreg;
2677 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2679 long offset = cfg->arch.fp_conv_var_offset;
2681 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2682 #ifdef __mono_ppc64__
2684 ppc_fctidz (code, ppc_f0, sreg);
2689 ppc_fctiwz (code, ppc_f0, sreg);
2692 if (ppc_is_imm16 (offset + sub_offset)) {
2693 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2695 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2697 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2699 ppc_load (code, dreg, offset);
2700 ppc_add (code, dreg, dreg, cfg->frame_reg);
2701 ppc_stfd (code, ppc_f0, 0, dreg);
2703 ppc_ldr (code, dreg, sub_offset, dreg);
2705 ppc_lwz (code, dreg, sub_offset, dreg);
2709 ppc_andid (code, dreg, dreg, 0xff);
2711 ppc_andid (code, dreg, dreg, 0xffff);
2712 #ifdef __mono_ppc64__
2714 ppc_clrldi (code, dreg, dreg, 32);
2718 ppc_extsb (code, dreg, dreg);
2720 ppc_extsh (code, dreg, dreg);
2721 #ifdef __mono_ppc64__
2723 ppc_extsw (code, dreg, dreg);
2731 const guchar *target;
2736 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2739 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2740 #ifdef __mono_ppc64__
2741 g_assert_not_reached ();
2743 PatchData *pdata = (PatchData*)user_data;
2744 guchar *code = data;
2745 guint32 *thunks = data;
2746 guint32 *endthunks = (guint32*)(code + bsize);
2750 int difflow, diffhigh;
2752 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2753 difflow = (char*)pdata->code - (char*)thunks;
2754 diffhigh = (char*)pdata->code - (char*)endthunks;
2755 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2758 templ = (guchar*)load;
2759 ppc_load_sequence (templ, ppc_r0, pdata->target);
2761 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2762 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2763 while (thunks < endthunks) {
2764 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2765 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2766 ppc_patch (pdata->code, (guchar*)thunks);
2769 static int num_thunks = 0;
2771 if ((num_thunks % 20) == 0)
2772 g_print ("num_thunks lookup: %d\n", num_thunks);
2775 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2776 /* found a free slot instead: emit thunk */
2777 code = (guchar*)thunks;
2778 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2779 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2780 ppc_mtctr (code, ppc_r0);
2781 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2782 mono_arch_flush_icache ((guchar*)thunks, 16);
2784 ppc_patch (pdata->code, (guchar*)thunks);
2787 static int num_thunks = 0;
2789 if ((num_thunks % 20) == 0)
2790 g_print ("num_thunks: %d\n", num_thunks);
2794 /* skip 16 bytes, the size of the thunk */
2798 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2805 handle_thunk (int absolute, guchar *code, const guchar *target) {
2806 MonoDomain *domain = mono_domain_get ();
2810 pdata.target = target;
2811 pdata.absolute = absolute;
2814 mono_domain_lock (domain);
2815 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2818 /* this uses the first available slot */
2820 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2822 mono_domain_unlock (domain);
2824 if (pdata.found != 1)
2825 g_print ("thunk failed for %p from %p\n", target, code);
2826 g_assert (pdata.found == 1);
2830 patch_ins (guint8 *code, guint32 ins)
2832 *(guint32*)code = ins;
2833 mono_arch_flush_icache (code, 4);
2837 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2839 guint32 ins = *(guint32*)code;
2840 guint32 prim = ins >> 26;
2843 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2845 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2846 gint diff = target - code;
2849 if (diff <= 33554431){
2850 ins = (18 << 26) | (diff) | (ins & 1);
2851 patch_ins (code, ins);
2855 /* diff between 0 and -33554432 */
2856 if (diff >= -33554432){
2857 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2858 patch_ins (code, ins);
2863 if ((glong)target >= 0){
2864 if ((glong)target <= 33554431){
2865 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2866 patch_ins (code, ins);
2870 if ((glong)target >= -33554432){
2871 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2872 patch_ins (code, ins);
2877 handle_thunk (TRUE, code, target);
2880 g_assert_not_reached ();
2888 guint32 li = (gulong)target;
2889 ins = (ins & 0xffff0000) | (ins & 3);
2890 ovf = li & 0xffff0000;
2891 if (ovf != 0 && ovf != 0xffff0000)
2892 g_assert_not_reached ();
2895 // FIXME: assert the top bits of li are 0
2897 gint diff = target - code;
2898 ins = (ins & 0xffff0000) | (ins & 3);
2899 ovf = diff & 0xffff0000;
2900 if (ovf != 0 && ovf != 0xffff0000)
2901 g_assert_not_reached ();
2905 patch_ins (code, ins);
2909 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2910 #ifdef __mono_ppc64__
2911 guint32 *seq = (guint32*)code;
2912 guint32 *branch_ins;
2914 /* the trampoline code will try to patch the blrl, blr, bcctr */
2915 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2917 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2922 if (ppc_is_load_op (seq [5])
2923 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2924 /* With function descs we need to do more careful
2926 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
2929 branch_ins = seq + 8;
2931 branch_ins = seq + 6;
2934 seq = (guint32*)code;
2935 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2936 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2938 if (ppc_is_load_op (seq [5])) {
2939 g_assert (ppc_is_load_op (seq [6]));
2942 guint8 *buf = (guint8*)&seq [5];
2943 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
2948 target = mono_get_addr_from_ftnptr ((gpointer)target);
2951 /* FIXME: make this thread safe */
2952 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2953 /* FIXME: we're assuming we're using r12 here */
2954 ppc_load_ptr_sequence (code, ppc_r12, target);
2956 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
2958 mono_arch_flush_icache ((guint8*)seq, 28);
2961 /* the trampoline code will try to patch the blrl, blr, bcctr */
2962 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2965 /* this is the lis/ori/mtlr/blrl sequence */
2966 seq = (guint32*)code;
2967 g_assert ((seq [0] >> 26) == 15);
2968 g_assert ((seq [1] >> 26) == 24);
2969 g_assert ((seq [2] >> 26) == 31);
2970 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2971 /* FIXME: make this thread safe */
2972 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
2973 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
2974 mono_arch_flush_icache (code - 8, 8);
2977 g_assert_not_reached ();
2979 // g_print ("patched with 0x%08x\n", ins);
2983 ppc_patch (guchar *code, const guchar *target)
2985 ppc_patch_full (code, target, FALSE);
2989 mono_ppc_patch (guchar *code, const guchar *target)
2991 ppc_patch (code, target);
2995 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2997 switch (ins->opcode) {
3000 case OP_FCALL_MEMBASE:
3001 if (ins->dreg != ppc_f1)
3002 ppc_fmr (code, ins->dreg, ppc_f1);
3010 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3012 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3016 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3018 long size = cfg->param_area;
3020 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3021 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3026 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3027 if (ppc_is_imm16 (-size)) {
3028 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3030 ppc_load (code, ppc_r12, -size);
3031 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3038 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3040 long size = cfg->param_area;
3042 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3043 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3048 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3049 if (ppc_is_imm16 (size)) {
3050 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3052 ppc_load (code, ppc_r12, size);
3053 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3059 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3063 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3065 MonoInst *ins, *next;
3068 guint8 *code = cfg->native_code + cfg->code_len;
3069 MonoInst *last_ins = NULL;
3070 guint last_offset = 0;
3074 /* we don't align basic blocks of loops on ppc */
3076 if (cfg->verbose_level > 2)
3077 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3079 cpos = bb->max_offset;
3081 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3082 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3083 //g_assert (!mono_compile_aot);
3086 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3087 /* this is not thread save, but good enough */
3088 /* fixme: howto handle overflows? */
3089 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3092 MONO_BB_FOR_EACH_INS (bb, ins) {
3093 offset = code - cfg->native_code;
3095 max_len = ins_native_length (cfg, ins);
3097 if (offset > (cfg->code_size - max_len - 16)) {
3098 cfg->code_size *= 2;
3099 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3100 code = cfg->native_code + offset;
3102 // if (ins->cil_code)
3103 // g_print ("cil code\n");
3104 mono_debug_record_line_number (cfg, ins, offset);
3106 switch (normalize_opcode (ins->opcode)) {
3107 case OP_RELAXED_NOP:
3110 case OP_DUMMY_STORE:
3111 case OP_NOT_REACHED:
3114 case OP_IL_SEQ_POINT:
3115 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3117 case OP_SEQ_POINT: {
3120 if (cfg->compile_aot)
3124 * Read from the single stepping trigger page. This will cause a
3125 * SIGSEGV when single stepping is enabled.
3126 * We do this _before_ the breakpoint, so single stepping after
3127 * a breakpoint is hit will step to the next IL offset.
3129 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3130 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3131 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3134 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3137 * A placeholder for a possible breakpoint inserted by
3138 * mono_arch_set_breakpoint ().
3140 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3145 emit_tls_access (code, ins->dreg, ins->inst_offset);
3148 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3149 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3150 ppc_mr (code, ppc_r4, ppc_r0);
3153 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3154 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3155 ppc_mr (code, ppc_r4, ppc_r0);
3157 case OP_MEMORY_BARRIER:
3160 case OP_STOREI1_MEMBASE_REG:
3161 if (ppc_is_imm16 (ins->inst_offset)) {
3162 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3164 if (ppc_is_imm32 (ins->inst_offset)) {
3165 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3166 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3168 ppc_load (code, ppc_r0, ins->inst_offset);
3169 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3173 case OP_STOREI2_MEMBASE_REG:
3174 if (ppc_is_imm16 (ins->inst_offset)) {
3175 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3177 if (ppc_is_imm32 (ins->inst_offset)) {
3178 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3179 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3181 ppc_load (code, ppc_r0, ins->inst_offset);
3182 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3186 case OP_STORE_MEMBASE_REG:
3187 if (ppc_is_imm16 (ins->inst_offset)) {
3188 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3190 if (ppc_is_imm32 (ins->inst_offset)) {
3191 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3192 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3194 ppc_load (code, ppc_r0, ins->inst_offset);
3195 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3199 #ifdef __mono_ilp32__
3200 case OP_STOREI8_MEMBASE_REG:
3201 if (ppc_is_imm16 (ins->inst_offset)) {
3202 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3204 ppc_load (code, ppc_r0, ins->inst_offset);
3205 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3209 case OP_STOREI1_MEMINDEX:
3210 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3212 case OP_STOREI2_MEMINDEX:
3213 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3215 case OP_STORE_MEMINDEX:
3216 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3219 g_assert_not_reached ();
3221 case OP_LOAD_MEMBASE:
3222 if (ppc_is_imm16 (ins->inst_offset)) {
3223 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3225 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3226 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3227 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3229 ppc_load (code, ppc_r0, ins->inst_offset);
3230 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3234 case OP_LOADI4_MEMBASE:
3235 #ifdef __mono_ppc64__
3236 if (ppc_is_imm16 (ins->inst_offset)) {
3237 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3239 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3240 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3241 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3243 ppc_load (code, ppc_r0, ins->inst_offset);
3244 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3249 case OP_LOADU4_MEMBASE:
3250 if (ppc_is_imm16 (ins->inst_offset)) {
3251 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3253 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3254 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3255 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3257 ppc_load (code, ppc_r0, ins->inst_offset);
3258 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3262 case OP_LOADI1_MEMBASE:
3263 case OP_LOADU1_MEMBASE:
3264 if (ppc_is_imm16 (ins->inst_offset)) {
3265 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3267 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3268 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3269 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3271 ppc_load (code, ppc_r0, ins->inst_offset);
3272 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3275 if (ins->opcode == OP_LOADI1_MEMBASE)
3276 ppc_extsb (code, ins->dreg, ins->dreg);
3278 case OP_LOADU2_MEMBASE:
3279 if (ppc_is_imm16 (ins->inst_offset)) {
3280 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3282 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3283 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3284 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3286 ppc_load (code, ppc_r0, ins->inst_offset);
3287 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3291 case OP_LOADI2_MEMBASE:
3292 if (ppc_is_imm16 (ins->inst_offset)) {
3293 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3295 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3296 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3297 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3299 ppc_load (code, ppc_r0, ins->inst_offset);
3300 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3304 #ifdef __mono_ilp32__
3305 case OP_LOADI8_MEMBASE:
3306 if (ppc_is_imm16 (ins->inst_offset)) {
3307 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3309 ppc_load (code, ppc_r0, ins->inst_offset);
3310 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3314 case OP_LOAD_MEMINDEX:
3315 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3317 case OP_LOADI4_MEMINDEX:
3318 #ifdef __mono_ppc64__
3319 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3322 case OP_LOADU4_MEMINDEX:
3323 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3325 case OP_LOADU2_MEMINDEX:
3326 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3328 case OP_LOADI2_MEMINDEX:
3329 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3331 case OP_LOADU1_MEMINDEX:
3332 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3334 case OP_LOADI1_MEMINDEX:
3335 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3336 ppc_extsb (code, ins->dreg, ins->dreg);
3338 case OP_ICONV_TO_I1:
3339 CASE_PPC64 (OP_LCONV_TO_I1)
3340 ppc_extsb (code, ins->dreg, ins->sreg1);
3342 case OP_ICONV_TO_I2:
3343 CASE_PPC64 (OP_LCONV_TO_I2)
3344 ppc_extsh (code, ins->dreg, ins->sreg1);
3346 case OP_ICONV_TO_U1:
3347 CASE_PPC64 (OP_LCONV_TO_U1)
3348 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3350 case OP_ICONV_TO_U2:
3351 CASE_PPC64 (OP_LCONV_TO_U2)
3352 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3356 CASE_PPC64 (OP_LCOMPARE)
3357 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3359 if (next && compare_opcode_is_unsigned (next->opcode))
3360 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3362 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3364 case OP_COMPARE_IMM:
3365 case OP_ICOMPARE_IMM:
3366 CASE_PPC64 (OP_LCOMPARE_IMM)
3367 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3369 if (next && compare_opcode_is_unsigned (next->opcode)) {
3370 if (ppc_is_uimm16 (ins->inst_imm)) {
3371 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3373 g_assert_not_reached ();
3376 if (ppc_is_imm16 (ins->inst_imm)) {
3377 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3379 g_assert_not_reached ();
3385 * gdb does not like encountering a trap in the debugged code. So
3386 * instead of emitting a trap, we emit a call a C function and place a
3390 ppc_mr (code, ppc_r3, ins->sreg1);
3391 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3392 (gpointer)"mono_break");
3393 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3394 ppc_load_func (code, PPC_CALL_REG, 0);
3395 ppc_mtlr (code, PPC_CALL_REG);
3403 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3406 CASE_PPC64 (OP_LADD)
3407 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3411 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3414 if (ppc_is_imm16 (ins->inst_imm)) {
3415 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3417 g_assert_not_reached ();
3422 CASE_PPC64 (OP_LADD_IMM)
3423 if (ppc_is_imm16 (ins->inst_imm)) {
3424 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3426 g_assert_not_reached ();
3430 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3432 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3433 ppc_mfspr (code, ppc_r0, ppc_xer);
3434 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3435 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3437 case OP_IADD_OVF_UN:
3438 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3440 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3441 ppc_mfspr (code, ppc_r0, ppc_xer);
3442 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3443 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3446 CASE_PPC64 (OP_LSUB_OVF)
3447 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3449 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3450 ppc_mfspr (code, ppc_r0, ppc_xer);
3451 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3452 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3454 case OP_ISUB_OVF_UN:
3455 CASE_PPC64 (OP_LSUB_OVF_UN)
3456 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3458 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3459 ppc_mfspr (code, ppc_r0, ppc_xer);
3460 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3461 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3463 case OP_ADD_OVF_CARRY:
3464 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3466 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3467 ppc_mfspr (code, ppc_r0, ppc_xer);
3468 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3469 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3471 case OP_ADD_OVF_UN_CARRY:
3472 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3474 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3475 ppc_mfspr (code, ppc_r0, ppc_xer);
3476 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3477 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3479 case OP_SUB_OVF_CARRY:
3480 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3482 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3483 ppc_mfspr (code, ppc_r0, ppc_xer);
3484 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3485 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3487 case OP_SUB_OVF_UN_CARRY:
3488 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3490 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3491 ppc_mfspr (code, ppc_r0, ppc_xer);
3492 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3493 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3497 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3500 CASE_PPC64 (OP_LSUB)
3501 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3505 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3509 CASE_PPC64 (OP_LSUB_IMM)
3510 // we add the negated value
3511 if (ppc_is_imm16 (-ins->inst_imm))
3512 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3514 g_assert_not_reached ();
3518 g_assert (ppc_is_imm16 (ins->inst_imm));
3519 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3522 ppc_subfze (code, ins->dreg, ins->sreg1);
3525 CASE_PPC64 (OP_LAND)
3526 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3527 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3531 CASE_PPC64 (OP_LAND_IMM)
3532 if (!(ins->inst_imm & 0xffff0000)) {
3533 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3534 } else if (!(ins->inst_imm & 0xffff)) {
3535 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3537 g_assert_not_reached ();
3541 CASE_PPC64 (OP_LDIV) {
3542 guint8 *divisor_is_m1;
3543 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3545 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3546 divisor_is_m1 = code;
3547 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3548 ppc_lis (code, ppc_r0, 0x8000);
3549 #ifdef __mono_ppc64__
3550 if (ins->opcode == OP_LDIV)
3551 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3553 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3554 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3555 ppc_patch (divisor_is_m1, code);
3556 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3558 if (ins->opcode == OP_IDIV)
3559 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3560 #ifdef __mono_ppc64__
3562 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3564 ppc_mfspr (code, ppc_r0, ppc_xer);
3565 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3566 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3570 CASE_PPC64 (OP_LDIV_UN)
3571 if (ins->opcode == OP_IDIV_UN)
3572 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3573 #ifdef __mono_ppc64__
3575 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3577 ppc_mfspr (code, ppc_r0, ppc_xer);
3578 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3579 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3585 g_assert_not_reached ();
3588 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3592 CASE_PPC64 (OP_LOR_IMM)
3593 if (!(ins->inst_imm & 0xffff0000)) {
3594 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3595 } else if (!(ins->inst_imm & 0xffff)) {
3596 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3598 g_assert_not_reached ();
3602 CASE_PPC64 (OP_LXOR)
3603 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3607 CASE_PPC64 (OP_LXOR_IMM)
3608 if (!(ins->inst_imm & 0xffff0000)) {
3609 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3610 } else if (!(ins->inst_imm & 0xffff)) {
3611 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3613 g_assert_not_reached ();
3617 CASE_PPC64 (OP_LSHL)
3618 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3622 CASE_PPC64 (OP_LSHL_IMM)
3623 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3626 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3629 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3632 if (MASK_SHIFT_IMM (ins->inst_imm))
3633 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3635 ppc_mr (code, ins->dreg, ins->sreg1);
3638 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3641 CASE_PPC64 (OP_LNOT)
3642 ppc_not (code, ins->dreg, ins->sreg1);
3645 CASE_PPC64 (OP_LNEG)
3646 ppc_neg (code, ins->dreg, ins->sreg1);
3649 CASE_PPC64 (OP_LMUL)
3650 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3654 CASE_PPC64 (OP_LMUL_IMM)
3655 if (ppc_is_imm16 (ins->inst_imm)) {
3656 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3658 g_assert_not_reached ();
3662 CASE_PPC64 (OP_LMUL_OVF)
3663 /* we annot use mcrxr, since it's not implemented on some processors
3664 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3666 if (ins->opcode == OP_IMUL_OVF)
3667 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3668 #ifdef __mono_ppc64__
3670 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3672 ppc_mfspr (code, ppc_r0, ppc_xer);
3673 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3674 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3676 case OP_IMUL_OVF_UN:
3677 CASE_PPC64 (OP_LMUL_OVF_UN)
3678 /* we first multiply to get the high word and compare to 0
3679 * to set the flags, then the result is discarded and then
3680 * we multiply to get the lower * bits result
3682 if (ins->opcode == OP_IMUL_OVF_UN)
3683 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3684 #ifdef __mono_ppc64__
3686 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3688 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3689 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3690 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3693 ppc_load (code, ins->dreg, ins->inst_c0);
3696 ppc_load (code, ins->dreg, ins->inst_l);
3699 case OP_LOAD_GOTADDR:
3700 /* The PLT implementation depends on this */
3701 g_assert (ins->dreg == ppc_r30);
3703 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3706 // FIXME: Fix max instruction length
3707 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3708 /* arch_emit_got_access () patches this */
3709 ppc_load32 (code, ppc_r0, 0);
3710 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3713 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3714 ppc_load_sequence (code, ins->dreg, 0);
3716 CASE_PPC32 (OP_ICONV_TO_I4)
3717 CASE_PPC32 (OP_ICONV_TO_U4)
3719 if (ins->dreg != ins->sreg1)
3720 ppc_mr (code, ins->dreg, ins->sreg1);
3723 int saved = ins->sreg1;
3724 if (ins->sreg1 == ppc_r3) {
3725 ppc_mr (code, ppc_r0, ins->sreg1);
3728 if (ins->sreg2 != ppc_r3)
3729 ppc_mr (code, ppc_r3, ins->sreg2);
3730 if (saved != ppc_r4)
3731 ppc_mr (code, ppc_r4, saved);
3735 if (ins->dreg != ins->sreg1)
3736 ppc_fmr (code, ins->dreg, ins->sreg1);
3738 case OP_FCONV_TO_R4:
3739 ppc_frsp (code, ins->dreg, ins->sreg1);
3743 MonoCallInst *call = (MonoCallInst*)ins;
3746 * Keep in sync with mono_arch_emit_epilog
3748 g_assert (!cfg->method->save_lmf);
3750 * Note: we can use ppc_r12 here because it is dead anyway:
3751 * we're leaving the method.
3753 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3754 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3755 if (ppc_is_imm16 (ret_offset)) {
3756 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3758 ppc_load (code, ppc_r12, ret_offset);
3759 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3761 ppc_mtlr (code, ppc_r0);
3764 if (ppc_is_imm16 (cfg->stack_usage)) {
3765 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3767 /* cfg->stack_usage is an int, so we can use
3768 * an addis/addi sequence here even in 64-bit. */
3769 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3770 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3772 if (!cfg->method->save_lmf) {
3774 for (i = 31; i >= 13; --i) {
3775 if (cfg->used_int_regs & (1 << i)) {
3776 pos += sizeof (gpointer);
3777 ppc_ldptr (code, i, -pos, ppc_r12);
3781 /* FIXME restore from MonoLMF: though this can't happen yet */
3784 /* Copy arguments on the stack to our argument area */
3785 if (call->stack_usage) {
3786 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3787 /* r12 was clobbered */
3788 g_assert (cfg->frame_reg == ppc_sp);
3789 if (ppc_is_imm16 (cfg->stack_usage)) {
3790 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3792 /* cfg->stack_usage is an int, so we can use
3793 * an addis/addi sequence here even in 64-bit. */
3794 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3795 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3799 ppc_mr (code, ppc_sp, ppc_r12);
3800 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3801 if (cfg->compile_aot) {
3802 /* arch_emit_got_access () patches this */
3803 ppc_load32 (code, ppc_r0, 0);
3804 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3805 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3806 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3808 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3810 ppc_mtctr (code, ppc_r0);
3811 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3818 /* ensure ins->sreg1 is not NULL */
3819 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3822 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3823 if (ppc_is_imm16 (cookie_offset)) {
3824 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3826 ppc_load (code, ppc_r0, cookie_offset);
3827 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3829 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3838 call = (MonoCallInst*)ins;
3839 if (ins->flags & MONO_INST_HAS_METHOD)
3840 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3842 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3843 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3844 ppc_load_func (code, PPC_CALL_REG, 0);
3845 ppc_mtlr (code, PPC_CALL_REG);
3850 /* FIXME: this should be handled somewhere else in the new jit */
3851 code = emit_move_return_value (cfg, ins, code);
3857 case OP_VOIDCALL_REG:
3859 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3860 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3861 /* FIXME: if we know that this is a method, we
3862 can omit this load */
3863 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3864 ppc_mtlr (code, ppc_r0);
3866 ppc_mtlr (code, ins->sreg1);
3869 /* FIXME: this should be handled somewhere else in the new jit */
3870 code = emit_move_return_value (cfg, ins, code);
3872 case OP_FCALL_MEMBASE:
3873 case OP_LCALL_MEMBASE:
3874 case OP_VCALL_MEMBASE:
3875 case OP_VCALL2_MEMBASE:
3876 case OP_VOIDCALL_MEMBASE:
3877 case OP_CALL_MEMBASE:
3878 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3879 /* The trampolines clobber this */
3880 ppc_mr (code, ppc_r29, ins->sreg1);
3881 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3883 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3885 ppc_mtlr (code, ppc_r0);
3887 /* FIXME: this should be handled somewhere else in the new jit */
3888 code = emit_move_return_value (cfg, ins, code);
3891 guint8 * zero_loop_jump, * zero_loop_start;
3892 /* keep alignment */
3893 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3894 int area_offset = alloca_waste;
3896 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3897 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3898 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3899 /* use ctr to store the number of words to 0 if needed */
3900 if (ins->flags & MONO_INST_INIT) {
3901 /* we zero 4 bytes at a time:
3902 * we add 7 instead of 3 so that we set the counter to
3903 * at least 1, otherwise the bdnz instruction will make
3904 * it negative and iterate billions of times.
3906 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3907 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3908 ppc_mtctr (code, ppc_r0);
3910 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3911 ppc_neg (code, ppc_r12, ppc_r12);
3912 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3914 /* FIXME: make this loop work in 8 byte
3915 increments on PPC64 */
3916 if (ins->flags & MONO_INST_INIT) {
3917 /* adjust the dest reg by -4 so we can use stwu */
3918 /* we actually adjust -8 because we let the loop
3921 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3922 ppc_li (code, ppc_r12, 0);
3923 zero_loop_start = code;
3924 ppc_stwu (code, ppc_r12, 4, ins->dreg);
3925 zero_loop_jump = code;
3926 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3927 ppc_patch (zero_loop_jump, zero_loop_start);
3929 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3934 ppc_mr (code, ppc_r3, ins->sreg1);
3935 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3936 (gpointer)"mono_arch_throw_exception");
3937 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3938 ppc_load_func (code, PPC_CALL_REG, 0);
3939 ppc_mtlr (code, PPC_CALL_REG);
3948 ppc_mr (code, ppc_r3, ins->sreg1);
3949 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3950 (gpointer)"mono_arch_rethrow_exception");
3951 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3952 ppc_load_func (code, PPC_CALL_REG, 0);
3953 ppc_mtlr (code, PPC_CALL_REG);
3960 case OP_START_HANDLER: {
3961 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3962 g_assert (spvar->inst_basereg != ppc_sp);
3963 code = emit_reserve_param_area (cfg, code);
3964 ppc_mflr (code, ppc_r0);
3965 if (ppc_is_imm16 (spvar->inst_offset)) {
3966 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3968 ppc_load (code, ppc_r12, spvar->inst_offset);
3969 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
3973 case OP_ENDFILTER: {
3974 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3975 g_assert (spvar->inst_basereg != ppc_sp);
3976 code = emit_unreserve_param_area (cfg, code);
3977 if (ins->sreg1 != ppc_r3)
3978 ppc_mr (code, ppc_r3, ins->sreg1);
3979 if (ppc_is_imm16 (spvar->inst_offset)) {
3980 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3982 ppc_load (code, ppc_r12, spvar->inst_offset);
3983 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
3985 ppc_mtlr (code, ppc_r0);
3989 case OP_ENDFINALLY: {
3990 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3991 g_assert (spvar->inst_basereg != ppc_sp);
3992 code = emit_unreserve_param_area (cfg, code);
3993 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3994 ppc_mtlr (code, ppc_r0);
3998 case OP_CALL_HANDLER:
3999 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4001 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4004 ins->inst_c0 = code - cfg->native_code;
4007 /*if (ins->inst_target_bb->native_offset) {
4009 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4011 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4016 ppc_mtctr (code, ins->sreg1);
4017 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4021 CASE_PPC64 (OP_LCEQ)
4022 ppc_li (code, ins->dreg, 0);
4023 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4024 ppc_li (code, ins->dreg, 1);
4030 CASE_PPC64 (OP_LCLT)
4031 CASE_PPC64 (OP_LCLT_UN)
4032 ppc_li (code, ins->dreg, 1);
4033 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4034 ppc_li (code, ins->dreg, 0);
4040 CASE_PPC64 (OP_LCGT)
4041 CASE_PPC64 (OP_LCGT_UN)
4042 ppc_li (code, ins->dreg, 1);
4043 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4044 ppc_li (code, ins->dreg, 0);
4046 case OP_COND_EXC_EQ:
4047 case OP_COND_EXC_NE_UN:
4048 case OP_COND_EXC_LT:
4049 case OP_COND_EXC_LT_UN:
4050 case OP_COND_EXC_GT:
4051 case OP_COND_EXC_GT_UN:
4052 case OP_COND_EXC_GE:
4053 case OP_COND_EXC_GE_UN:
4054 case OP_COND_EXC_LE:
4055 case OP_COND_EXC_LE_UN:
4056 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4058 case OP_COND_EXC_IEQ:
4059 case OP_COND_EXC_INE_UN:
4060 case OP_COND_EXC_ILT:
4061 case OP_COND_EXC_ILT_UN:
4062 case OP_COND_EXC_IGT:
4063 case OP_COND_EXC_IGT_UN:
4064 case OP_COND_EXC_IGE:
4065 case OP_COND_EXC_IGE_UN:
4066 case OP_COND_EXC_ILE:
4067 case OP_COND_EXC_ILE_UN:
4068 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4080 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4083 /* floating point opcodes */
4085 g_assert (cfg->compile_aot);
4087 /* FIXME: Optimize this */
4089 ppc_mflr (code, ppc_r12);
4091 *(double*)code = *(double*)ins->inst_p0;
4093 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4096 g_assert_not_reached ();
4098 case OP_STORER8_MEMBASE_REG:
4099 if (ppc_is_imm16 (ins->inst_offset)) {
4100 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4102 if (ppc_is_imm32 (ins->inst_offset)) {
4103 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4104 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4106 ppc_load (code, ppc_r0, ins->inst_offset);
4107 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4111 case OP_LOADR8_MEMBASE:
4112 if (ppc_is_imm16 (ins->inst_offset)) {
4113 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4115 if (ppc_is_imm32 (ins->inst_offset)) {
4116 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4117 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4119 ppc_load (code, ppc_r0, ins->inst_offset);
4120 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4124 case OP_STORER4_MEMBASE_REG:
4125 ppc_frsp (code, ins->sreg1, ins->sreg1);
4126 if (ppc_is_imm16 (ins->inst_offset)) {
4127 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4129 if (ppc_is_imm32 (ins->inst_offset)) {
4130 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4131 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4133 ppc_load (code, ppc_r0, ins->inst_offset);
4134 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4138 case OP_LOADR4_MEMBASE:
4139 if (ppc_is_imm16 (ins->inst_offset)) {
4140 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4142 if (ppc_is_imm32 (ins->inst_offset)) {
4143 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4144 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4146 ppc_load (code, ppc_r0, ins->inst_offset);
4147 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4151 case OP_LOADR4_MEMINDEX:
4152 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4154 case OP_LOADR8_MEMINDEX:
4155 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4157 case OP_STORER4_MEMINDEX:
4158 ppc_frsp (code, ins->sreg1, ins->sreg1);
4159 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4161 case OP_STORER8_MEMINDEX:
4162 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4165 case CEE_CONV_R4: /* FIXME: change precision */
4167 g_assert_not_reached ();
4168 case OP_FCONV_TO_I1:
4169 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4171 case OP_FCONV_TO_U1:
4172 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4174 case OP_FCONV_TO_I2:
4175 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4177 case OP_FCONV_TO_U2:
4178 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4180 case OP_FCONV_TO_I4:
4182 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4184 case OP_FCONV_TO_U4:
4186 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4188 case OP_LCONV_TO_R_UN:
4189 g_assert_not_reached ();
4190 /* Implemented as helper calls */
4192 case OP_LCONV_TO_OVF_I4_2:
4193 case OP_LCONV_TO_OVF_I: {
4194 #ifdef __mono_ppc64__
4197 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4198 // Check if its negative
4199 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4200 negative_branch = code;
4201 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4202 // Its positive msword == 0
4203 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4204 msword_positive_branch = code;
4205 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4207 ovf_ex_target = code;
4208 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4210 ppc_patch (negative_branch, code);
4211 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4212 msword_negative_branch = code;
4213 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4214 ppc_patch (msword_negative_branch, ovf_ex_target);
4216 ppc_patch (msword_positive_branch, code);
4217 if (ins->dreg != ins->sreg1)
4218 ppc_mr (code, ins->dreg, ins->sreg1);
4223 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4226 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4229 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4232 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4235 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4238 ppc_fneg (code, ins->dreg, ins->sreg1);
4242 g_assert_not_reached ();
4245 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4248 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4249 ppc_li (code, ins->dreg, 0);
4250 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4251 ppc_li (code, ins->dreg, 1);
4254 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4255 ppc_li (code, ins->dreg, 1);
4256 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4257 ppc_li (code, ins->dreg, 0);
4260 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4261 ppc_li (code, ins->dreg, 1);
4262 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4263 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4264 ppc_li (code, ins->dreg, 0);
4267 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4268 ppc_li (code, ins->dreg, 1);
4269 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4270 ppc_li (code, ins->dreg, 0);
4273 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4274 ppc_li (code, ins->dreg, 1);
4275 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4276 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4277 ppc_li (code, ins->dreg, 0);
4280 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4283 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4286 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4287 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4290 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4291 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4294 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4295 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4298 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4299 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4302 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4303 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4306 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4309 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4310 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4313 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4316 g_assert_not_reached ();
4317 case OP_CHECK_FINITE: {
4318 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4319 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4320 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4321 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4324 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4325 #ifdef __mono_ppc64__
4326 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4328 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4333 #ifdef __mono_ppc64__
4334 case OP_ICONV_TO_I4:
4336 ppc_extsw (code, ins->dreg, ins->sreg1);
4338 case OP_ICONV_TO_U4:
4340 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4342 case OP_ICONV_TO_R4:
4343 case OP_ICONV_TO_R8:
4344 case OP_LCONV_TO_R4:
4345 case OP_LCONV_TO_R8: {
4347 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4348 ppc_extsw (code, ppc_r0, ins->sreg1);
4353 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4354 ppc_mffgpr (code, ins->dreg, tmp);
4356 ppc_str (code, tmp, -8, ppc_r1);
4357 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4359 ppc_fcfid (code, ins->dreg, ins->dreg);
4360 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4361 ppc_frsp (code, ins->dreg, ins->dreg);
4365 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4368 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4371 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4373 ppc_mfspr (code, ppc_r0, ppc_xer);
4374 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4375 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4377 case OP_COND_EXC_OV:
4378 ppc_mfspr (code, ppc_r0, ppc_xer);
4379 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4380 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4392 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4394 case OP_FCONV_TO_I8:
4395 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4397 case OP_FCONV_TO_U8:
4398 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4400 case OP_STOREI4_MEMBASE_REG:
4401 if (ppc_is_imm16 (ins->inst_offset)) {
4402 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4404 ppc_load (code, ppc_r0, ins->inst_offset);
4405 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4408 case OP_STOREI4_MEMINDEX:
4409 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4412 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4414 case OP_ISHR_UN_IMM:
4415 if (ins->inst_imm & 0x1f)
4416 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4418 ppc_mr (code, ins->dreg, ins->sreg1);
4420 case OP_ATOMIC_ADD_I4:
4421 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4422 int location = ins->inst_basereg;
4423 int addend = ins->sreg2;
4424 guint8 *loop, *branch;
4425 g_assert (ins->inst_offset == 0);
4429 if (ins->opcode == OP_ATOMIC_ADD_I4)
4430 ppc_lwarx (code, ppc_r0, 0, location);
4431 #ifdef __mono_ppc64__
4433 ppc_ldarx (code, ppc_r0, 0, location);
4436 ppc_add (code, ppc_r0, ppc_r0, addend);
4438 if (ins->opcode == OP_ATOMIC_ADD_I4)
4439 ppc_stwcxd (code, ppc_r0, 0, location);
4440 #ifdef __mono_ppc64__
4442 ppc_stdcxd (code, ppc_r0, 0, location);
4446 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4447 ppc_patch (branch, loop);
4450 ppc_mr (code, ins->dreg, ppc_r0);
4454 case OP_ICONV_TO_R4:
4455 case OP_ICONV_TO_R8: {
4456 if (cpu_hw_caps & PPC_ISA_64) {
4457 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4458 ppc_stw (code, ppc_r0, -8, ppc_r1);
4459 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4460 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4461 ppc_fcfid (code, ins->dreg, ins->dreg);
4462 if (ins->opcode == OP_ICONV_TO_R4)
4463 ppc_frsp (code, ins->dreg, ins->dreg);
4468 case OP_ATOMIC_CAS_I4:
4469 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4470 int location = ins->sreg1;
4471 int value = ins->sreg2;
4472 int comparand = ins->sreg3;
4473 guint8 *start, *not_equal, *lost_reservation;
4477 if (ins->opcode == OP_ATOMIC_CAS_I4)
4478 ppc_lwarx (code, ppc_r0, 0, location);
4479 #ifdef __mono_ppc64__
4481 ppc_ldarx (code, ppc_r0, 0, location);
4484 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4486 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4488 if (ins->opcode == OP_ATOMIC_CAS_I4)
4489 ppc_stwcxd (code, value, 0, location);
4490 #ifdef __mono_ppc64__
4492 ppc_stdcxd (code, value, 0, location);
4495 lost_reservation = code;
4496 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4497 ppc_patch (lost_reservation, start);
4498 ppc_patch (not_equal, code);
4501 ppc_mr (code, ins->dreg, ppc_r0);
4506 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4507 g_assert_not_reached ();
4510 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4511 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4512 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4513 g_assert_not_reached ();
4519 last_offset = offset;
4522 cfg->code_len = code - cfg->native_code;
4524 #endif /* !DISABLE_JIT */
4527 mono_arch_register_lowlevel_calls (void)
4529 /* The signature doesn't matter */
4530 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4533 #ifdef __mono_ppc64__
4534 #ifdef _LITTLE_ENDIAN
4535 #define patch_load_sequence(ip,val) do {\
4536 guint16 *__load = (guint16*)(ip); \
4537 g_assert (sizeof (val) == sizeof (gsize)); \
4538 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4539 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4540 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4541 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4543 #elif defined _BIG_ENDIAN
4544 #define patch_load_sequence(ip,val) do {\
4545 guint16 *__load = (guint16*)(ip); \
4546 g_assert (sizeof (val) == sizeof (gsize)); \
4547 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4548 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4549 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4550 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4553 #error huh? No endianess defined by compiler
4556 #define patch_load_sequence(ip,val) do {\
4557 guint16 *__lis_ori = (guint16*)(ip); \
4558 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4559 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4565 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4567 MonoJumpInfo *patch_info;
4568 gboolean compile_aot = !run_cctors;
4570 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4571 unsigned char *ip = patch_info->ip.i + code;
4572 unsigned char *target;
4573 gboolean is_fd = FALSE;
4575 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4578 switch (patch_info->type) {
4579 case MONO_PATCH_INFO_BB:
4580 case MONO_PATCH_INFO_LABEL:
4583 /* No need to patch these */
4588 switch (patch_info->type) {
4589 case MONO_PATCH_INFO_IP:
4590 patch_load_sequence (ip, ip);
4592 case MONO_PATCH_INFO_METHOD_REL:
4593 g_assert_not_reached ();
4594 *((gpointer *)(ip)) = code + patch_info->data.offset;
4596 case MONO_PATCH_INFO_SWITCH: {
4597 gpointer *table = (gpointer *)patch_info->data.table->table;
4600 patch_load_sequence (ip, table);
4602 for (i = 0; i < patch_info->data.table->table_size; i++) {
4603 table [i] = (glong)patch_info->data.table->table [i] + code;
4605 /* we put into the table the absolute address, no need for ppc_patch in this case */
4608 case MONO_PATCH_INFO_METHODCONST:
4609 case MONO_PATCH_INFO_CLASS:
4610 case MONO_PATCH_INFO_IMAGE:
4611 case MONO_PATCH_INFO_FIELD:
4612 case MONO_PATCH_INFO_VTABLE:
4613 case MONO_PATCH_INFO_IID:
4614 case MONO_PATCH_INFO_SFLDA:
4615 case MONO_PATCH_INFO_LDSTR:
4616 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4617 case MONO_PATCH_INFO_LDTOKEN:
4618 /* from OP_AOTCONST : lis + ori */
4619 patch_load_sequence (ip, target);
4621 case MONO_PATCH_INFO_R4:
4622 case MONO_PATCH_INFO_R8:
4623 g_assert_not_reached ();
4624 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4626 case MONO_PATCH_INFO_EXC_NAME:
4627 g_assert_not_reached ();
4628 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4630 case MONO_PATCH_INFO_NONE:
4631 case MONO_PATCH_INFO_BB_OVF:
4632 case MONO_PATCH_INFO_EXC_OVF:
4633 /* everything is dealt with at epilog output time */
4635 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4636 case MONO_PATCH_INFO_INTERNAL_METHOD:
4637 case MONO_PATCH_INFO_ABS:
4638 case MONO_PATCH_INFO_CLASS_INIT:
4639 case MONO_PATCH_INFO_RGCTX_FETCH:
4640 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4647 ppc_patch_full (ip, target, is_fd);
4652 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4653 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4654 * the instruction offset immediate for all the registers.
4657 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4661 for (i = 13; i <= 31; i++) {
4662 if (used_int_regs & (1 << i)) {
4663 ppc_str (code, i, pos, base_reg);
4664 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4665 pos += sizeof (mgreg_t);
4669 /* pos is the start of the MonoLMF structure */
4670 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4671 for (i = 13; i <= 31; i++) {
4672 ppc_str (code, i, offset, base_reg);
4673 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4674 offset += sizeof (mgreg_t);
4676 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4677 for (i = 14; i < 32; i++) {
4678 ppc_stfd (code, i, offset, base_reg);
4679 offset += sizeof (gdouble);
4686 * Stack frame layout:
4688 * ------------------- sp
4689 * MonoLMF structure or saved registers
4690 * -------------------
4692 * -------------------
4694 * -------------------
4695 * optional 8 bytes for tracing
4696 * -------------------
4697 * param area size is cfg->param_area
4698 * -------------------
4699 * linkage area size is PPC_STACK_PARAM_OFFSET
4700 * ------------------- sp
4704 mono_arch_emit_prolog (MonoCompile *cfg)
4706 MonoMethod *method = cfg->method;
4708 MonoMethodSignature *sig;
4710 long alloc_size, pos, max_offset, cfa_offset;
4716 int tailcall_struct_index;
4718 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4721 sig = mono_method_signature (method);
4722 cfg->code_size = 512 + sig->param_count * 32;
4723 code = cfg->native_code = g_malloc (cfg->code_size);
4727 /* We currently emit unwind info for aot, but don't use it */
4728 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4730 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4731 ppc_mflr (code, ppc_r0);
4732 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4733 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4736 alloc_size = cfg->stack_offset;
4739 if (!method->save_lmf) {
4740 for (i = 31; i >= 13; --i) {
4741 if (cfg->used_int_regs & (1 << i)) {
4742 pos += sizeof (mgreg_t);
4746 pos += sizeof (MonoLMF);
4750 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4751 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4752 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4753 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4756 cfg->stack_usage = alloc_size;
4757 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4759 if (ppc_is_imm16 (-alloc_size)) {
4760 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4761 cfa_offset = alloc_size;
4762 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4763 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4766 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4767 ppc_load (code, ppc_r0, -alloc_size);
4768 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4769 cfa_offset = alloc_size;
4770 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4771 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4774 if (cfg->frame_reg != ppc_sp) {
4775 ppc_mr (code, cfg->frame_reg, ppc_sp);
4776 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4779 /* store runtime generic context */
4780 if (cfg->rgctx_var) {
4781 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4782 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4784 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4787 /* compute max_offset in order to use short forward jumps
4788 * we always do it on ppc because the immediate displacement
4789 * for jumps is too small
4792 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4794 bb->max_offset = max_offset;
4796 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4799 MONO_BB_FOR_EACH_INS (bb, ins)
4800 max_offset += ins_native_length (cfg, ins);
4803 /* load arguments allocated to register from the stack */
4806 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4808 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4809 ArgInfo *ainfo = &cinfo->ret;
4811 inst = cfg->vret_addr;
4814 if (ppc_is_imm16 (inst->inst_offset)) {
4815 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4817 ppc_load (code, ppc_r12, inst->inst_offset);
4818 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4822 tailcall_struct_index = 0;
4823 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4824 ArgInfo *ainfo = cinfo->args + i;
4825 inst = cfg->args [pos];
4827 if (cfg->verbose_level > 2)
4828 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4829 if (inst->opcode == OP_REGVAR) {
4830 if (ainfo->regtype == RegTypeGeneral)
4831 ppc_mr (code, inst->dreg, ainfo->reg);
4832 else if (ainfo->regtype == RegTypeFP)
4833 ppc_fmr (code, inst->dreg, ainfo->reg);
4834 else if (ainfo->regtype == RegTypeBase) {
4835 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4836 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4838 g_assert_not_reached ();
4840 if (cfg->verbose_level > 2)
4841 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4843 /* the argument should be put on the stack: FIXME handle size != word */
4844 if (ainfo->regtype == RegTypeGeneral) {
4845 switch (ainfo->size) {
4847 if (ppc_is_imm16 (inst->inst_offset)) {
4848 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4850 if (ppc_is_imm32 (inst->inst_offset)) {
4851 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4852 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4854 ppc_load (code, ppc_r12, inst->inst_offset);
4855 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4860 if (ppc_is_imm16 (inst->inst_offset)) {
4861 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4863 if (ppc_is_imm32 (inst->inst_offset)) {
4864 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4865 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4867 ppc_load (code, ppc_r12, inst->inst_offset);
4868 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4872 #ifdef __mono_ppc64__
4874 if (ppc_is_imm16 (inst->inst_offset)) {
4875 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4877 if (ppc_is_imm32 (inst->inst_offset)) {
4878 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4879 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4881 ppc_load (code, ppc_r12, inst->inst_offset);
4882 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4887 if (ppc_is_imm16 (inst->inst_offset)) {
4888 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4890 ppc_load (code, ppc_r12, inst->inst_offset);
4891 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4896 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4897 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4898 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4900 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4901 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4902 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4903 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4908 if (ppc_is_imm16 (inst->inst_offset)) {
4909 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4911 if (ppc_is_imm32 (inst->inst_offset)) {
4912 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4913 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
4915 ppc_load (code, ppc_r12, inst->inst_offset);
4916 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4921 } else if (ainfo->regtype == RegTypeBase) {
4922 g_assert (ppc_is_imm16 (ainfo->offset));
4923 /* load the previous stack pointer in r12 */
4924 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4925 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
4926 switch (ainfo->size) {
4928 if (ppc_is_imm16 (inst->inst_offset)) {
4929 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4931 if (ppc_is_imm32 (inst->inst_offset)) {
4932 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4933 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
4935 ppc_load (code, ppc_r12, inst->inst_offset);
4936 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4941 if (ppc_is_imm16 (inst->inst_offset)) {
4942 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4944 if (ppc_is_imm32 (inst->inst_offset)) {
4945 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4946 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
4948 ppc_load (code, ppc_r12, inst->inst_offset);
4949 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4953 #ifdef __mono_ppc64__
4955 if (ppc_is_imm16 (inst->inst_offset)) {
4956 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4958 if (ppc_is_imm32 (inst->inst_offset)) {
4959 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4960 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
4962 ppc_load (code, ppc_r12, inst->inst_offset);
4963 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
4968 if (ppc_is_imm16 (inst->inst_offset)) {
4969 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4971 ppc_load (code, ppc_r12, inst->inst_offset);
4972 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
4977 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4978 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4979 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4980 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
4981 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4983 /* use r11 to load the 2nd half of the long before we clobber r12. */
4984 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
4985 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4986 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4987 ppc_stw (code, ppc_r0, 0, ppc_r12);
4988 ppc_stw (code, ppc_r11, 4, ppc_r12);
4993 if (ppc_is_imm16 (inst->inst_offset)) {
4994 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4996 if (ppc_is_imm32 (inst->inst_offset)) {
4997 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4998 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5000 ppc_load (code, ppc_r12, inst->inst_offset);
5001 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5006 } else if (ainfo->regtype == RegTypeFP) {
5007 g_assert (ppc_is_imm16 (inst->inst_offset));
5008 if (ainfo->size == 8)
5009 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5010 else if (ainfo->size == 4)
5011 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5013 g_assert_not_reached ();
5014 } else if (ainfo->regtype == RegTypeStructByVal) {
5015 int doffset = inst->inst_offset;
5019 g_assert (ppc_is_imm16 (inst->inst_offset));
5020 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5021 /* FIXME: what if there is no class? */
5022 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5023 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5024 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5027 * Darwin handles 1 and 2 byte
5028 * structs specially by
5029 * loading h/b into the arg
5030 * register. Only done for
5034 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5036 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5040 #ifdef __mono_ppc64__
5042 g_assert (cur_reg == 0);
5043 ppc_sldi (code, ppc_r0, ainfo->reg,
5044 (sizeof (gpointer) - ainfo->bytes) * 8);
5045 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5049 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5050 inst->inst_basereg);
5053 soffset += sizeof (gpointer);
5054 doffset += sizeof (gpointer);
5056 if (ainfo->vtsize) {
5057 /* FIXME: we need to do the shifting here, too */
5060 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5061 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5062 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5063 code = emit_memcpy (code, size - soffset,
5064 inst->inst_basereg, doffset,
5065 ppc_r12, ainfo->offset + soffset);
5067 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5068 inst->inst_basereg, doffset,
5069 ppc_r12, ainfo->offset + soffset);
5072 } else if (ainfo->regtype == RegTypeStructByAddr) {
5073 /* if it was originally a RegTypeBase */
5074 if (ainfo->offset) {
5075 /* load the previous stack pointer in r12 */
5076 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5077 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5079 ppc_mr (code, ppc_r12, ainfo->reg);
5082 if (cfg->tailcall_valuetype_addrs) {
5083 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5085 g_assert (ppc_is_imm16 (addr->inst_offset));
5086 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5088 tailcall_struct_index++;
5091 g_assert (ppc_is_imm16 (inst->inst_offset));
5092 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5093 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5095 g_assert_not_reached ();
5100 if (method->save_lmf) {
5101 if (lmf_pthread_key != -1) {
5102 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5103 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5104 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5106 if (cfg->compile_aot) {
5107 /* Compute the got address which is needed by the PLT entry */
5108 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5110 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5111 (gpointer)"mono_get_lmf_addr");
5112 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5113 ppc_load_func (code, PPC_CALL_REG, 0);
5114 ppc_mtlr (code, PPC_CALL_REG);
5120 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5121 /* lmf_offset is the offset from the previous stack pointer,
5122 * alloc_size is the total stack space allocated, so the offset
5123 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5124 * The pointer to the struct is put in ppc_r12 (new_lmf).
5125 * The callee-saved registers are already in the MonoLMF structure
5127 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5128 /* ppc_r3 is the result from mono_get_lmf_addr () */
5129 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5130 /* new_lmf->previous_lmf = *lmf_addr */
5131 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5132 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5133 /* *(lmf_addr) = r12 */
5134 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5135 /* save method info */
5136 if (cfg->compile_aot)
5138 ppc_load (code, ppc_r0, 0);
5140 ppc_load_ptr (code, ppc_r0, method);
5141 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5142 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5143 /* save the current IP */
5144 if (cfg->compile_aot) {
5146 ppc_mflr (code, ppc_r0);
5148 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5149 #ifdef __mono_ppc64__
5150 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5152 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5155 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5159 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5161 cfg->code_len = code - cfg->native_code;
5162 g_assert (cfg->code_len <= cfg->code_size);
5169 mono_arch_emit_epilog (MonoCompile *cfg)
5171 MonoMethod *method = cfg->method;
5173 int max_epilog_size = 16 + 20*4;
5176 if (cfg->method->save_lmf)
5177 max_epilog_size += 128;
5179 if (mono_jit_trace_calls != NULL)
5180 max_epilog_size += 50;
5182 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5183 max_epilog_size += 50;
5185 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5186 cfg->code_size *= 2;
5187 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5188 cfg->stat_code_reallocs++;
5192 * Keep in sync with OP_JMP
5194 code = cfg->native_code + cfg->code_len;
5196 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5197 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5201 if (method->save_lmf) {
5203 pos += sizeof (MonoLMF);
5205 /* save the frame reg in r8 */
5206 ppc_mr (code, ppc_r8, cfg->frame_reg);
5207 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5208 /* r5 = previous_lmf */
5209 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5211 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5212 /* *(lmf_addr) = previous_lmf */
5213 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5214 /* FIXME: speedup: there is no actual need to restore the registers if
5215 * we didn't actually change them (idea from Zoltan).
5218 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5220 /*for (i = 14; i < 32; i++) {
5221 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5223 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5224 /* use the saved copy of the frame reg in r8 */
5225 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5226 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5227 ppc_mtlr (code, ppc_r0);
5229 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5231 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5232 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5233 if (ppc_is_imm16 (return_offset)) {
5234 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5236 ppc_load (code, ppc_r12, return_offset);
5237 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5239 ppc_mtlr (code, ppc_r0);
5241 if (ppc_is_imm16 (cfg->stack_usage)) {
5242 int offset = cfg->stack_usage;
5243 for (i = 13; i <= 31; i++) {
5244 if (cfg->used_int_regs & (1 << i))
5245 offset -= sizeof (mgreg_t);
5247 if (cfg->frame_reg != ppc_sp)
5248 ppc_mr (code, ppc_r12, cfg->frame_reg);
5249 /* note r31 (possibly the frame register) is restored last */
5250 for (i = 13; i <= 31; i++) {
5251 if (cfg->used_int_regs & (1 << i)) {
5252 ppc_ldr (code, i, offset, cfg->frame_reg);
5253 offset += sizeof (mgreg_t);
5256 if (cfg->frame_reg != ppc_sp)
5257 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5259 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5261 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5262 if (cfg->used_int_regs) {
5263 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5264 for (i = 31; i >= 13; --i) {
5265 if (cfg->used_int_regs & (1 << i)) {
5266 pos += sizeof (mgreg_t);
5267 ppc_ldr (code, i, -pos, ppc_r12);
5270 ppc_mr (code, ppc_sp, ppc_r12);
5272 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5279 cfg->code_len = code - cfg->native_code;
5281 g_assert (cfg->code_len < cfg->code_size);
5284 #endif /* ifndef DISABLE_JIT */
5286 /* remove once throw_exception_by_name is eliminated */
5288 exception_id_by_name (const char *name)
5290 if (strcmp (name, "IndexOutOfRangeException") == 0)
5291 return MONO_EXC_INDEX_OUT_OF_RANGE;
5292 if (strcmp (name, "OverflowException") == 0)
5293 return MONO_EXC_OVERFLOW;
5294 if (strcmp (name, "ArithmeticException") == 0)
5295 return MONO_EXC_ARITHMETIC;
5296 if (strcmp (name, "DivideByZeroException") == 0)
5297 return MONO_EXC_DIVIDE_BY_ZERO;
5298 if (strcmp (name, "InvalidCastException") == 0)
5299 return MONO_EXC_INVALID_CAST;
5300 if (strcmp (name, "NullReferenceException") == 0)
5301 return MONO_EXC_NULL_REF;
5302 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5303 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5304 if (strcmp (name, "ArgumentException") == 0)
5305 return MONO_EXC_ARGUMENT;
5306 g_error ("Unknown intrinsic exception %s\n", name);
5312 mono_arch_emit_exceptions (MonoCompile *cfg)
5314 MonoJumpInfo *patch_info;
5317 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5318 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5319 int max_epilog_size = 50;
5321 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5322 exc_throw_pos [i] = NULL;
5323 exc_throw_found [i] = 0;
5326 /* count the number of exception infos */
5329 * make sure we have enough space for exceptions
5331 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5332 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5333 i = exception_id_by_name (patch_info->data.target);
5334 if (!exc_throw_found [i]) {
5335 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5336 exc_throw_found [i] = TRUE;
5338 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5339 max_epilog_size += 12;
5340 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5341 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5342 i = exception_id_by_name (ovfj->data.exception);
5343 if (!exc_throw_found [i]) {
5344 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5345 exc_throw_found [i] = TRUE;
5347 max_epilog_size += 8;
5351 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5352 cfg->code_size *= 2;
5353 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5354 cfg->stat_code_reallocs++;
5357 code = cfg->native_code + cfg->code_len;
5359 /* add code to raise exceptions */
5360 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5361 switch (patch_info->type) {
5362 case MONO_PATCH_INFO_BB_OVF: {
5363 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5364 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5365 /* patch the initial jump */
5366 ppc_patch (ip, code);
5367 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5369 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5370 /* jump back to the true target */
5372 ip = ovfj->data.bb->native_offset + cfg->native_code;
5373 ppc_patch (code - 4, ip);
5374 patch_info->type = MONO_PATCH_INFO_NONE;
5377 case MONO_PATCH_INFO_EXC_OVF: {
5378 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5379 MonoJumpInfo *newji;
5380 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5381 unsigned char *bcl = code;
5382 /* patch the initial jump: we arrived here with a call */
5383 ppc_patch (ip, code);
5384 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5386 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5387 /* patch the conditional jump to the right handler */
5388 /* make it processed next */
5389 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5390 newji->type = MONO_PATCH_INFO_EXC;
5391 newji->ip.i = bcl - cfg->native_code;
5392 newji->data.target = ovfj->data.exception;
5393 newji->next = patch_info->next;
5394 patch_info->next = newji;
5395 patch_info->type = MONO_PATCH_INFO_NONE;
5398 case MONO_PATCH_INFO_EXC: {
5399 MonoClass *exc_class;
5401 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5402 i = exception_id_by_name (patch_info->data.target);
5403 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5404 ppc_patch (ip, exc_throw_pos [i]);
5405 patch_info->type = MONO_PATCH_INFO_NONE;
5408 exc_throw_pos [i] = code;
5411 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5412 g_assert (exc_class);
5414 ppc_patch (ip, code);
5415 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5416 ppc_load (code, ppc_r3, exc_class->type_token);
5417 /* we got here from a conditional call, so the calling ip is set in lr */
5418 ppc_mflr (code, ppc_r4);
5419 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5420 patch_info->data.name = "mono_arch_throw_corlib_exception";
5421 patch_info->ip.i = code - cfg->native_code;
5422 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5423 ppc_load_func (code, PPC_CALL_REG, 0);
5424 ppc_mtctr (code, PPC_CALL_REG);
5425 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5437 cfg->code_len = code - cfg->native_code;
5439 g_assert (cfg->code_len <= cfg->code_size);
5445 try_offset_access (void *value, guint32 idx)
5447 register void* me __asm__ ("r2");
5448 void ***p = (void***)((char*)me + 284);
5449 int idx1 = idx / 32;
5450 int idx2 = idx % 32;
5453 if (value != p[idx1][idx2])
5460 setup_tls_access (void)
5462 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5463 size_t conf_size = 0;
5466 /* FIXME for darwin */
5467 guint32 *ins, *code;
5468 guint32 cmplwi_1023, li_0x48, blr_ins;
5472 tls_mode = TLS_MODE_FAILED;
5475 if (tls_mode == TLS_MODE_FAILED)
5477 if (g_getenv ("MONO_NO_TLS")) {
5478 tls_mode = TLS_MODE_FAILED;
5482 if (tls_mode == TLS_MODE_DETECT) {
5483 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5484 tls_mode = TLS_MODE_DARWIN_G4;
5485 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5486 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5487 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5488 tls_mode = TLS_MODE_NPTL;
5489 #elif !defined(TARGET_PS3)
5490 ins = (guint32*)pthread_getspecific;
5491 /* uncond branch to the real method */
5492 if ((*ins >> 26) == 18) {
5494 val = (*ins & ~3) << 6;
5498 ins = (guint32*)(long)val;
5500 ins = (guint32*) ((char*)ins + val);
5503 code = &cmplwi_1023;
5504 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5506 ppc_li (code, ppc_r4, 0x48);
5509 if (*ins == cmplwi_1023) {
5510 int found_lwz_284 = 0;
5512 for (ptk = 0; ptk < 20; ++ptk) {
5514 if (!*ins || *ins == blr_ins)
5516 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5521 if (!found_lwz_284) {
5522 tls_mode = TLS_MODE_FAILED;
5525 tls_mode = TLS_MODE_LTHREADS;
5526 } else if (*ins == li_0x48) {
5528 /* uncond branch to the real method */
5529 if ((*ins >> 26) == 18) {
5531 val = (*ins & ~3) << 6;
5535 ins = (guint32*)(long)val;
5537 ins = (guint32*) ((char*)ins + val);
5539 code = (guint32*)&val;
5540 ppc_li (code, ppc_r0, 0x7FF2);
5541 if (ins [1] == val) {
5542 /* Darwin on G4, implement */
5543 tls_mode = TLS_MODE_FAILED;
5546 code = (guint32*)&val;
5547 ppc_mfspr (code, ppc_r3, 104);
5548 if (ins [1] != val) {
5549 tls_mode = TLS_MODE_FAILED;
5552 tls_mode = TLS_MODE_DARWIN_G5;
5555 tls_mode = TLS_MODE_FAILED;
5559 tls_mode = TLS_MODE_FAILED;
5565 if (tls_mode == TLS_MODE_DETECT)
5566 tls_mode = TLS_MODE_FAILED;
5567 if (tls_mode == TLS_MODE_FAILED)
5569 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5570 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5574 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5575 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5576 if (lmf_pthread_key == -1) {
5577 guint32 ptk = mono_jit_tls_id;
5579 /*g_print ("MonoLMF at: %d\n", ptk);*/
5580 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5581 init_tls_failed = 1;
5584 lmf_pthread_key = ptk;
5593 mono_arch_finish_init (void)
5595 setup_tls_access ();
5599 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5603 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5605 #define LOADSTORE_SIZE 4
5606 #define JUMP_IMM_SIZE 12
5607 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5608 #define ENABLE_WRONG_METHOD_CHECK 0
5611 * LOCKING: called with the domain lock held
5614 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5615 gpointer fail_tramp)
5619 guint8 *code, *start;
5621 for (i = 0; i < count; ++i) {
5622 MonoIMTCheckItem *item = imt_entries [i];
5623 if (item->is_equals) {
5624 if (item->check_target_idx) {
5625 if (!item->compare_done)
5626 item->chunk_size += CMP_SIZE;
5627 if (item->has_target_code)
5628 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5630 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5633 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5634 if (!item->has_target_code)
5635 item->chunk_size += LOADSTORE_SIZE;
5637 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5638 #if ENABLE_WRONG_METHOD_CHECK
5639 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5644 item->chunk_size += CMP_SIZE + BR_SIZE;
5645 imt_entries [item->check_target_idx]->compare_done = TRUE;
5647 size += item->chunk_size;
5649 /* the initial load of the vtable address */
5650 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5652 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5654 code = mono_domain_code_reserve (domain, size);
5659 * We need to save and restore r12 because it might be
5660 * used by the caller as the vtable register, so
5661 * clobbering it will trip up the magic trampoline.
5663 * FIXME: Get rid of this by making sure that r12 is
5664 * not used as the vtable register in interface calls.
5666 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5667 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5669 for (i = 0; i < count; ++i) {
5670 MonoIMTCheckItem *item = imt_entries [i];
5671 item->code_target = code;
5672 if (item->is_equals) {
5673 if (item->check_target_idx) {
5674 if (!item->compare_done) {
5675 ppc_load (code, ppc_r0, (gsize)item->key);
5676 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5678 item->jmp_code = code;
5679 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5680 if (item->has_target_code) {
5681 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5683 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5684 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5686 ppc_mtctr (code, ppc_r0);
5687 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5690 ppc_load (code, ppc_r0, (gulong)item->key);
5691 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5692 item->jmp_code = code;
5693 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5694 if (item->has_target_code) {
5695 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5698 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5699 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5701 ppc_mtctr (code, ppc_r0);
5702 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5703 ppc_patch (item->jmp_code, code);
5704 ppc_load_ptr (code, ppc_r0, fail_tramp);
5705 ppc_mtctr (code, ppc_r0);
5706 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5707 item->jmp_code = NULL;
5709 /* enable the commented code to assert on wrong method */
5710 #if ENABLE_WRONG_METHOD_CHECK
5711 ppc_load (code, ppc_r0, (guint32)item->key);
5712 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5713 item->jmp_code = code;
5714 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5716 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5717 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5718 ppc_mtctr (code, ppc_r0);
5719 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5720 #if ENABLE_WRONG_METHOD_CHECK
5721 ppc_patch (item->jmp_code, code);
5723 item->jmp_code = NULL;
5728 ppc_load (code, ppc_r0, (gulong)item->key);
5729 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5730 item->jmp_code = code;
5731 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5734 /* patch the branches to get to the target items */
5735 for (i = 0; i < count; ++i) {
5736 MonoIMTCheckItem *item = imt_entries [i];
5737 if (item->jmp_code) {
5738 if (item->check_target_idx) {
5739 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5745 mono_stats.imt_thunks_size += code - start;
5746 g_assert (code - start <= size);
5747 mono_arch_flush_icache (start, size);
5752 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5754 mgreg_t *r = (mgreg_t*)regs;
5756 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5760 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5762 mgreg_t *r = (mgreg_t*)regs;
5764 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5768 mono_arch_get_cie_program (void)
5772 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5778 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5785 mono_arch_print_tree (MonoInst *tree, int arity)
5791 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5794 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5796 g_assert (reg >= ppc_r13);
5798 return ctx->regs [reg - ppc_r13];
5802 mono_arch_get_patch_offset (guint8 *code)
5808 * mono_aot_emit_load_got_addr:
5810 * Emit code to load the got address.
5811 * On PPC, the result is placed into r30.
5814 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5817 ppc_mflr (code, ppc_r30);
5819 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5821 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5822 /* arch_emit_got_address () patches this */
5823 #if defined(TARGET_POWERPC64)
5829 ppc_load32 (code, ppc_r0, 0);
5830 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5837 * mono_ppc_emit_load_aotconst:
5839 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5840 * TARGET from the mscorlib GOT in full-aot code.
5841 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5845 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5847 /* Load the mscorlib got address */
5848 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5849 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5850 /* arch_emit_got_access () patches this */
5851 ppc_load32 (code, ppc_r0, 0);
5852 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5857 /* Soft Debug support */
5858 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5865 * mono_arch_set_breakpoint:
5867 * See mini-amd64.c for docs.
5870 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5873 guint8 *orig_code = code;
5875 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5876 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5878 g_assert (code - orig_code == BREAKPOINT_SIZE);
5880 mono_arch_flush_icache (orig_code, code - orig_code);
5884 * mono_arch_clear_breakpoint:
5886 * See mini-amd64.c for docs.
5889 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5894 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5897 mono_arch_flush_icache (ip, code - ip);
5901 * mono_arch_is_breakpoint_event:
5903 * See mini-amd64.c for docs.
5906 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5908 siginfo_t* sinfo = (siginfo_t*) info;
5909 /* Sometimes the address is off by 4 */
5910 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5917 * mono_arch_skip_breakpoint:
5919 * See mini-amd64.c for docs.
5922 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5924 /* skip the ldptr */
5925 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5933 * mono_arch_start_single_stepping:
5935 * See mini-amd64.c for docs.
5938 mono_arch_start_single_stepping (void)
5940 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5944 * mono_arch_stop_single_stepping:
5946 * See mini-amd64.c for docs.
5949 mono_arch_stop_single_stepping (void)
5951 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5955 * mono_arch_is_single_step_event:
5957 * See mini-amd64.c for docs.
5960 mono_arch_is_single_step_event (void *info, void *sigctx)
5962 siginfo_t* sinfo = (siginfo_t*) info;
5963 /* Sometimes the address is off by 4 */
5964 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5971 * mono_arch_skip_single_step:
5973 * See mini-amd64.c for docs.
5976 mono_arch_skip_single_step (MonoContext *ctx)
5978 /* skip the ldptr */
5979 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5983 * mono_arch_create_seq_point_info:
5985 * See mini-amd64.c for docs.
5988 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5995 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5997 ext->lmf.previous_lmf = prev_lmf;
5998 /* Mark that this is a MonoLMFExt */
5999 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6000 ext->lmf.ebp = (gssize)ext;
6006 mono_arch_opcode_supported (int opcode)
6009 case OP_ATOMIC_ADD_I4:
6010 case OP_ATOMIC_CAS_I4:
6011 #ifdef TARGET_POWERPC64
6012 case OP_ATOMIC_ADD_I8:
6013 case OP_ATOMIC_CAS_I8: