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/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
19 #include <mono/utils/mono-hwcap-ppc.h>
22 #ifdef TARGET_POWERPC64
23 #include "cpu-ppc64.h"
30 #include <sys/sysctl.h>
36 #define FORCE_INDIR_CALL 1
47 /* cpu_hw_caps contains the flags defined below */
48 static int cpu_hw_caps = 0;
49 static int cachelinesize = 0;
50 static int cachelineinc = 0;
52 PPC_ICACHE_SNOOP = 1 << 0,
53 PPC_MULTIPLE_LS_UNITS = 1 << 1,
54 PPC_SMP_CAPABLE = 1 << 2,
57 PPC_MOVE_FPR_GPR = 1 << 5,
61 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
63 /* This mutex protects architecture specific caches */
64 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
65 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
66 static CRITICAL_SECTION mini_arch_mutex;
68 int mono_exc_esp_offset = 0;
69 static int tls_mode = TLS_MODE_DETECT;
70 static int lmf_pthread_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
82 offsets_from_pthread_key (guint32 key, int *offset2)
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
161 if (reg >= 0 && reg < 32)
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
177 if (reg >= 0 && reg < 32)
182 /* this function overwrites r0, r11, r12 */
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 //g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
283 int k, frame_size = 0;
284 int size, align, pad;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
292 arg_info [0].offset = offset;
295 frame_size += sizeof (gpointer);
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
317 arg_info [k + 1].offset = offset;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
329 #ifdef __mono_ppc64__
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
349 mono_ppc_is_direct_call_sequence (guint32 *code)
351 #ifdef __mono_ppc64__
352 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
357 if (!is_load_sequence (&code [-8]))
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
361 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
363 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code [-8]);
366 return is_load_sequence (&code [-6]);
370 g_assert(*code == 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code [-1]) == 31 &&
374 ppc_opcode (code [-2]) == 24 &&
375 ppc_opcode (code [-3]) == 15;
379 #define MAX_ARCH_DELEGATE_PARAMS 7
382 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
384 guint8 *code, *start;
387 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
389 start = code = mono_global_codeman_reserve (size);
391 code = mono_ppc_create_pre_code_ftnptr (code);
393 /* Replace the this argument with the target */
394 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
395 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
396 /* it's a function descriptor */
397 /* Can't use ldptr as it doesn't work with r0 */
398 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
400 ppc_mtctr (code, ppc_r0);
401 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
402 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
404 g_assert ((code - start) <= size);
406 mono_arch_flush_icache (start, size);
410 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
411 start = code = mono_global_codeman_reserve (size);
413 code = mono_ppc_create_pre_code_ftnptr (code);
415 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
417 /* it's a function descriptor */
418 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
420 ppc_mtctr (code, ppc_r0);
421 /* slide down the arguments */
422 for (i = 0; i < param_count; ++i) {
423 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
425 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
427 g_assert ((code - start) <= size);
429 mono_arch_flush_icache (start, size);
433 *code_len = code - start;
439 mono_arch_get_delegate_invoke_impls (void)
447 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
448 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
450 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
451 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
452 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
453 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
461 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
463 guint8 *code, *start;
465 /* FIXME: Support more cases */
466 if (MONO_TYPE_ISSTRUCT (sig->ret))
470 static guint8* cached = NULL;
476 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
478 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
480 mono_memory_barrier ();
484 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
487 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
489 for (i = 0; i < sig->param_count; ++i)
490 if (!mono_is_regsize_var (sig->params [i]))
494 code = cache [sig->param_count];
499 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
500 start = mono_aot_get_trampoline (name);
503 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
506 mono_memory_barrier ();
508 cache [sig->param_count] = start;
514 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
516 mgreg_t *r = (mgreg_t*)regs;
518 return (gpointer)(gsize)r [ppc_r3];
526 #define MAX_AUX_ENTRIES 128
528 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
529 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
531 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
533 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
534 #define ISA_64 0x40000000
536 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
537 #define ISA_MOVE_FPR_GPR 0x00000200
539 * Initialize the cpu to execute managed code.
542 mono_arch_cpu_init (void)
547 * Initialize architecture specific code.
550 mono_arch_init (void)
552 #if defined(MONO_CROSS_COMPILE)
553 #elif defined(__APPLE__)
555 size_t len = sizeof (cachelinesize);
558 mib [1] = HW_CACHELINE;
560 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
564 cachelineinc = cachelinesize;
566 #elif defined(__linux__)
567 AuxVec vec [MAX_AUX_ENTRIES];
568 int i, vec_entries = 0;
569 /* sadly this will work only with 2.6 kernels... */
570 FILE* f = fopen ("/proc/self/auxv", "rb");
573 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
577 for (i = 0; i < vec_entries; i++) {
578 int type = vec [i].type;
580 if (type == 19) { /* AT_DCACHEBSIZE */
581 cachelinesize = vec [i].value;
585 #elif defined(G_COMPILER_CODEWARRIOR)
589 //#error Need a way to get cache line size
592 if (mono_hwcap_ppc_has_icache_snoop)
593 cpu_hw_caps |= PPC_ICACHE_SNOOP;
595 if (mono_hwcap_ppc_is_isa_2x)
596 cpu_hw_caps |= PPC_ISA_2X;
598 if (mono_hwcap_ppc_is_isa_64)
599 cpu_hw_caps |= PPC_ISA_64;
601 if (mono_hwcap_ppc_has_move_fpr_gpr)
602 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
604 if (mono_hwcap_ppc_has_multiple_ls_units)
605 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
611 cachelineinc = cachelinesize;
613 if (mono_cpu_count () > 1)
614 cpu_hw_caps |= PPC_SMP_CAPABLE;
616 InitializeCriticalSection (&mini_arch_mutex);
618 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
619 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
620 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
622 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
626 * Cleanup architecture specific code.
629 mono_arch_cleanup (void)
631 DeleteCriticalSection (&mini_arch_mutex);
635 * This function returns the optimizations supported on this cpu.
638 mono_arch_cpu_optimizations (guint32 *exclude_mask)
642 /* no ppc-specific optimizations yet */
648 * This function test for all SIMD functions supported.
650 * Returns a bitmask corresponding to all supported versions.
654 mono_arch_cpu_enumerate_simd_versions (void)
656 /* SIMD is currently unimplemented */
660 #ifdef __mono_ppc64__
661 #define CASE_PPC32(c)
662 #define CASE_PPC64(c) case c:
664 #define CASE_PPC32(c) case c:
665 #define CASE_PPC64(c)
669 is_regsize_var (MonoType *t) {
672 t = mini_type_get_underlying_type (NULL, t);
676 CASE_PPC64 (MONO_TYPE_I8)
677 CASE_PPC64 (MONO_TYPE_U8)
681 case MONO_TYPE_FNPTR:
683 case MONO_TYPE_OBJECT:
684 case MONO_TYPE_STRING:
685 case MONO_TYPE_CLASS:
686 case MONO_TYPE_SZARRAY:
687 case MONO_TYPE_ARRAY:
689 case MONO_TYPE_GENERICINST:
690 if (!mono_type_generic_inst_is_valuetype (t))
693 case MONO_TYPE_VALUETYPE:
701 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
706 for (i = 0; i < cfg->num_varinfo; i++) {
707 MonoInst *ins = cfg->varinfo [i];
708 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
711 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
714 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
717 /* we can only allocate 32 bit values */
718 if (is_regsize_var (ins->inst_vtype)) {
719 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
720 g_assert (i == vmv->idx);
721 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
727 #endif /* ifndef DISABLE_JIT */
730 mono_arch_get_global_int_regs (MonoCompile *cfg)
734 if (cfg->frame_reg != ppc_sp)
736 /* ppc_r13 is used by the system on PPC EABI */
737 for (i = 14; i < top; ++i) {
739 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
740 * since the trampolines can clobber r11.
742 if (!(cfg->compile_aot && i == 29))
743 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
750 * mono_arch_regalloc_cost:
752 * Return the cost, in number of memory references, of the action of
753 * allocating the variable VMV into a register during global register
757 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
764 mono_arch_flush_icache (guint8 *code, gint size)
766 #ifdef MONO_CROSS_COMPILE
769 guint8 *endp, *start;
773 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
774 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
775 #if defined(G_COMPILER_CODEWARRIOR)
776 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
777 for (p = start; p < endp; p += cachelineinc) {
781 for (p = start; p < endp; p += cachelineinc) {
787 for (p = start; p < endp; p += cachelineinc) {
798 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
799 * The sync is required to insure that the store queue is completely empty.
800 * While the icbi performs no cache operations, icbi/isync is required to
801 * kill local prefetch.
803 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
805 asm ("icbi 0,%0;" : : "r"(code) : "memory");
809 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
810 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
811 for (p = start; p < endp; p += cachelineinc) {
812 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
815 for (p = start; p < endp; p += cachelineinc) {
816 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
821 for (p = start; p < endp; p += cachelineinc) {
822 /* for ISA2.0+ implementations we should not need any extra sync between the
823 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
824 * So I am not sure which chip had this problem but its not an issue on
825 * of the ISA V2 chips.
827 if (cpu_hw_caps & PPC_ISA_2X)
828 asm ("icbi 0,%0;" : : "r"(p) : "memory");
830 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
832 if (!(cpu_hw_caps & PPC_ISA_2X))
840 mono_arch_flush_register_windows (void)
845 #define ALWAYS_ON_STACK(s) s
846 #define FP_ALSO_IN_REG(s) s
848 #ifdef __mono_ppc64__
849 #define ALWAYS_ON_STACK(s) s
850 #define FP_ALSO_IN_REG(s) s
852 #define ALWAYS_ON_STACK(s)
853 #define FP_ALSO_IN_REG(s)
855 #define ALIGN_DOUBLES
868 guint32 vtsize; /* in param area */
870 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
871 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
872 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
873 guint8 bytes : 4; /* size in bytes - only valid for
874 RegTypeStructByVal if the struct fits
875 in one word, otherwise it's 0*/
884 gboolean vtype_retaddr;
892 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
894 #ifdef __mono_ppc64__
899 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
900 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
901 ainfo->reg = ppc_sp; /* in the caller */
902 ainfo->regtype = RegTypeBase;
903 *stack_size += sizeof (gpointer);
905 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
909 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
911 //*stack_size += (*stack_size % 8);
913 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
914 ainfo->reg = ppc_sp; /* in the caller */
915 ainfo->regtype = RegTypeBase;
922 ALWAYS_ON_STACK (*stack_size += 8);
930 #if defined(__APPLE__) || defined(__mono_ppc64__)
932 has_only_a_r48_field (MonoClass *klass)
936 gboolean have_field = FALSE;
938 while ((f = mono_class_get_fields (klass, &iter))) {
939 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
942 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
953 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
955 guint i, fr, gr, pstart;
956 int n = sig->hasthis + sig->param_count;
957 MonoType *simpletype;
958 guint32 stack_size = 0;
959 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
960 gboolean is_pinvoke = sig->pinvoke;
962 fr = PPC_FIRST_FPARG_REG;
963 gr = PPC_FIRST_ARG_REG;
965 /* FIXME: handle returning a struct */
966 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
967 cinfo->vtype_retaddr = TRUE;
973 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
974 * the first argument, allowing 'this' to be always passed in the first arg reg.
975 * Also do this if the first argument is a reference type, since virtual calls
976 * are sometimes made using calli without sig->hasthis set, like in the delegate
979 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]))))) {
981 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
984 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
988 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
989 cinfo->struct_ret = cinfo->ret.reg;
990 cinfo->vret_arg_index = 1;
994 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
998 if (cinfo->vtype_retaddr) {
999 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1000 cinfo->struct_ret = cinfo->ret.reg;
1004 DEBUG(printf("params: %d\n", sig->param_count));
1005 for (i = pstart; i < sig->param_count; ++i) {
1006 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1007 /* Prevent implicit arguments and sig_cookie from
1008 being passed in registers */
1009 gr = PPC_LAST_ARG_REG + 1;
1010 /* FIXME: don't we have to set fr, too? */
1011 /* Emit the signature cookie just before the implicit arguments */
1012 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1014 DEBUG(printf("param %d: ", i));
1015 if (sig->params [i]->byref) {
1016 DEBUG(printf("byref\n"));
1017 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1021 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1022 switch (simpletype->type) {
1023 case MONO_TYPE_BOOLEAN:
1026 cinfo->args [n].size = 1;
1027 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1030 case MONO_TYPE_CHAR:
1033 cinfo->args [n].size = 2;
1034 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1039 cinfo->args [n].size = 4;
1040 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1046 case MONO_TYPE_FNPTR:
1047 case MONO_TYPE_CLASS:
1048 case MONO_TYPE_OBJECT:
1049 case MONO_TYPE_STRING:
1050 case MONO_TYPE_SZARRAY:
1051 case MONO_TYPE_ARRAY:
1052 cinfo->args [n].size = sizeof (gpointer);
1053 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1056 case MONO_TYPE_GENERICINST:
1057 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1058 cinfo->args [n].size = sizeof (gpointer);
1059 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1064 case MONO_TYPE_VALUETYPE:
1065 case MONO_TYPE_TYPEDBYREF: {
1069 klass = mono_class_from_mono_type (sig->params [i]);
1070 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1071 size = sizeof (MonoTypedRef);
1072 else if (is_pinvoke)
1073 size = mono_class_native_size (klass, NULL);
1075 size = mono_class_value_size (klass, NULL);
1077 #if defined(__APPLE__) || defined(__mono_ppc64__)
1078 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1079 cinfo->args [n].size = size;
1081 /* It was 7, now it is 8 in LinuxPPC */
1082 if (fr <= PPC_LAST_FPARG_REG) {
1083 cinfo->args [n].regtype = RegTypeFP;
1084 cinfo->args [n].reg = fr;
1086 FP_ALSO_IN_REG (gr ++);
1088 FP_ALSO_IN_REG (gr ++);
1089 ALWAYS_ON_STACK (stack_size += size);
1091 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1092 cinfo->args [n].regtype = RegTypeBase;
1093 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1100 DEBUG(printf ("load %d bytes struct\n",
1101 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1103 #if PPC_PASS_STRUCTS_BY_VALUE
1105 int align_size = size;
1107 int rest = PPC_LAST_ARG_REG - gr + 1;
1110 align_size += (sizeof (gpointer) - 1);
1111 align_size &= ~(sizeof (gpointer) - 1);
1112 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1113 n_in_regs = MIN (rest, nregs);
1117 /* FIXME: check this */
1118 if (size >= 3 && size % 4 != 0)
1121 cinfo->args [n].regtype = RegTypeStructByVal;
1122 cinfo->args [n].vtregs = n_in_regs;
1123 cinfo->args [n].size = n_in_regs;
1124 cinfo->args [n].vtsize = nregs - n_in_regs;
1125 cinfo->args [n].reg = gr;
1127 #ifdef __mono_ppc64__
1128 if (nregs == 1 && is_pinvoke)
1129 cinfo->args [n].bytes = size;
1132 cinfo->args [n].bytes = 0;
1134 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1135 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1136 stack_size += nregs * sizeof (gpointer);
1139 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1140 cinfo->args [n].regtype = RegTypeStructByAddr;
1141 cinfo->args [n].vtsize = size;
1148 cinfo->args [n].size = 8;
1149 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1153 cinfo->args [n].size = 4;
1155 /* It was 7, now it is 8 in LinuxPPC */
1156 if (fr <= PPC_LAST_FPARG_REG) {
1157 cinfo->args [n].regtype = RegTypeFP;
1158 cinfo->args [n].reg = fr;
1160 FP_ALSO_IN_REG (gr ++);
1161 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1163 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1164 cinfo->args [n].regtype = RegTypeBase;
1165 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1166 stack_size += SIZEOF_REGISTER;
1171 cinfo->args [n].size = 8;
1172 /* It was 7, now it is 8 in LinuxPPC */
1173 if (fr <= PPC_LAST_FPARG_REG) {
1174 cinfo->args [n].regtype = RegTypeFP;
1175 cinfo->args [n].reg = fr;
1177 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1178 ALWAYS_ON_STACK (stack_size += 8);
1180 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1181 cinfo->args [n].regtype = RegTypeBase;
1182 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1188 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1193 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1194 /* Prevent implicit arguments and sig_cookie from
1195 being passed in registers */
1196 gr = PPC_LAST_ARG_REG + 1;
1197 /* Emit the signature cookie just before the implicit arguments */
1198 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1202 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1203 switch (simpletype->type) {
1204 case MONO_TYPE_BOOLEAN:
1209 case MONO_TYPE_CHAR:
1215 case MONO_TYPE_FNPTR:
1216 case MONO_TYPE_CLASS:
1217 case MONO_TYPE_OBJECT:
1218 case MONO_TYPE_SZARRAY:
1219 case MONO_TYPE_ARRAY:
1220 case MONO_TYPE_STRING:
1221 cinfo->ret.reg = ppc_r3;
1225 cinfo->ret.reg = ppc_r3;
1229 cinfo->ret.reg = ppc_f1;
1230 cinfo->ret.regtype = RegTypeFP;
1232 case MONO_TYPE_GENERICINST:
1233 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1234 cinfo->ret.reg = ppc_r3;
1238 case MONO_TYPE_VALUETYPE:
1240 case MONO_TYPE_TYPEDBYREF:
1241 case MONO_TYPE_VOID:
1244 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1248 /* align stack size to 16 */
1249 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1250 stack_size = (stack_size + 15) & ~15;
1252 cinfo->stack_usage = stack_size;
1257 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1263 c1 = get_call_info (NULL, caller_sig);
1264 c2 = get_call_info (NULL, callee_sig);
1265 res = c1->stack_usage >= c2->stack_usage;
1266 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1267 /* An address on the callee's stack is passed as the first argument */
1269 for (i = 0; i < c2->nargs; ++i) {
1270 if (c2->args [i].regtype == RegTypeStructByAddr)
1271 /* An address on the callee's stack is passed as the argument */
1276 if (!mono_debug_count ())
1287 * Set var information according to the calling convention. ppc version.
1288 * The locals var stuff should most likely be split in another method.
1291 mono_arch_allocate_vars (MonoCompile *m)
1293 MonoMethodSignature *sig;
1294 MonoMethodHeader *header;
1296 int i, offset, size, align, curinst;
1297 int frame_reg = ppc_sp;
1299 guint32 locals_stack_size, locals_stack_align;
1301 m->flags |= MONO_CFG_HAS_SPILLUP;
1303 /* allow room for the vararg method args: void* and long/double */
1304 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1305 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1306 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1307 * call convs needs to be handled this way.
1309 if (m->flags & MONO_CFG_HAS_VARARGS)
1310 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1311 /* gtk-sharp and other broken code will dllimport vararg functions even with
1312 * non-varargs signatures. Since there is little hope people will get this right
1313 * we assume they won't.
1315 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1316 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1321 * We use the frame register also for any method that has
1322 * exception clauses. This way, when the handlers are called,
1323 * the code will reference local variables using the frame reg instead of
1324 * the stack pointer: if we had to restore the stack pointer, we'd
1325 * corrupt the method frames that are already on the stack (since
1326 * filters get called before stack unwinding happens) when the filter
1327 * code would call any method (this also applies to finally etc.).
1329 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1330 frame_reg = ppc_r31;
1331 m->frame_reg = frame_reg;
1332 if (frame_reg != ppc_sp) {
1333 m->used_int_regs |= 1 << frame_reg;
1336 sig = mono_method_signature (m->method);
1340 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1341 m->ret->opcode = OP_REGVAR;
1342 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1344 /* FIXME: handle long values? */
1345 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1346 case MONO_TYPE_VOID:
1350 m->ret->opcode = OP_REGVAR;
1351 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1354 m->ret->opcode = OP_REGVAR;
1355 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1359 /* local vars are at a positive offset from the stack pointer */
1361 * also note that if the function uses alloca, we use ppc_r31
1362 * to point at the local variables.
1364 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1365 /* align the offset to 16 bytes: not sure this is needed here */
1367 //offset &= ~(16 - 1);
1369 /* add parameter area size for called functions */
1370 offset += m->param_area;
1372 offset &= ~(16 - 1);
1374 /* allow room to save the return value */
1375 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1378 /* the MonoLMF structure is stored just below the stack pointer */
1381 /* this stuff should not be needed on ppc and the new jit,
1382 * because a call on ppc to the handlers doesn't change the
1383 * stack pointer and the jist doesn't manipulate the stack pointer
1384 * for operations involving valuetypes.
1386 /* reserve space to store the esp */
1387 offset += sizeof (gpointer);
1389 /* this is a global constant */
1390 mono_exc_esp_offset = offset;
1393 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1394 offset += sizeof(gpointer) - 1;
1395 offset &= ~(sizeof(gpointer) - 1);
1397 m->vret_addr->opcode = OP_REGOFFSET;
1398 m->vret_addr->inst_basereg = frame_reg;
1399 m->vret_addr->inst_offset = offset;
1401 if (G_UNLIKELY (m->verbose_level > 1)) {
1402 printf ("vret_addr =");
1403 mono_print_ins (m->vret_addr);
1406 offset += sizeof(gpointer);
1409 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1410 if (locals_stack_align) {
1411 offset += (locals_stack_align - 1);
1412 offset &= ~(locals_stack_align - 1);
1414 for (i = m->locals_start; i < m->num_varinfo; i++) {
1415 if (offsets [i] != -1) {
1416 MonoInst *inst = m->varinfo [i];
1417 inst->opcode = OP_REGOFFSET;
1418 inst->inst_basereg = frame_reg;
1419 inst->inst_offset = offset + offsets [i];
1421 g_print ("allocating local %d (%s) to %d\n",
1422 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1426 offset += locals_stack_size;
1430 inst = m->args [curinst];
1431 if (inst->opcode != OP_REGVAR) {
1432 inst->opcode = OP_REGOFFSET;
1433 inst->inst_basereg = frame_reg;
1434 offset += sizeof (gpointer) - 1;
1435 offset &= ~(sizeof (gpointer) - 1);
1436 inst->inst_offset = offset;
1437 offset += sizeof (gpointer);
1442 for (i = 0; i < sig->param_count; ++i) {
1443 inst = m->args [curinst];
1444 if (inst->opcode != OP_REGVAR) {
1445 inst->opcode = OP_REGOFFSET;
1446 inst->inst_basereg = frame_reg;
1448 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1449 inst->backend.is_pinvoke = 1;
1451 size = mono_type_size (sig->params [i], &align);
1453 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1454 size = align = sizeof (gpointer);
1456 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1457 * they are saved using std in the prolog.
1459 align = sizeof (gpointer);
1460 offset += align - 1;
1461 offset &= ~(align - 1);
1462 inst->inst_offset = offset;
1468 /* some storage for fp conversions */
1471 m->arch.fp_conv_var_offset = offset;
1474 /* align the offset to 16 bytes */
1476 offset &= ~(16 - 1);
1479 m->stack_offset = offset;
1481 if (sig->call_convention == MONO_CALL_VARARG) {
1482 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1484 m->sig_cookie = cinfo->sig_cookie.offset;
1491 mono_arch_create_vars (MonoCompile *cfg)
1493 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1495 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1496 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1500 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1501 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1505 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1507 int sig_reg = mono_alloc_ireg (cfg);
1509 /* FIXME: Add support for signature tokens to AOT */
1510 cfg->disable_aot = TRUE;
1512 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1513 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1514 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1518 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1521 MonoMethodSignature *sig;
1525 sig = call->signature;
1526 n = sig->param_count + sig->hasthis;
1528 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1530 for (i = 0; i < n; ++i) {
1531 ArgInfo *ainfo = cinfo->args + i;
1534 if (i >= sig->hasthis)
1535 t = sig->params [i - sig->hasthis];
1537 t = &mono_defaults.int_class->byval_arg;
1538 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1540 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1541 emit_sig_cookie (cfg, call, cinfo);
1543 in = call->args [i];
1545 if (ainfo->regtype == RegTypeGeneral) {
1546 #ifndef __mono_ppc64__
1547 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1548 MONO_INST_NEW (cfg, ins, OP_MOVE);
1549 ins->dreg = mono_alloc_ireg (cfg);
1550 ins->sreg1 = in->dreg + 1;
1551 MONO_ADD_INS (cfg->cbb, ins);
1552 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1554 MONO_INST_NEW (cfg, ins, OP_MOVE);
1555 ins->dreg = mono_alloc_ireg (cfg);
1556 ins->sreg1 = in->dreg + 2;
1557 MONO_ADD_INS (cfg->cbb, ins);
1558 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1562 MONO_INST_NEW (cfg, ins, OP_MOVE);
1563 ins->dreg = mono_alloc_ireg (cfg);
1564 ins->sreg1 = in->dreg;
1565 MONO_ADD_INS (cfg->cbb, ins);
1567 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1569 } else if (ainfo->regtype == RegTypeStructByAddr) {
1570 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1571 ins->opcode = OP_OUTARG_VT;
1572 ins->sreg1 = in->dreg;
1573 ins->klass = in->klass;
1574 ins->inst_p0 = call;
1575 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1576 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1577 MONO_ADD_INS (cfg->cbb, ins);
1578 } else if (ainfo->regtype == RegTypeStructByVal) {
1579 /* this is further handled in mono_arch_emit_outarg_vt () */
1580 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1581 ins->opcode = OP_OUTARG_VT;
1582 ins->sreg1 = in->dreg;
1583 ins->klass = in->klass;
1584 ins->inst_p0 = call;
1585 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1586 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1587 MONO_ADD_INS (cfg->cbb, ins);
1588 } else if (ainfo->regtype == RegTypeBase) {
1589 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1590 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1591 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1592 if (t->type == MONO_TYPE_R8)
1593 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1595 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1597 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1599 } else if (ainfo->regtype == RegTypeFP) {
1600 if (t->type == MONO_TYPE_VALUETYPE) {
1601 /* this is further handled in mono_arch_emit_outarg_vt () */
1602 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1603 ins->opcode = OP_OUTARG_VT;
1604 ins->sreg1 = in->dreg;
1605 ins->klass = in->klass;
1606 ins->inst_p0 = call;
1607 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1608 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1609 MONO_ADD_INS (cfg->cbb, ins);
1611 cfg->flags |= MONO_CFG_HAS_FPOUT;
1613 int dreg = mono_alloc_freg (cfg);
1615 if (ainfo->size == 4) {
1616 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1618 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1620 ins->sreg1 = in->dreg;
1621 MONO_ADD_INS (cfg->cbb, ins);
1624 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1625 cfg->flags |= MONO_CFG_HAS_FPOUT;
1628 g_assert_not_reached ();
1632 /* Emit the signature cookie in the case that there is no
1633 additional argument */
1634 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1635 emit_sig_cookie (cfg, call, cinfo);
1637 if (cinfo->struct_ret) {
1640 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1641 vtarg->sreg1 = call->vret_var->dreg;
1642 vtarg->dreg = mono_alloc_preg (cfg);
1643 MONO_ADD_INS (cfg->cbb, vtarg);
1645 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1648 call->stack_usage = cinfo->stack_usage;
1649 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1650 cfg->flags |= MONO_CFG_HAS_CALLS;
1658 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1660 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1661 ArgInfo *ainfo = ins->inst_p1;
1662 int ovf_size = ainfo->vtsize;
1663 int doffset = ainfo->offset;
1664 int i, soffset, dreg;
1666 if (ainfo->regtype == RegTypeStructByVal) {
1673 * Darwin pinvokes needs some special handling for 1
1674 * and 2 byte arguments
1676 g_assert (ins->klass);
1677 if (call->signature->pinvoke)
1678 size = mono_class_native_size (ins->klass, NULL);
1679 if (size == 2 || size == 1) {
1680 int tmpr = mono_alloc_ireg (cfg);
1682 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1684 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1685 dreg = mono_alloc_ireg (cfg);
1686 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1687 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1690 for (i = 0; i < ainfo->vtregs; ++i) {
1691 int antipadding = 0;
1694 antipadding = sizeof (gpointer) - ainfo->bytes;
1696 dreg = mono_alloc_ireg (cfg);
1697 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1699 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1700 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1701 soffset += sizeof (gpointer);
1704 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1705 } else if (ainfo->regtype == RegTypeFP) {
1706 int tmpr = mono_alloc_freg (cfg);
1707 if (ainfo->size == 4)
1708 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1710 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1711 dreg = mono_alloc_freg (cfg);
1712 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1713 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1715 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1719 /* FIXME: alignment? */
1720 if (call->signature->pinvoke) {
1721 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1722 vtcopy->backend.is_pinvoke = 1;
1724 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1727 g_assert (ovf_size > 0);
1729 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1730 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1733 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1735 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1740 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1742 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1743 mono_method_signature (method)->ret);
1746 #ifndef __mono_ppc64__
1747 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1750 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1751 ins->sreg1 = val->dreg + 1;
1752 ins->sreg2 = val->dreg + 2;
1753 MONO_ADD_INS (cfg->cbb, ins);
1757 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1758 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1762 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1765 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1767 mono_arch_is_inst_imm (gint64 imm)
1772 #endif /* DISABLE_JIT */
1775 * Allow tracing to work with this interface (with an optional argument)
1779 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1783 ppc_load_ptr (code, ppc_r3, cfg->method);
1784 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1785 ppc_load_func (code, ppc_r0, func);
1786 ppc_mtlr (code, ppc_r0);
1800 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1803 int save_mode = SAVE_NONE;
1805 MonoMethod *method = cfg->method;
1806 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1807 mono_method_signature (method)->ret)->type;
1808 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1812 offset = code - cfg->native_code;
1813 /* we need about 16 instructions */
1814 if (offset > (cfg->code_size - 16 * 4)) {
1815 cfg->code_size *= 2;
1816 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1817 code = cfg->native_code + offset;
1821 case MONO_TYPE_VOID:
1822 /* special case string .ctor icall */
1823 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1824 save_mode = SAVE_ONE;
1826 save_mode = SAVE_NONE;
1828 #ifndef __mono_ppc64__
1831 save_mode = SAVE_TWO;
1836 save_mode = SAVE_FP;
1838 case MONO_TYPE_VALUETYPE:
1839 save_mode = SAVE_STRUCT;
1842 save_mode = SAVE_ONE;
1846 switch (save_mode) {
1848 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1849 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1850 if (enable_arguments) {
1851 ppc_mr (code, ppc_r5, ppc_r4);
1852 ppc_mr (code, ppc_r4, ppc_r3);
1856 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1857 if (enable_arguments) {
1858 ppc_mr (code, ppc_r4, ppc_r3);
1862 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1863 if (enable_arguments) {
1864 /* FIXME: what reg? */
1865 ppc_fmr (code, ppc_f3, ppc_f1);
1866 /* FIXME: use 8 byte load on PPC64 */
1867 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1868 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1872 if (enable_arguments) {
1873 /* FIXME: get the actual address */
1874 ppc_mr (code, ppc_r4, ppc_r3);
1882 ppc_load_ptr (code, ppc_r3, cfg->method);
1883 ppc_load_func (code, ppc_r0, func);
1884 ppc_mtlr (code, ppc_r0);
1887 switch (save_mode) {
1889 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1890 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1893 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1896 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1906 * Conditional branches have a small offset, so if it is likely overflowed,
1907 * we do a branch to the end of the method (uncond branches have much larger
1908 * offsets) where we perform the conditional and jump back unconditionally.
1909 * It's slightly slower, since we add two uncond branches, but it's very simple
1910 * with the current patch implementation and such large methods are likely not
1911 * going to be perf critical anyway.
1916 const char *exception;
1923 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1924 if (0 && ins->inst_true_bb->native_offset) { \
1925 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1927 int br_disp = ins->inst_true_bb->max_offset - offset; \
1928 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1929 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1930 ovfj->data.bb = ins->inst_true_bb; \
1931 ovfj->ip_offset = 0; \
1932 ovfj->b0_cond = (b0); \
1933 ovfj->b1_cond = (b1); \
1934 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1937 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1938 ppc_bc (code, (b0), (b1), 0); \
1942 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1944 /* emit an exception if condition is fail
1946 * We assign the extra code used to throw the implicit exceptions
1947 * to cfg->bb_exit as far as the big branch handling is concerned
1949 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1951 int br_disp = cfg->bb_exit->max_offset - offset; \
1952 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1953 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1954 ovfj->data.exception = (exc_name); \
1955 ovfj->ip_offset = code - cfg->native_code; \
1956 ovfj->b0_cond = (b0); \
1957 ovfj->b1_cond = (b1); \
1958 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1960 cfg->bb_exit->max_offset += 24; \
1962 mono_add_patch_info (cfg, code - cfg->native_code, \
1963 MONO_PATCH_INFO_EXC, exc_name); \
1964 ppc_bcl (code, (b0), (b1), 0); \
1968 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1971 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1976 normalize_opcode (int opcode)
1979 #ifndef __mono_ilp32__
1980 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1981 return OP_LOAD_MEMBASE;
1982 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1983 return OP_LOAD_MEMINDEX;
1984 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1985 return OP_STORE_MEMBASE_REG;
1986 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1987 return OP_STORE_MEMBASE_IMM;
1988 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1989 return OP_STORE_MEMINDEX;
1991 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1993 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1994 return OP_SHR_UN_IMM;
2001 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2003 MonoInst *ins, *n, *last_ins = NULL;
2005 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2006 switch (normalize_opcode (ins->opcode)) {
2008 /* remove unnecessary multiplication with 1 */
2009 if (ins->inst_imm == 1) {
2010 if (ins->dreg != ins->sreg1) {
2011 ins->opcode = OP_MOVE;
2013 MONO_DELETE_INS (bb, ins);
2017 int power2 = mono_is_power_of_two (ins->inst_imm);
2019 ins->opcode = OP_SHL_IMM;
2020 ins->inst_imm = power2;
2024 case OP_LOAD_MEMBASE:
2026 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2027 * OP_LOAD_MEMBASE offset(basereg), reg
2029 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2030 ins->inst_basereg == last_ins->inst_destbasereg &&
2031 ins->inst_offset == last_ins->inst_offset) {
2032 if (ins->dreg == last_ins->sreg1) {
2033 MONO_DELETE_INS (bb, ins);
2036 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2037 ins->opcode = OP_MOVE;
2038 ins->sreg1 = last_ins->sreg1;
2042 * Note: reg1 must be different from the basereg in the second load
2043 * OP_LOAD_MEMBASE offset(basereg), reg1
2044 * OP_LOAD_MEMBASE offset(basereg), reg2
2046 * OP_LOAD_MEMBASE offset(basereg), reg1
2047 * OP_MOVE reg1, reg2
2049 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2050 ins->inst_basereg != last_ins->dreg &&
2051 ins->inst_basereg == last_ins->inst_basereg &&
2052 ins->inst_offset == last_ins->inst_offset) {
2054 if (ins->dreg == last_ins->dreg) {
2055 MONO_DELETE_INS (bb, ins);
2058 ins->opcode = OP_MOVE;
2059 ins->sreg1 = last_ins->dreg;
2062 //g_assert_not_reached ();
2066 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2067 * OP_LOAD_MEMBASE offset(basereg), reg
2069 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2070 * OP_ICONST reg, imm
2072 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2073 ins->inst_basereg == last_ins->inst_destbasereg &&
2074 ins->inst_offset == last_ins->inst_offset) {
2075 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2076 ins->opcode = OP_ICONST;
2077 ins->inst_c0 = last_ins->inst_imm;
2078 g_assert_not_reached (); // check this rule
2082 case OP_LOADU1_MEMBASE:
2083 case OP_LOADI1_MEMBASE:
2084 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2085 ins->inst_basereg == last_ins->inst_destbasereg &&
2086 ins->inst_offset == last_ins->inst_offset) {
2087 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2088 ins->sreg1 = last_ins->sreg1;
2091 case OP_LOADU2_MEMBASE:
2092 case OP_LOADI2_MEMBASE:
2093 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2094 ins->inst_basereg == last_ins->inst_destbasereg &&
2095 ins->inst_offset == last_ins->inst_offset) {
2096 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2097 ins->sreg1 = last_ins->sreg1;
2100 #ifdef __mono_ppc64__
2101 case OP_LOADU4_MEMBASE:
2102 case OP_LOADI4_MEMBASE:
2103 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2104 ins->inst_basereg == last_ins->inst_destbasereg &&
2105 ins->inst_offset == last_ins->inst_offset) {
2106 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2107 ins->sreg1 = last_ins->sreg1;
2112 ins->opcode = OP_MOVE;
2116 if (ins->dreg == ins->sreg1) {
2117 MONO_DELETE_INS (bb, ins);
2121 * OP_MOVE sreg, dreg
2122 * OP_MOVE dreg, sreg
2124 if (last_ins && last_ins->opcode == OP_MOVE &&
2125 ins->sreg1 == last_ins->dreg &&
2126 ins->dreg == last_ins->sreg1) {
2127 MONO_DELETE_INS (bb, ins);
2135 bb->last_ins = last_ins;
2139 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2141 switch (ins->opcode) {
2142 case OP_ICONV_TO_R_UN: {
2143 #if G_BYTE_ORDER == G_BIG_ENDIAN
2144 static const guint64 adjust_val = 0x4330000000000000ULL;
2146 static const guint64 adjust_val = 0x0000000000003043ULL;
2148 int msw_reg = mono_alloc_ireg (cfg);
2149 int adj_reg = mono_alloc_freg (cfg);
2150 int tmp_reg = mono_alloc_freg (cfg);
2151 int basereg = ppc_sp;
2153 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2154 if (!ppc_is_imm16 (offset + 4)) {
2155 basereg = mono_alloc_ireg (cfg);
2156 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2158 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2159 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2160 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2161 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2162 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2163 ins->opcode = OP_NOP;
2166 #ifndef __mono_ppc64__
2167 case OP_ICONV_TO_R4:
2168 case OP_ICONV_TO_R8: {
2169 /* If we have a PPC_FEATURE_64 machine we can avoid
2170 this and use the fcfid instruction. Otherwise
2171 on an old 32-bit chip and we have to do this the
2173 if (!(cpu_hw_caps & PPC_ISA_64)) {
2174 /* FIXME: change precision for CEE_CONV_R4 */
2175 static const guint64 adjust_val = 0x4330000080000000ULL;
2176 int msw_reg = mono_alloc_ireg (cfg);
2177 int xored = mono_alloc_ireg (cfg);
2178 int adj_reg = mono_alloc_freg (cfg);
2179 int tmp_reg = mono_alloc_freg (cfg);
2180 int basereg = ppc_sp;
2182 if (!ppc_is_imm16 (offset + 4)) {
2183 basereg = mono_alloc_ireg (cfg);
2184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2186 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2187 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2188 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2189 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2190 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2191 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2193 if (ins->opcode == OP_ICONV_TO_R4)
2194 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2195 ins->opcode = OP_NOP;
2201 int msw_reg = mono_alloc_ireg (cfg);
2202 int basereg = ppc_sp;
2204 if (!ppc_is_imm16 (offset + 4)) {
2205 basereg = mono_alloc_ireg (cfg);
2206 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2208 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2209 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2210 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2211 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2212 ins->opcode = OP_NOP;
2215 #ifdef __mono_ppc64__
2217 case OP_IADD_OVF_UN:
2219 int shifted1_reg = mono_alloc_ireg (cfg);
2220 int shifted2_reg = mono_alloc_ireg (cfg);
2221 int result_shifted_reg = mono_alloc_ireg (cfg);
2223 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2224 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2225 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2226 if (ins->opcode == OP_IADD_OVF_UN)
2227 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2229 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2230 ins->opcode = OP_NOP;
2237 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2239 switch (ins->opcode) {
2241 /* ADC sets the condition code */
2242 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2243 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2246 case OP_LADD_OVF_UN:
2247 /* ADC sets the condition code */
2248 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2249 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2253 /* SBB sets the condition code */
2254 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2255 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2258 case OP_LSUB_OVF_UN:
2259 /* SBB sets the condition code */
2260 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2265 /* From gcc generated code */
2266 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2267 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2276 * the branch_b0_table should maintain the order of these
2290 branch_b0_table [] = {
2305 branch_b1_table [] = {
2319 #define NEW_INS(cfg,dest,op) do { \
2320 MONO_INST_NEW((cfg), (dest), (op)); \
2321 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2325 map_to_reg_reg_op (int op)
2334 case OP_COMPARE_IMM:
2336 case OP_ICOMPARE_IMM:
2338 case OP_LCOMPARE_IMM:
2354 case OP_LOAD_MEMBASE:
2355 return OP_LOAD_MEMINDEX;
2356 case OP_LOADI4_MEMBASE:
2357 return OP_LOADI4_MEMINDEX;
2358 case OP_LOADU4_MEMBASE:
2359 return OP_LOADU4_MEMINDEX;
2360 case OP_LOADI8_MEMBASE:
2361 return OP_LOADI8_MEMINDEX;
2362 case OP_LOADU1_MEMBASE:
2363 return OP_LOADU1_MEMINDEX;
2364 case OP_LOADI2_MEMBASE:
2365 return OP_LOADI2_MEMINDEX;
2366 case OP_LOADU2_MEMBASE:
2367 return OP_LOADU2_MEMINDEX;
2368 case OP_LOADI1_MEMBASE:
2369 return OP_LOADI1_MEMINDEX;
2370 case OP_LOADR4_MEMBASE:
2371 return OP_LOADR4_MEMINDEX;
2372 case OP_LOADR8_MEMBASE:
2373 return OP_LOADR8_MEMINDEX;
2374 case OP_STOREI1_MEMBASE_REG:
2375 return OP_STOREI1_MEMINDEX;
2376 case OP_STOREI2_MEMBASE_REG:
2377 return OP_STOREI2_MEMINDEX;
2378 case OP_STOREI4_MEMBASE_REG:
2379 return OP_STOREI4_MEMINDEX;
2380 case OP_STOREI8_MEMBASE_REG:
2381 return OP_STOREI8_MEMINDEX;
2382 case OP_STORE_MEMBASE_REG:
2383 return OP_STORE_MEMINDEX;
2384 case OP_STORER4_MEMBASE_REG:
2385 return OP_STORER4_MEMINDEX;
2386 case OP_STORER8_MEMBASE_REG:
2387 return OP_STORER8_MEMINDEX;
2388 case OP_STORE_MEMBASE_IMM:
2389 return OP_STORE_MEMBASE_REG;
2390 case OP_STOREI1_MEMBASE_IMM:
2391 return OP_STOREI1_MEMBASE_REG;
2392 case OP_STOREI2_MEMBASE_IMM:
2393 return OP_STOREI2_MEMBASE_REG;
2394 case OP_STOREI4_MEMBASE_IMM:
2395 return OP_STOREI4_MEMBASE_REG;
2396 case OP_STOREI8_MEMBASE_IMM:
2397 return OP_STOREI8_MEMBASE_REG;
2399 return mono_op_imm_to_op (op);
2402 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2404 #define compare_opcode_is_unsigned(opcode) \
2405 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2406 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2407 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2408 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2409 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2410 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2411 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2412 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2415 * Remove from the instruction list the instructions that can't be
2416 * represented with very simple instructions with no register
2420 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2422 MonoInst *ins, *next, *temp, *last_ins = NULL;
2425 MONO_BB_FOR_EACH_INS (bb, ins) {
2427 switch (ins->opcode) {
2428 case OP_IDIV_UN_IMM:
2431 case OP_IREM_UN_IMM:
2432 NEW_INS (cfg, temp, OP_ICONST);
2433 temp->inst_c0 = ins->inst_imm;
2434 temp->dreg = mono_alloc_ireg (cfg);
2435 ins->sreg2 = temp->dreg;
2436 if (ins->opcode == OP_IDIV_IMM)
2437 ins->opcode = OP_IDIV;
2438 else if (ins->opcode == OP_IREM_IMM)
2439 ins->opcode = OP_IREM;
2440 else if (ins->opcode == OP_IDIV_UN_IMM)
2441 ins->opcode = OP_IDIV_UN;
2442 else if (ins->opcode == OP_IREM_UN_IMM)
2443 ins->opcode = OP_IREM_UN;
2445 /* handle rem separately */
2449 CASE_PPC64 (OP_LREM)
2450 CASE_PPC64 (OP_LREM_UN) {
2452 /* we change a rem dest, src1, src2 to
2453 * div temp1, src1, src2
2454 * mul temp2, temp1, src2
2455 * sub dest, src1, temp2
2457 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2458 NEW_INS (cfg, mul, OP_IMUL);
2459 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2460 ins->opcode = OP_ISUB;
2462 NEW_INS (cfg, mul, OP_LMUL);
2463 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2464 ins->opcode = OP_LSUB;
2466 temp->sreg1 = ins->sreg1;
2467 temp->sreg2 = ins->sreg2;
2468 temp->dreg = mono_alloc_ireg (cfg);
2469 mul->sreg1 = temp->dreg;
2470 mul->sreg2 = ins->sreg2;
2471 mul->dreg = mono_alloc_ireg (cfg);
2472 ins->sreg2 = mul->dreg;
2476 CASE_PPC64 (OP_LADD_IMM)
2479 if (!ppc_is_imm16 (ins->inst_imm)) {
2480 NEW_INS (cfg, temp, OP_ICONST);
2481 temp->inst_c0 = ins->inst_imm;
2482 temp->dreg = mono_alloc_ireg (cfg);
2483 ins->sreg2 = temp->dreg;
2484 ins->opcode = map_to_reg_reg_op (ins->opcode);
2488 CASE_PPC64 (OP_LSUB_IMM)
2490 if (!ppc_is_imm16 (-ins->inst_imm)) {
2491 NEW_INS (cfg, temp, OP_ICONST);
2492 temp->inst_c0 = ins->inst_imm;
2493 temp->dreg = mono_alloc_ireg (cfg);
2494 ins->sreg2 = temp->dreg;
2495 ins->opcode = map_to_reg_reg_op (ins->opcode);
2507 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2508 #ifdef __mono_ppc64__
2509 if (ins->inst_imm & 0xffffffff00000000ULL)
2513 NEW_INS (cfg, temp, OP_ICONST);
2514 temp->inst_c0 = ins->inst_imm;
2515 temp->dreg = mono_alloc_ireg (cfg);
2516 ins->sreg2 = temp->dreg;
2517 ins->opcode = map_to_reg_reg_op (ins->opcode);
2526 NEW_INS (cfg, temp, OP_ICONST);
2527 temp->inst_c0 = ins->inst_imm;
2528 temp->dreg = mono_alloc_ireg (cfg);
2529 ins->sreg2 = temp->dreg;
2530 ins->opcode = map_to_reg_reg_op (ins->opcode);
2532 case OP_COMPARE_IMM:
2533 case OP_ICOMPARE_IMM:
2534 CASE_PPC64 (OP_LCOMPARE_IMM)
2536 /* Branch opts can eliminate the branch */
2537 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2538 ins->opcode = OP_NOP;
2542 if (compare_opcode_is_unsigned (next->opcode)) {
2543 if (!ppc_is_uimm16 (ins->inst_imm)) {
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);
2551 if (!ppc_is_imm16 (ins->inst_imm)) {
2552 NEW_INS (cfg, temp, OP_ICONST);
2553 temp->inst_c0 = ins->inst_imm;
2554 temp->dreg = mono_alloc_ireg (cfg);
2555 ins->sreg2 = temp->dreg;
2556 ins->opcode = map_to_reg_reg_op (ins->opcode);
2562 if (ins->inst_imm == 1) {
2563 ins->opcode = OP_MOVE;
2566 if (ins->inst_imm == 0) {
2567 ins->opcode = OP_ICONST;
2571 imm = mono_is_power_of_two (ins->inst_imm);
2573 ins->opcode = OP_SHL_IMM;
2574 ins->inst_imm = imm;
2577 if (!ppc_is_imm16 (ins->inst_imm)) {
2578 NEW_INS (cfg, temp, OP_ICONST);
2579 temp->inst_c0 = ins->inst_imm;
2580 temp->dreg = mono_alloc_ireg (cfg);
2581 ins->sreg2 = temp->dreg;
2582 ins->opcode = map_to_reg_reg_op (ins->opcode);
2585 case OP_LOCALLOC_IMM:
2586 NEW_INS (cfg, temp, OP_ICONST);
2587 temp->inst_c0 = ins->inst_imm;
2588 temp->dreg = mono_alloc_ireg (cfg);
2589 ins->sreg1 = temp->dreg;
2590 ins->opcode = OP_LOCALLOC;
2592 case OP_LOAD_MEMBASE:
2593 case OP_LOADI4_MEMBASE:
2594 CASE_PPC64 (OP_LOADI8_MEMBASE)
2595 case OP_LOADU4_MEMBASE:
2596 case OP_LOADI2_MEMBASE:
2597 case OP_LOADU2_MEMBASE:
2598 case OP_LOADI1_MEMBASE:
2599 case OP_LOADU1_MEMBASE:
2600 case OP_LOADR4_MEMBASE:
2601 case OP_LOADR8_MEMBASE:
2602 case OP_STORE_MEMBASE_REG:
2603 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2604 case OP_STOREI4_MEMBASE_REG:
2605 case OP_STOREI2_MEMBASE_REG:
2606 case OP_STOREI1_MEMBASE_REG:
2607 case OP_STORER4_MEMBASE_REG:
2608 case OP_STORER8_MEMBASE_REG:
2609 /* we can do two things: load the immed in a register
2610 * and use an indexed load, or see if the immed can be
2611 * represented as an ad_imm + a load with a smaller offset
2612 * that fits. We just do the first for now, optimize later.
2614 if (ppc_is_imm16 (ins->inst_offset))
2616 NEW_INS (cfg, temp, OP_ICONST);
2617 temp->inst_c0 = ins->inst_offset;
2618 temp->dreg = mono_alloc_ireg (cfg);
2619 ins->sreg2 = temp->dreg;
2620 ins->opcode = map_to_reg_reg_op (ins->opcode);
2622 case OP_STORE_MEMBASE_IMM:
2623 case OP_STOREI1_MEMBASE_IMM:
2624 case OP_STOREI2_MEMBASE_IMM:
2625 case OP_STOREI4_MEMBASE_IMM:
2626 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2627 NEW_INS (cfg, temp, OP_ICONST);
2628 temp->inst_c0 = ins->inst_imm;
2629 temp->dreg = mono_alloc_ireg (cfg);
2630 ins->sreg1 = temp->dreg;
2631 ins->opcode = map_to_reg_reg_op (ins->opcode);
2633 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2636 if (cfg->compile_aot) {
2637 /* Keep these in the aot case */
2640 NEW_INS (cfg, temp, OP_ICONST);
2641 temp->inst_c0 = (gulong)ins->inst_p0;
2642 temp->dreg = mono_alloc_ireg (cfg);
2643 ins->inst_basereg = temp->dreg;
2644 ins->inst_offset = 0;
2645 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2647 /* make it handle the possibly big ins->inst_offset
2648 * later optimize to use lis + load_membase
2654 bb->last_ins = last_ins;
2655 bb->max_vreg = cfg->next_vreg;
2659 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2661 long offset = cfg->arch.fp_conv_var_offset;
2663 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2664 #ifdef __mono_ppc64__
2666 ppc_fctidz (code, ppc_f0, sreg);
2671 ppc_fctiwz (code, ppc_f0, sreg);
2674 if (ppc_is_imm16 (offset + sub_offset)) {
2675 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2677 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2679 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2681 ppc_load (code, dreg, offset);
2682 ppc_add (code, dreg, dreg, cfg->frame_reg);
2683 ppc_stfd (code, ppc_f0, 0, dreg);
2685 ppc_ldr (code, dreg, sub_offset, dreg);
2687 ppc_lwz (code, dreg, sub_offset, dreg);
2691 ppc_andid (code, dreg, dreg, 0xff);
2693 ppc_andid (code, dreg, dreg, 0xffff);
2694 #ifdef __mono_ppc64__
2696 ppc_clrldi (code, dreg, dreg, 32);
2700 ppc_extsb (code, dreg, dreg);
2702 ppc_extsh (code, dreg, dreg);
2703 #ifdef __mono_ppc64__
2705 ppc_extsw (code, dreg, dreg);
2713 const guchar *target;
2718 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2721 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2722 #ifdef __mono_ppc64__
2723 g_assert_not_reached ();
2725 PatchData *pdata = (PatchData*)user_data;
2726 guchar *code = data;
2727 guint32 *thunks = data;
2728 guint32 *endthunks = (guint32*)(code + bsize);
2732 int difflow, diffhigh;
2734 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2735 difflow = (char*)pdata->code - (char*)thunks;
2736 diffhigh = (char*)pdata->code - (char*)endthunks;
2737 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2740 templ = (guchar*)load;
2741 ppc_load_sequence (templ, ppc_r0, pdata->target);
2743 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2744 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2745 while (thunks < endthunks) {
2746 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2747 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2748 ppc_patch (pdata->code, (guchar*)thunks);
2751 static int num_thunks = 0;
2753 if ((num_thunks % 20) == 0)
2754 g_print ("num_thunks lookup: %d\n", num_thunks);
2757 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2758 /* found a free slot instead: emit thunk */
2759 code = (guchar*)thunks;
2760 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2761 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2762 ppc_mtctr (code, ppc_r0);
2763 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2764 mono_arch_flush_icache ((guchar*)thunks, 16);
2766 ppc_patch (pdata->code, (guchar*)thunks);
2769 static int num_thunks = 0;
2771 if ((num_thunks % 20) == 0)
2772 g_print ("num_thunks: %d\n", num_thunks);
2776 /* skip 16 bytes, the size of the thunk */
2780 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2787 handle_thunk (int absolute, guchar *code, const guchar *target) {
2788 MonoDomain *domain = mono_domain_get ();
2792 pdata.target = target;
2793 pdata.absolute = absolute;
2796 mono_domain_lock (domain);
2797 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2800 /* this uses the first available slot */
2802 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2804 mono_domain_unlock (domain);
2806 if (pdata.found != 1)
2807 g_print ("thunk failed for %p from %p\n", target, code);
2808 g_assert (pdata.found == 1);
2812 patch_ins (guint8 *code, guint32 ins)
2814 *(guint32*)code = GUINT32_TO_BE (ins);
2815 mono_arch_flush_icache (code, 4);
2819 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2821 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2822 guint32 prim = ins >> 26;
2825 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2827 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2828 gint diff = target - code;
2831 if (diff <= 33554431){
2832 ins = (18 << 26) | (diff) | (ins & 1);
2833 patch_ins (code, ins);
2837 /* diff between 0 and -33554432 */
2838 if (diff >= -33554432){
2839 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2840 patch_ins (code, ins);
2845 if ((glong)target >= 0){
2846 if ((glong)target <= 33554431){
2847 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2848 patch_ins (code, ins);
2852 if ((glong)target >= -33554432){
2853 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2854 patch_ins (code, ins);
2859 handle_thunk (TRUE, code, target);
2862 g_assert_not_reached ();
2870 guint32 li = (gulong)target;
2871 ins = (ins & 0xffff0000) | (ins & 3);
2872 ovf = li & 0xffff0000;
2873 if (ovf != 0 && ovf != 0xffff0000)
2874 g_assert_not_reached ();
2877 // FIXME: assert the top bits of li are 0
2879 gint diff = target - code;
2880 ins = (ins & 0xffff0000) | (ins & 3);
2881 ovf = diff & 0xffff0000;
2882 if (ovf != 0 && ovf != 0xffff0000)
2883 g_assert_not_reached ();
2887 patch_ins (code, ins);
2891 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2892 #ifdef __mono_ppc64__
2893 guint32 *seq = (guint32*)code;
2894 guint32 *branch_ins;
2896 /* the trampoline code will try to patch the blrl, blr, bcctr */
2897 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2899 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2904 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2905 branch_ins = seq + 8;
2907 branch_ins = seq + 6;
2910 seq = (guint32*)code;
2911 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2912 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2914 if (ppc_is_load_op (seq [5])) {
2915 g_assert (ppc_is_load_op (seq [6]));
2918 guint8 *buf = (guint8*)&seq [5];
2919 ppc_mr (buf, ppc_r0, ppc_r11);
2924 target = mono_get_addr_from_ftnptr ((gpointer)target);
2927 /* FIXME: make this thread safe */
2928 /* FIXME: we're assuming we're using r11 here */
2929 ppc_load_ptr_sequence (code, ppc_r11, target);
2930 mono_arch_flush_icache ((guint8*)seq, 28);
2933 /* the trampoline code will try to patch the blrl, blr, bcctr */
2934 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2937 /* this is the lis/ori/mtlr/blrl sequence */
2938 seq = (guint32*)code;
2939 g_assert ((seq [0] >> 26) == 15);
2940 g_assert ((seq [1] >> 26) == 24);
2941 g_assert ((seq [2] >> 26) == 31);
2942 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2943 /* FIXME: make this thread safe */
2944 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2945 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2946 mono_arch_flush_icache (code - 8, 8);
2949 g_assert_not_reached ();
2951 // g_print ("patched with 0x%08x\n", ins);
2955 ppc_patch (guchar *code, const guchar *target)
2957 ppc_patch_full (code, target, FALSE);
2961 mono_ppc_patch (guchar *code, const guchar *target)
2963 ppc_patch (code, target);
2967 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2969 switch (ins->opcode) {
2972 case OP_FCALL_MEMBASE:
2973 if (ins->dreg != ppc_f1)
2974 ppc_fmr (code, ins->dreg, ppc_f1);
2982 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2984 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2988 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2990 long size = cfg->param_area;
2992 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2993 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2998 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
2999 if (ppc_is_imm16 (-size)) {
3000 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3002 ppc_load (code, ppc_r11, -size);
3003 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3010 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3012 long size = cfg->param_area;
3014 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3015 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3020 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3021 if (ppc_is_imm16 (size)) {
3022 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3024 ppc_load (code, ppc_r11, size);
3025 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3031 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3035 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3037 MonoInst *ins, *next;
3040 guint8 *code = cfg->native_code + cfg->code_len;
3041 MonoInst *last_ins = NULL;
3042 guint last_offset = 0;
3046 /* we don't align basic blocks of loops on ppc */
3048 if (cfg->verbose_level > 2)
3049 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3051 cpos = bb->max_offset;
3053 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3054 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3055 //g_assert (!mono_compile_aot);
3058 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3059 /* this is not thread save, but good enough */
3060 /* fixme: howto handle overflows? */
3061 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3064 MONO_BB_FOR_EACH_INS (bb, ins) {
3065 offset = code - cfg->native_code;
3067 max_len = ins_native_length (cfg, ins);
3069 if (offset > (cfg->code_size - max_len - 16)) {
3070 cfg->code_size *= 2;
3071 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3072 code = cfg->native_code + offset;
3074 // if (ins->cil_code)
3075 // g_print ("cil code\n");
3076 mono_debug_record_line_number (cfg, ins, offset);
3078 switch (normalize_opcode (ins->opcode)) {
3079 case OP_RELAXED_NOP:
3082 case OP_DUMMY_STORE:
3083 case OP_NOT_REACHED:
3086 case OP_SEQ_POINT: {
3089 if (cfg->compile_aot)
3093 * Read from the single stepping trigger page. This will cause a
3094 * SIGSEGV when single stepping is enabled.
3095 * We do this _before_ the breakpoint, so single stepping after
3096 * a breakpoint is hit will step to the next IL offset.
3098 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3099 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3100 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3103 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3106 * A placeholder for a possible breakpoint inserted by
3107 * mono_arch_set_breakpoint ().
3109 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3114 emit_tls_access (code, ins->dreg, ins->inst_offset);
3117 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3118 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3119 ppc_mr (code, ppc_r4, ppc_r0);
3122 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3123 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3124 ppc_mr (code, ppc_r4, ppc_r0);
3126 case OP_MEMORY_BARRIER:
3129 case OP_STOREI1_MEMBASE_REG:
3130 if (ppc_is_imm16 (ins->inst_offset)) {
3131 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3133 if (ppc_is_imm32 (ins->inst_offset)) {
3134 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3135 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3137 ppc_load (code, ppc_r0, ins->inst_offset);
3138 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3142 case OP_STOREI2_MEMBASE_REG:
3143 if (ppc_is_imm16 (ins->inst_offset)) {
3144 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3146 if (ppc_is_imm32 (ins->inst_offset)) {
3147 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3148 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3150 ppc_load (code, ppc_r0, ins->inst_offset);
3151 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3155 case OP_STORE_MEMBASE_REG:
3156 if (ppc_is_imm16 (ins->inst_offset)) {
3157 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3159 if (ppc_is_imm32 (ins->inst_offset)) {
3160 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3161 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3163 ppc_load (code, ppc_r0, ins->inst_offset);
3164 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3168 #ifdef __mono_ilp32__
3169 case OP_STOREI8_MEMBASE_REG:
3170 if (ppc_is_imm16 (ins->inst_offset)) {
3171 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3173 ppc_load (code, ppc_r0, ins->inst_offset);
3174 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3178 case OP_STOREI1_MEMINDEX:
3179 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3181 case OP_STOREI2_MEMINDEX:
3182 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3184 case OP_STORE_MEMINDEX:
3185 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3188 g_assert_not_reached ();
3190 case OP_LOAD_MEMBASE:
3191 if (ppc_is_imm16 (ins->inst_offset)) {
3192 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3194 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3195 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3196 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3198 ppc_load (code, ppc_r0, ins->inst_offset);
3199 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3203 case OP_LOADI4_MEMBASE:
3204 #ifdef __mono_ppc64__
3205 if (ppc_is_imm16 (ins->inst_offset)) {
3206 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3208 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3209 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3210 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3212 ppc_load (code, ppc_r0, ins->inst_offset);
3213 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3218 case OP_LOADU4_MEMBASE:
3219 if (ppc_is_imm16 (ins->inst_offset)) {
3220 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3222 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3223 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3224 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3226 ppc_load (code, ppc_r0, ins->inst_offset);
3227 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3231 case OP_LOADI1_MEMBASE:
3232 case OP_LOADU1_MEMBASE:
3233 if (ppc_is_imm16 (ins->inst_offset)) {
3234 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3236 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3237 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3238 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3240 ppc_load (code, ppc_r0, ins->inst_offset);
3241 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3244 if (ins->opcode == OP_LOADI1_MEMBASE)
3245 ppc_extsb (code, ins->dreg, ins->dreg);
3247 case OP_LOADU2_MEMBASE:
3248 if (ppc_is_imm16 (ins->inst_offset)) {
3249 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3251 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3252 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3253 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3255 ppc_load (code, ppc_r0, ins->inst_offset);
3256 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3260 case OP_LOADI2_MEMBASE:
3261 if (ppc_is_imm16 (ins->inst_offset)) {
3262 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3264 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3265 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3266 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3268 ppc_load (code, ppc_r0, ins->inst_offset);
3269 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3273 #ifdef __mono_ilp32__
3274 case OP_LOADI8_MEMBASE:
3275 if (ppc_is_imm16 (ins->inst_offset)) {
3276 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3278 ppc_load (code, ppc_r0, ins->inst_offset);
3279 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3283 case OP_LOAD_MEMINDEX:
3284 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3286 case OP_LOADI4_MEMINDEX:
3287 #ifdef __mono_ppc64__
3288 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3291 case OP_LOADU4_MEMINDEX:
3292 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3294 case OP_LOADU2_MEMINDEX:
3295 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3297 case OP_LOADI2_MEMINDEX:
3298 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3300 case OP_LOADU1_MEMINDEX:
3301 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3303 case OP_LOADI1_MEMINDEX:
3304 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3305 ppc_extsb (code, ins->dreg, ins->dreg);
3307 case OP_ICONV_TO_I1:
3308 CASE_PPC64 (OP_LCONV_TO_I1)
3309 ppc_extsb (code, ins->dreg, ins->sreg1);
3311 case OP_ICONV_TO_I2:
3312 CASE_PPC64 (OP_LCONV_TO_I2)
3313 ppc_extsh (code, ins->dreg, ins->sreg1);
3315 case OP_ICONV_TO_U1:
3316 CASE_PPC64 (OP_LCONV_TO_U1)
3317 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3319 case OP_ICONV_TO_U2:
3320 CASE_PPC64 (OP_LCONV_TO_U2)
3321 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3325 CASE_PPC64 (OP_LCOMPARE)
3326 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3328 if (next && compare_opcode_is_unsigned (next->opcode))
3329 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3331 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3333 case OP_COMPARE_IMM:
3334 case OP_ICOMPARE_IMM:
3335 CASE_PPC64 (OP_LCOMPARE_IMM)
3336 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3338 if (next && compare_opcode_is_unsigned (next->opcode)) {
3339 if (ppc_is_uimm16 (ins->inst_imm)) {
3340 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3342 g_assert_not_reached ();
3345 if (ppc_is_imm16 (ins->inst_imm)) {
3346 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3348 g_assert_not_reached ();
3354 * gdb does not like encountering a trap in the debugged code. So
3355 * instead of emitting a trap, we emit a call a C function and place a
3359 ppc_mr (code, ppc_r3, ins->sreg1);
3360 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3361 (gpointer)"mono_break");
3362 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3363 ppc_load_func (code, ppc_r0, 0);
3364 ppc_mtlr (code, ppc_r0);
3372 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3375 CASE_PPC64 (OP_LADD)
3376 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3380 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3383 if (ppc_is_imm16 (ins->inst_imm)) {
3384 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3386 g_assert_not_reached ();
3391 CASE_PPC64 (OP_LADD_IMM)
3392 if (ppc_is_imm16 (ins->inst_imm)) {
3393 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3395 g_assert_not_reached ();
3399 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3401 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3402 ppc_mfspr (code, ppc_r0, ppc_xer);
3403 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3404 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3406 case OP_IADD_OVF_UN:
3407 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3409 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3410 ppc_mfspr (code, ppc_r0, ppc_xer);
3411 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3412 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3415 CASE_PPC64 (OP_LSUB_OVF)
3416 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3418 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3419 ppc_mfspr (code, ppc_r0, ppc_xer);
3420 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3421 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3423 case OP_ISUB_OVF_UN:
3424 CASE_PPC64 (OP_LSUB_OVF_UN)
3425 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3427 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3428 ppc_mfspr (code, ppc_r0, ppc_xer);
3429 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3430 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3432 case OP_ADD_OVF_CARRY:
3433 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3435 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3436 ppc_mfspr (code, ppc_r0, ppc_xer);
3437 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3438 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3440 case OP_ADD_OVF_UN_CARRY:
3441 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3443 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3444 ppc_mfspr (code, ppc_r0, ppc_xer);
3445 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3446 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3448 case OP_SUB_OVF_CARRY:
3449 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3451 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3452 ppc_mfspr (code, ppc_r0, ppc_xer);
3453 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3454 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3456 case OP_SUB_OVF_UN_CARRY:
3457 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3459 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3460 ppc_mfspr (code, ppc_r0, ppc_xer);
3461 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3462 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3466 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3469 CASE_PPC64 (OP_LSUB)
3470 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3474 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3478 CASE_PPC64 (OP_LSUB_IMM)
3479 // we add the negated value
3480 if (ppc_is_imm16 (-ins->inst_imm))
3481 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3483 g_assert_not_reached ();
3487 g_assert (ppc_is_imm16 (ins->inst_imm));
3488 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3491 ppc_subfze (code, ins->dreg, ins->sreg1);
3494 CASE_PPC64 (OP_LAND)
3495 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3496 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3500 CASE_PPC64 (OP_LAND_IMM)
3501 if (!(ins->inst_imm & 0xffff0000)) {
3502 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3503 } else if (!(ins->inst_imm & 0xffff)) {
3504 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3506 g_assert_not_reached ();
3510 CASE_PPC64 (OP_LDIV) {
3511 guint8 *divisor_is_m1;
3512 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3514 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3515 divisor_is_m1 = code;
3516 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3517 ppc_lis (code, ppc_r0, 0x8000);
3518 #ifdef __mono_ppc64__
3519 if (ins->opcode == OP_LDIV)
3520 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3522 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3523 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3524 ppc_patch (divisor_is_m1, code);
3525 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3527 if (ins->opcode == OP_IDIV)
3528 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3529 #ifdef __mono_ppc64__
3531 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3533 ppc_mfspr (code, ppc_r0, ppc_xer);
3534 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3535 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3539 CASE_PPC64 (OP_LDIV_UN)
3540 if (ins->opcode == OP_IDIV_UN)
3541 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3542 #ifdef __mono_ppc64__
3544 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3546 ppc_mfspr (code, ppc_r0, ppc_xer);
3547 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3548 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3554 g_assert_not_reached ();
3557 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3561 CASE_PPC64 (OP_LOR_IMM)
3562 if (!(ins->inst_imm & 0xffff0000)) {
3563 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3564 } else if (!(ins->inst_imm & 0xffff)) {
3565 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3567 g_assert_not_reached ();
3571 CASE_PPC64 (OP_LXOR)
3572 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3576 CASE_PPC64 (OP_LXOR_IMM)
3577 if (!(ins->inst_imm & 0xffff0000)) {
3578 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3579 } else if (!(ins->inst_imm & 0xffff)) {
3580 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3582 g_assert_not_reached ();
3586 CASE_PPC64 (OP_LSHL)
3587 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3591 CASE_PPC64 (OP_LSHL_IMM)
3592 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3595 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3598 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3601 if (MASK_SHIFT_IMM (ins->inst_imm))
3602 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3604 ppc_mr (code, ins->dreg, ins->sreg1);
3607 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3610 CASE_PPC64 (OP_LNOT)
3611 ppc_not (code, ins->dreg, ins->sreg1);
3614 CASE_PPC64 (OP_LNEG)
3615 ppc_neg (code, ins->dreg, ins->sreg1);
3618 CASE_PPC64 (OP_LMUL)
3619 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3623 CASE_PPC64 (OP_LMUL_IMM)
3624 if (ppc_is_imm16 (ins->inst_imm)) {
3625 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3627 g_assert_not_reached ();
3631 CASE_PPC64 (OP_LMUL_OVF)
3632 /* we annot use mcrxr, since it's not implemented on some processors
3633 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3635 if (ins->opcode == OP_IMUL_OVF)
3636 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 #ifdef __mono_ppc64__
3639 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3641 ppc_mfspr (code, ppc_r0, ppc_xer);
3642 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3643 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3645 case OP_IMUL_OVF_UN:
3646 CASE_PPC64 (OP_LMUL_OVF_UN)
3647 /* we first multiply to get the high word and compare to 0
3648 * to set the flags, then the result is discarded and then
3649 * we multiply to get the lower * bits result
3651 if (ins->opcode == OP_IMUL_OVF_UN)
3652 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3653 #ifdef __mono_ppc64__
3655 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3657 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3658 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3659 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3662 ppc_load (code, ins->dreg, ins->inst_c0);
3665 ppc_load (code, ins->dreg, ins->inst_l);
3668 case OP_LOAD_GOTADDR:
3669 /* The PLT implementation depends on this */
3670 g_assert (ins->dreg == ppc_r30);
3672 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3675 // FIXME: Fix max instruction length
3676 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3677 /* arch_emit_got_access () patches this */
3678 ppc_load32 (code, ppc_r0, 0);
3679 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3682 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3683 ppc_load_sequence (code, ins->dreg, 0);
3685 CASE_PPC32 (OP_ICONV_TO_I4)
3686 CASE_PPC32 (OP_ICONV_TO_U4)
3688 ppc_mr (code, ins->dreg, ins->sreg1);
3691 int saved = ins->sreg1;
3692 if (ins->sreg1 == ppc_r3) {
3693 ppc_mr (code, ppc_r0, ins->sreg1);
3696 if (ins->sreg2 != ppc_r3)
3697 ppc_mr (code, ppc_r3, ins->sreg2);
3698 if (saved != ppc_r4)
3699 ppc_mr (code, ppc_r4, saved);
3703 ppc_fmr (code, ins->dreg, ins->sreg1);
3705 case OP_FCONV_TO_R4:
3706 ppc_frsp (code, ins->dreg, ins->sreg1);
3710 MonoCallInst *call = (MonoCallInst*)ins;
3713 * Keep in sync with mono_arch_emit_epilog
3715 g_assert (!cfg->method->save_lmf);
3717 * Note: we can use ppc_r11 here because it is dead anyway:
3718 * we're leaving the method.
3720 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3721 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3722 if (ppc_is_imm16 (ret_offset)) {
3723 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3725 ppc_load (code, ppc_r11, ret_offset);
3726 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3728 ppc_mtlr (code, ppc_r0);
3731 if (ppc_is_imm16 (cfg->stack_usage)) {
3732 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3734 /* cfg->stack_usage is an int, so we can use
3735 * an addis/addi sequence here even in 64-bit. */
3736 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3737 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3739 if (!cfg->method->save_lmf) {
3741 for (i = 31; i >= 13; --i) {
3742 if (cfg->used_int_regs & (1 << i)) {
3743 pos += sizeof (gpointer);
3744 ppc_ldptr (code, i, -pos, ppc_r11);
3748 /* FIXME restore from MonoLMF: though this can't happen yet */
3751 /* Copy arguments on the stack to our argument area */
3752 if (call->stack_usage) {
3753 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3754 /* r11 was clobbered */
3755 g_assert (cfg->frame_reg == ppc_sp);
3756 if (ppc_is_imm16 (cfg->stack_usage)) {
3757 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3759 /* cfg->stack_usage is an int, so we can use
3760 * an addis/addi sequence here even in 64-bit. */
3761 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3762 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3766 ppc_mr (code, ppc_sp, ppc_r11);
3767 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3768 if (cfg->compile_aot) {
3769 /* arch_emit_got_access () patches this */
3770 ppc_load32 (code, ppc_r0, 0);
3771 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3772 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3773 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3775 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3777 ppc_mtctr (code, ppc_r0);
3778 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3785 /* ensure ins->sreg1 is not NULL */
3786 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3789 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3790 if (ppc_is_imm16 (cookie_offset)) {
3791 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3793 ppc_load (code, ppc_r0, cookie_offset);
3794 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3796 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3805 call = (MonoCallInst*)ins;
3806 if (ins->flags & MONO_INST_HAS_METHOD)
3807 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3809 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3810 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3811 ppc_load_func (code, ppc_r0, 0);
3812 ppc_mtlr (code, ppc_r0);
3817 /* FIXME: this should be handled somewhere else in the new jit */
3818 code = emit_move_return_value (cfg, ins, code);
3824 case OP_VOIDCALL_REG:
3826 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3827 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3828 /* FIXME: if we know that this is a method, we
3829 can omit this load */
3830 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3831 ppc_mtlr (code, ppc_r0);
3833 ppc_mtlr (code, ins->sreg1);
3836 /* FIXME: this should be handled somewhere else in the new jit */
3837 code = emit_move_return_value (cfg, ins, code);
3839 case OP_FCALL_MEMBASE:
3840 case OP_LCALL_MEMBASE:
3841 case OP_VCALL_MEMBASE:
3842 case OP_VCALL2_MEMBASE:
3843 case OP_VOIDCALL_MEMBASE:
3844 case OP_CALL_MEMBASE:
3845 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3846 /* The trampolines clobber this */
3847 ppc_mr (code, ppc_r29, ins->sreg1);
3848 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3850 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3852 ppc_mtlr (code, ppc_r0);
3854 /* FIXME: this should be handled somewhere else in the new jit */
3855 code = emit_move_return_value (cfg, ins, code);
3858 guint8 * zero_loop_jump, * zero_loop_start;
3859 /* keep alignment */
3860 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3861 int area_offset = alloca_waste;
3863 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3864 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3865 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3866 /* use ctr to store the number of words to 0 if needed */
3867 if (ins->flags & MONO_INST_INIT) {
3868 /* we zero 4 bytes at a time:
3869 * we add 7 instead of 3 so that we set the counter to
3870 * at least 1, otherwise the bdnz instruction will make
3871 * it negative and iterate billions of times.
3873 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3874 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3875 ppc_mtctr (code, ppc_r0);
3877 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3878 ppc_neg (code, ppc_r11, ppc_r11);
3879 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3881 /* FIXME: make this loop work in 8 byte
3882 increments on PPC64 */
3883 if (ins->flags & MONO_INST_INIT) {
3884 /* adjust the dest reg by -4 so we can use stwu */
3885 /* we actually adjust -8 because we let the loop
3888 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3889 ppc_li (code, ppc_r11, 0);
3890 zero_loop_start = code;
3891 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3892 zero_loop_jump = code;
3893 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3894 ppc_patch (zero_loop_jump, zero_loop_start);
3896 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3901 ppc_mr (code, ppc_r3, ins->sreg1);
3902 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3903 (gpointer)"mono_arch_throw_exception");
3904 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3905 ppc_load_func (code, ppc_r0, 0);
3906 ppc_mtlr (code, ppc_r0);
3915 ppc_mr (code, ppc_r3, ins->sreg1);
3916 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3917 (gpointer)"mono_arch_rethrow_exception");
3918 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3919 ppc_load_func (code, ppc_r0, 0);
3920 ppc_mtlr (code, ppc_r0);
3927 case OP_START_HANDLER: {
3928 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3929 g_assert (spvar->inst_basereg != ppc_sp);
3930 code = emit_reserve_param_area (cfg, code);
3931 ppc_mflr (code, ppc_r0);
3932 if (ppc_is_imm16 (spvar->inst_offset)) {
3933 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3935 ppc_load (code, ppc_r11, spvar->inst_offset);
3936 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3940 case OP_ENDFILTER: {
3941 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3942 g_assert (spvar->inst_basereg != ppc_sp);
3943 code = emit_unreserve_param_area (cfg, code);
3944 if (ins->sreg1 != ppc_r3)
3945 ppc_mr (code, ppc_r3, ins->sreg1);
3946 if (ppc_is_imm16 (spvar->inst_offset)) {
3947 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3949 ppc_load (code, ppc_r11, spvar->inst_offset);
3950 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3952 ppc_mtlr (code, ppc_r0);
3956 case OP_ENDFINALLY: {
3957 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3958 g_assert (spvar->inst_basereg != ppc_sp);
3959 code = emit_unreserve_param_area (cfg, code);
3960 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3961 ppc_mtlr (code, ppc_r0);
3965 case OP_CALL_HANDLER:
3966 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3968 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3971 ins->inst_c0 = code - cfg->native_code;
3974 /*if (ins->inst_target_bb->native_offset) {
3976 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3978 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3983 ppc_mtctr (code, ins->sreg1);
3984 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3988 CASE_PPC64 (OP_LCEQ)
3989 ppc_li (code, ins->dreg, 0);
3990 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3991 ppc_li (code, ins->dreg, 1);
3997 CASE_PPC64 (OP_LCLT)
3998 CASE_PPC64 (OP_LCLT_UN)
3999 ppc_li (code, ins->dreg, 1);
4000 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4001 ppc_li (code, ins->dreg, 0);
4007 CASE_PPC64 (OP_LCGT)
4008 CASE_PPC64 (OP_LCGT_UN)
4009 ppc_li (code, ins->dreg, 1);
4010 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4011 ppc_li (code, ins->dreg, 0);
4013 case OP_COND_EXC_EQ:
4014 case OP_COND_EXC_NE_UN:
4015 case OP_COND_EXC_LT:
4016 case OP_COND_EXC_LT_UN:
4017 case OP_COND_EXC_GT:
4018 case OP_COND_EXC_GT_UN:
4019 case OP_COND_EXC_GE:
4020 case OP_COND_EXC_GE_UN:
4021 case OP_COND_EXC_LE:
4022 case OP_COND_EXC_LE_UN:
4023 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4025 case OP_COND_EXC_IEQ:
4026 case OP_COND_EXC_INE_UN:
4027 case OP_COND_EXC_ILT:
4028 case OP_COND_EXC_ILT_UN:
4029 case OP_COND_EXC_IGT:
4030 case OP_COND_EXC_IGT_UN:
4031 case OP_COND_EXC_IGE:
4032 case OP_COND_EXC_IGE_UN:
4033 case OP_COND_EXC_ILE:
4034 case OP_COND_EXC_ILE_UN:
4035 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4047 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4050 /* floating point opcodes */
4052 g_assert (cfg->compile_aot);
4054 /* FIXME: Optimize this */
4056 ppc_mflr (code, ppc_r11);
4058 *(double*)code = *(double*)ins->inst_p0;
4060 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4063 g_assert_not_reached ();
4065 case OP_STORER8_MEMBASE_REG:
4066 if (ppc_is_imm16 (ins->inst_offset)) {
4067 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4069 if (ppc_is_imm32 (ins->inst_offset)) {
4070 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4071 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4073 ppc_load (code, ppc_r0, ins->inst_offset);
4074 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4078 case OP_LOADR8_MEMBASE:
4079 if (ppc_is_imm16 (ins->inst_offset)) {
4080 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4082 if (ppc_is_imm32 (ins->inst_offset)) {
4083 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4084 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4086 ppc_load (code, ppc_r0, ins->inst_offset);
4087 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4091 case OP_STORER4_MEMBASE_REG:
4092 ppc_frsp (code, ins->sreg1, ins->sreg1);
4093 if (ppc_is_imm16 (ins->inst_offset)) {
4094 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4096 if (ppc_is_imm32 (ins->inst_offset)) {
4097 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4098 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4100 ppc_load (code, ppc_r0, ins->inst_offset);
4101 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4105 case OP_LOADR4_MEMBASE:
4106 if (ppc_is_imm16 (ins->inst_offset)) {
4107 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4109 if (ppc_is_imm32 (ins->inst_offset)) {
4110 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4111 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4113 ppc_load (code, ppc_r0, ins->inst_offset);
4114 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4118 case OP_LOADR4_MEMINDEX:
4119 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4121 case OP_LOADR8_MEMINDEX:
4122 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4124 case OP_STORER4_MEMINDEX:
4125 ppc_frsp (code, ins->sreg1, ins->sreg1);
4126 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4128 case OP_STORER8_MEMINDEX:
4129 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4132 case CEE_CONV_R4: /* FIXME: change precision */
4134 g_assert_not_reached ();
4135 case OP_FCONV_TO_I1:
4136 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4138 case OP_FCONV_TO_U1:
4139 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4141 case OP_FCONV_TO_I2:
4142 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4144 case OP_FCONV_TO_U2:
4145 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4147 case OP_FCONV_TO_I4:
4149 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4151 case OP_FCONV_TO_U4:
4153 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4155 case OP_LCONV_TO_R_UN:
4156 g_assert_not_reached ();
4157 /* Implemented as helper calls */
4159 case OP_LCONV_TO_OVF_I4_2:
4160 case OP_LCONV_TO_OVF_I: {
4161 #ifdef __mono_ppc64__
4164 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4165 // Check if its negative
4166 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4167 negative_branch = code;
4168 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4169 // Its positive msword == 0
4170 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4171 msword_positive_branch = code;
4172 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4174 ovf_ex_target = code;
4175 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4177 ppc_patch (negative_branch, code);
4178 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4179 msword_negative_branch = code;
4180 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4181 ppc_patch (msword_negative_branch, ovf_ex_target);
4183 ppc_patch (msword_positive_branch, code);
4184 if (ins->dreg != ins->sreg1)
4185 ppc_mr (code, ins->dreg, ins->sreg1);
4190 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4193 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4196 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4199 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4202 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4205 ppc_fneg (code, ins->dreg, ins->sreg1);
4209 g_assert_not_reached ();
4212 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4215 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4216 ppc_li (code, ins->dreg, 0);
4217 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4218 ppc_li (code, ins->dreg, 1);
4221 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4222 ppc_li (code, ins->dreg, 1);
4223 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4224 ppc_li (code, ins->dreg, 0);
4227 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4228 ppc_li (code, ins->dreg, 1);
4229 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4230 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4231 ppc_li (code, ins->dreg, 0);
4234 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4235 ppc_li (code, ins->dreg, 1);
4236 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4237 ppc_li (code, ins->dreg, 0);
4240 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4241 ppc_li (code, ins->dreg, 1);
4242 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4243 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4244 ppc_li (code, ins->dreg, 0);
4247 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4250 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4253 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4254 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4257 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4258 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4261 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4262 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4265 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4266 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4269 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4270 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4273 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4276 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4277 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4280 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4283 g_assert_not_reached ();
4284 case OP_CHECK_FINITE: {
4285 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4286 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4287 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4288 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4291 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4292 #ifdef __mono_ppc64__
4293 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4295 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4300 #ifdef __mono_ppc64__
4301 case OP_ICONV_TO_I4:
4303 ppc_extsw (code, ins->dreg, ins->sreg1);
4305 case OP_ICONV_TO_U4:
4307 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4309 case OP_ICONV_TO_R4:
4310 case OP_ICONV_TO_R8:
4311 case OP_LCONV_TO_R4:
4312 case OP_LCONV_TO_R8: {
4314 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4315 ppc_extsw (code, ppc_r0, ins->sreg1);
4320 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4321 ppc_mffgpr (code, ins->dreg, tmp);
4323 ppc_str (code, tmp, -8, ppc_r1);
4324 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4326 ppc_fcfid (code, ins->dreg, ins->dreg);
4327 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4328 ppc_frsp (code, ins->dreg, ins->dreg);
4332 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4335 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4338 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4340 ppc_mfspr (code, ppc_r0, ppc_xer);
4341 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4342 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4344 case OP_COND_EXC_OV:
4345 ppc_mfspr (code, ppc_r0, ppc_xer);
4346 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4347 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4359 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4361 case OP_FCONV_TO_I8:
4362 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4364 case OP_FCONV_TO_U8:
4365 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4367 case OP_STOREI4_MEMBASE_REG:
4368 if (ppc_is_imm16 (ins->inst_offset)) {
4369 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4371 ppc_load (code, ppc_r0, ins->inst_offset);
4372 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4375 case OP_STOREI4_MEMINDEX:
4376 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4379 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4381 case OP_ISHR_UN_IMM:
4382 if (ins->inst_imm & 0x1f)
4383 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4385 ppc_mr (code, ins->dreg, ins->sreg1);
4387 case OP_ATOMIC_ADD_NEW_I4:
4388 case OP_ATOMIC_ADD_NEW_I8: {
4389 guint8 *loop = code, *branch;
4390 g_assert (ins->inst_offset == 0);
4391 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4392 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4394 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4395 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4396 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4397 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4399 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4401 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4402 ppc_patch (branch, loop);
4403 ppc_mr (code, ins->dreg, ppc_r0);
4407 case OP_ICONV_TO_R4:
4408 case OP_ICONV_TO_R8: {
4409 if (cpu_hw_caps & PPC_ISA_64) {
4410 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4411 ppc_stw (code, ppc_r0, -8, ppc_r1);
4412 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4413 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4414 ppc_fcfid (code, ins->dreg, ins->dreg);
4415 if (ins->opcode == OP_ICONV_TO_R4)
4416 ppc_frsp (code, ins->dreg, ins->dreg);
4421 case OP_ATOMIC_CAS_I4:
4422 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4423 int location = ins->sreg1;
4424 int value = ins->sreg2;
4425 int comparand = ins->sreg3;
4426 guint8 *start, *not_equal, *lost_reservation;
4429 if (ins->opcode == OP_ATOMIC_CAS_I4)
4430 ppc_lwarx (code, ppc_r0, 0, location);
4431 #ifdef __mono_ppc64__
4433 ppc_ldarx (code, ppc_r0, 0, location);
4435 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4438 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4439 if (ins->opcode == OP_ATOMIC_CAS_I4)
4440 ppc_stwcxd (code, value, 0, location);
4441 #ifdef __mono_ppc64__
4443 ppc_stdcxd (code, value, 0, location);
4446 lost_reservation = code;
4447 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4448 ppc_patch (lost_reservation, start);
4450 ppc_patch (not_equal, code);
4451 ppc_mr (code, ins->dreg, ppc_r0);
4456 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4457 g_assert_not_reached ();
4460 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4461 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4462 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4463 g_assert_not_reached ();
4469 last_offset = offset;
4472 cfg->code_len = code - cfg->native_code;
4474 #endif /* !DISABLE_JIT */
4477 mono_arch_register_lowlevel_calls (void)
4479 /* The signature doesn't matter */
4480 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4483 #ifdef __mono_ppc64__
4484 #define patch_load_sequence(ip,val) do {\
4485 guint16 *__load = (guint16*)(ip); \
4486 g_assert (sizeof (val) == sizeof (gsize)); \
4487 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4488 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4489 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4490 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4493 #define patch_load_sequence(ip,val) do {\
4494 guint16 *__lis_ori = (guint16*)(ip); \
4495 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4496 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4502 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4504 MonoJumpInfo *patch_info;
4505 gboolean compile_aot = !run_cctors;
4507 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4508 unsigned char *ip = patch_info->ip.i + code;
4509 unsigned char *target;
4510 gboolean is_fd = FALSE;
4512 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4515 switch (patch_info->type) {
4516 case MONO_PATCH_INFO_BB:
4517 case MONO_PATCH_INFO_LABEL:
4520 /* No need to patch these */
4525 switch (patch_info->type) {
4526 case MONO_PATCH_INFO_IP:
4527 patch_load_sequence (ip, ip);
4529 case MONO_PATCH_INFO_METHOD_REL:
4530 g_assert_not_reached ();
4531 *((gpointer *)(ip)) = code + patch_info->data.offset;
4533 case MONO_PATCH_INFO_SWITCH: {
4534 gpointer *table = (gpointer *)patch_info->data.table->table;
4537 patch_load_sequence (ip, table);
4539 for (i = 0; i < patch_info->data.table->table_size; i++) {
4540 table [i] = (glong)patch_info->data.table->table [i] + code;
4542 /* we put into the table the absolute address, no need for ppc_patch in this case */
4545 case MONO_PATCH_INFO_METHODCONST:
4546 case MONO_PATCH_INFO_CLASS:
4547 case MONO_PATCH_INFO_IMAGE:
4548 case MONO_PATCH_INFO_FIELD:
4549 case MONO_PATCH_INFO_VTABLE:
4550 case MONO_PATCH_INFO_IID:
4551 case MONO_PATCH_INFO_SFLDA:
4552 case MONO_PATCH_INFO_LDSTR:
4553 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4554 case MONO_PATCH_INFO_LDTOKEN:
4555 /* from OP_AOTCONST : lis + ori */
4556 patch_load_sequence (ip, target);
4558 case MONO_PATCH_INFO_R4:
4559 case MONO_PATCH_INFO_R8:
4560 g_assert_not_reached ();
4561 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4563 case MONO_PATCH_INFO_EXC_NAME:
4564 g_assert_not_reached ();
4565 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4567 case MONO_PATCH_INFO_NONE:
4568 case MONO_PATCH_INFO_BB_OVF:
4569 case MONO_PATCH_INFO_EXC_OVF:
4570 /* everything is dealt with at epilog output time */
4572 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4573 case MONO_PATCH_INFO_INTERNAL_METHOD:
4574 case MONO_PATCH_INFO_ABS:
4575 case MONO_PATCH_INFO_CLASS_INIT:
4576 case MONO_PATCH_INFO_RGCTX_FETCH:
4577 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4584 ppc_patch_full (ip, target, is_fd);
4589 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4590 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4591 * the instruction offset immediate for all the registers.
4594 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4598 for (i = 13; i <= 31; i++) {
4599 if (used_int_regs & (1 << i)) {
4600 ppc_str (code, i, pos, base_reg);
4601 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4602 pos += sizeof (mgreg_t);
4606 /* pos is the start of the MonoLMF structure */
4607 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4608 for (i = 13; i <= 31; i++) {
4609 ppc_str (code, i, offset, base_reg);
4610 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4611 offset += sizeof (mgreg_t);
4613 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4614 for (i = 14; i < 32; i++) {
4615 ppc_stfd (code, i, offset, base_reg);
4616 offset += sizeof (gdouble);
4623 * Stack frame layout:
4625 * ------------------- sp
4626 * MonoLMF structure or saved registers
4627 * -------------------
4629 * -------------------
4631 * -------------------
4632 * optional 8 bytes for tracing
4633 * -------------------
4634 * param area size is cfg->param_area
4635 * -------------------
4636 * linkage area size is PPC_STACK_PARAM_OFFSET
4637 * ------------------- sp
4641 mono_arch_emit_prolog (MonoCompile *cfg)
4643 MonoMethod *method = cfg->method;
4645 MonoMethodSignature *sig;
4647 long alloc_size, pos, max_offset, cfa_offset;
4653 int tailcall_struct_index;
4655 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4658 sig = mono_method_signature (method);
4659 cfg->code_size = 512 + sig->param_count * 32;
4660 code = cfg->native_code = g_malloc (cfg->code_size);
4664 /* We currently emit unwind info for aot, but don't use it */
4665 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4667 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4668 ppc_mflr (code, ppc_r0);
4669 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4670 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4673 alloc_size = cfg->stack_offset;
4676 if (!method->save_lmf) {
4677 for (i = 31; i >= 13; --i) {
4678 if (cfg->used_int_regs & (1 << i)) {
4679 pos += sizeof (mgreg_t);
4683 pos += sizeof (MonoLMF);
4687 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4688 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4689 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4690 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4693 cfg->stack_usage = alloc_size;
4694 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4696 if (ppc_is_imm16 (-alloc_size)) {
4697 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4698 cfa_offset = alloc_size;
4699 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4700 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4703 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4704 ppc_load (code, ppc_r0, -alloc_size);
4705 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4706 cfa_offset = alloc_size;
4707 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4708 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4711 if (cfg->frame_reg != ppc_sp) {
4712 ppc_mr (code, cfg->frame_reg, ppc_sp);
4713 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4716 /* store runtime generic context */
4717 if (cfg->rgctx_var) {
4718 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4719 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4721 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4724 /* compute max_offset in order to use short forward jumps
4725 * we always do it on ppc because the immediate displacement
4726 * for jumps is too small
4729 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4731 bb->max_offset = max_offset;
4733 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4736 MONO_BB_FOR_EACH_INS (bb, ins)
4737 max_offset += ins_native_length (cfg, ins);
4740 /* load arguments allocated to register from the stack */
4743 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4745 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4746 ArgInfo *ainfo = &cinfo->ret;
4748 inst = cfg->vret_addr;
4751 if (ppc_is_imm16 (inst->inst_offset)) {
4752 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4754 ppc_load (code, ppc_r11, inst->inst_offset);
4755 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4759 tailcall_struct_index = 0;
4760 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4761 ArgInfo *ainfo = cinfo->args + i;
4762 inst = cfg->args [pos];
4764 if (cfg->verbose_level > 2)
4765 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4766 if (inst->opcode == OP_REGVAR) {
4767 if (ainfo->regtype == RegTypeGeneral)
4768 ppc_mr (code, inst->dreg, ainfo->reg);
4769 else if (ainfo->regtype == RegTypeFP)
4770 ppc_fmr (code, inst->dreg, ainfo->reg);
4771 else if (ainfo->regtype == RegTypeBase) {
4772 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4773 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4775 g_assert_not_reached ();
4777 if (cfg->verbose_level > 2)
4778 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4780 /* the argument should be put on the stack: FIXME handle size != word */
4781 if (ainfo->regtype == RegTypeGeneral) {
4782 switch (ainfo->size) {
4784 if (ppc_is_imm16 (inst->inst_offset)) {
4785 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4787 if (ppc_is_imm32 (inst->inst_offset)) {
4788 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4789 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4791 ppc_load (code, ppc_r11, inst->inst_offset);
4792 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4797 if (ppc_is_imm16 (inst->inst_offset)) {
4798 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4800 if (ppc_is_imm32 (inst->inst_offset)) {
4801 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4802 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4804 ppc_load (code, ppc_r11, inst->inst_offset);
4805 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4809 #ifdef __mono_ppc64__
4811 if (ppc_is_imm16 (inst->inst_offset)) {
4812 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4814 if (ppc_is_imm32 (inst->inst_offset)) {
4815 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4816 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4818 ppc_load (code, ppc_r11, inst->inst_offset);
4819 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4824 if (ppc_is_imm16 (inst->inst_offset)) {
4825 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4827 ppc_load (code, ppc_r11, inst->inst_offset);
4828 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4833 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4834 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4835 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4837 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4838 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4839 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4840 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4845 if (ppc_is_imm16 (inst->inst_offset)) {
4846 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4848 if (ppc_is_imm32 (inst->inst_offset)) {
4849 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4850 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4852 ppc_load (code, ppc_r11, inst->inst_offset);
4853 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4858 } else if (ainfo->regtype == RegTypeBase) {
4859 g_assert (ppc_is_imm16 (ainfo->offset));
4860 /* load the previous stack pointer in r11 */
4861 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4862 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4863 switch (ainfo->size) {
4865 if (ppc_is_imm16 (inst->inst_offset)) {
4866 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4868 if (ppc_is_imm32 (inst->inst_offset)) {
4869 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4870 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4872 ppc_load (code, ppc_r11, inst->inst_offset);
4873 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4878 if (ppc_is_imm16 (inst->inst_offset)) {
4879 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4881 if (ppc_is_imm32 (inst->inst_offset)) {
4882 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4883 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4885 ppc_load (code, ppc_r11, inst->inst_offset);
4886 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4890 #ifdef __mono_ppc64__
4892 if (ppc_is_imm16 (inst->inst_offset)) {
4893 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4895 if (ppc_is_imm32 (inst->inst_offset)) {
4896 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4897 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4899 ppc_load (code, ppc_r11, inst->inst_offset);
4900 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4905 if (ppc_is_imm16 (inst->inst_offset)) {
4906 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4908 ppc_load (code, ppc_r11, inst->inst_offset);
4909 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4914 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4915 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4916 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4917 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4918 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4920 /* use r12 to load the 2nd half of the long before we clobber r11. */
4921 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4922 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4923 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4924 ppc_stw (code, ppc_r0, 0, ppc_r11);
4925 ppc_stw (code, ppc_r12, 4, ppc_r11);
4930 if (ppc_is_imm16 (inst->inst_offset)) {
4931 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4933 if (ppc_is_imm32 (inst->inst_offset)) {
4934 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4935 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4937 ppc_load (code, ppc_r11, inst->inst_offset);
4938 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4943 } else if (ainfo->regtype == RegTypeFP) {
4944 g_assert (ppc_is_imm16 (inst->inst_offset));
4945 if (ainfo->size == 8)
4946 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4947 else if (ainfo->size == 4)
4948 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4950 g_assert_not_reached ();
4951 } else if (ainfo->regtype == RegTypeStructByVal) {
4952 int doffset = inst->inst_offset;
4956 g_assert (ppc_is_imm16 (inst->inst_offset));
4957 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4958 /* FIXME: what if there is no class? */
4959 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4960 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4961 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4964 * Darwin handles 1 and 2 byte
4965 * structs specially by
4966 * loading h/b into the arg
4967 * register. Only done for
4971 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4973 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4977 #ifdef __mono_ppc64__
4979 g_assert (cur_reg == 0);
4980 ppc_sldi (code, ppc_r0, ainfo->reg,
4981 (sizeof (gpointer) - ainfo->bytes) * 8);
4982 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
4986 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
4987 inst->inst_basereg);
4990 soffset += sizeof (gpointer);
4991 doffset += sizeof (gpointer);
4993 if (ainfo->vtsize) {
4994 /* FIXME: we need to do the shifting here, too */
4997 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4998 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4999 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5000 code = emit_memcpy (code, size - soffset,
5001 inst->inst_basereg, doffset,
5002 ppc_r11, ainfo->offset + soffset);
5004 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5005 inst->inst_basereg, doffset,
5006 ppc_r11, ainfo->offset + soffset);
5009 } else if (ainfo->regtype == RegTypeStructByAddr) {
5010 /* if it was originally a RegTypeBase */
5011 if (ainfo->offset) {
5012 /* load the previous stack pointer in r11 */
5013 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5014 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5016 ppc_mr (code, ppc_r11, ainfo->reg);
5019 if (cfg->tailcall_valuetype_addrs) {
5020 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5022 g_assert (ppc_is_imm16 (addr->inst_offset));
5023 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5025 tailcall_struct_index++;
5028 g_assert (ppc_is_imm16 (inst->inst_offset));
5029 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5030 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5032 g_assert_not_reached ();
5037 if (method->save_lmf) {
5038 if (lmf_pthread_key != -1) {
5039 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5040 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5041 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5043 if (cfg->compile_aot) {
5044 /* Compute the got address which is needed by the PLT entry */
5045 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5047 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5048 (gpointer)"mono_get_lmf_addr");
5049 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5050 ppc_load_func (code, ppc_r0, 0);
5051 ppc_mtlr (code, ppc_r0);
5057 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5058 /* lmf_offset is the offset from the previous stack pointer,
5059 * alloc_size is the total stack space allocated, so the offset
5060 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5061 * The pointer to the struct is put in ppc_r11 (new_lmf).
5062 * The callee-saved registers are already in the MonoLMF structure
5064 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5065 /* ppc_r3 is the result from mono_get_lmf_addr () */
5066 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5067 /* new_lmf->previous_lmf = *lmf_addr */
5068 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5069 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5070 /* *(lmf_addr) = r11 */
5071 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5072 /* save method info */
5073 if (cfg->compile_aot)
5075 ppc_load (code, ppc_r0, 0);
5077 ppc_load_ptr (code, ppc_r0, method);
5078 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5079 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5080 /* save the current IP */
5081 if (cfg->compile_aot) {
5083 ppc_mflr (code, ppc_r0);
5085 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5086 #ifdef __mono_ppc64__
5087 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5089 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5092 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5096 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5098 cfg->code_len = code - cfg->native_code;
5099 g_assert (cfg->code_len <= cfg->code_size);
5106 mono_arch_emit_epilog (MonoCompile *cfg)
5108 MonoMethod *method = cfg->method;
5110 int max_epilog_size = 16 + 20*4;
5113 if (cfg->method->save_lmf)
5114 max_epilog_size += 128;
5116 if (mono_jit_trace_calls != NULL)
5117 max_epilog_size += 50;
5119 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5120 max_epilog_size += 50;
5122 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5123 cfg->code_size *= 2;
5124 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5125 cfg->stat_code_reallocs++;
5129 * Keep in sync with OP_JMP
5131 code = cfg->native_code + cfg->code_len;
5133 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5134 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5138 if (method->save_lmf) {
5140 pos += sizeof (MonoLMF);
5142 /* save the frame reg in r8 */
5143 ppc_mr (code, ppc_r8, cfg->frame_reg);
5144 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5145 /* r5 = previous_lmf */
5146 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5148 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5149 /* *(lmf_addr) = previous_lmf */
5150 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5151 /* FIXME: speedup: there is no actual need to restore the registers if
5152 * we didn't actually change them (idea from Zoltan).
5155 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5157 /*for (i = 14; i < 32; i++) {
5158 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5160 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5161 /* use the saved copy of the frame reg in r8 */
5162 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5163 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5164 ppc_mtlr (code, ppc_r0);
5166 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5168 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5169 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5170 if (ppc_is_imm16 (return_offset)) {
5171 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5173 ppc_load (code, ppc_r11, return_offset);
5174 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5176 ppc_mtlr (code, ppc_r0);
5178 if (ppc_is_imm16 (cfg->stack_usage)) {
5179 int offset = cfg->stack_usage;
5180 for (i = 13; i <= 31; i++) {
5181 if (cfg->used_int_regs & (1 << i))
5182 offset -= sizeof (mgreg_t);
5184 if (cfg->frame_reg != ppc_sp)
5185 ppc_mr (code, ppc_r11, cfg->frame_reg);
5186 /* note r31 (possibly the frame register) is restored last */
5187 for (i = 13; i <= 31; i++) {
5188 if (cfg->used_int_regs & (1 << i)) {
5189 ppc_ldr (code, i, offset, cfg->frame_reg);
5190 offset += sizeof (mgreg_t);
5193 if (cfg->frame_reg != ppc_sp)
5194 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5196 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5198 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5199 if (cfg->used_int_regs) {
5200 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5201 for (i = 31; i >= 13; --i) {
5202 if (cfg->used_int_regs & (1 << i)) {
5203 pos += sizeof (mgreg_t);
5204 ppc_ldr (code, i, -pos, ppc_r11);
5207 ppc_mr (code, ppc_sp, ppc_r11);
5209 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5216 cfg->code_len = code - cfg->native_code;
5218 g_assert (cfg->code_len < cfg->code_size);
5221 #endif /* ifndef DISABLE_JIT */
5223 /* remove once throw_exception_by_name is eliminated */
5225 exception_id_by_name (const char *name)
5227 if (strcmp (name, "IndexOutOfRangeException") == 0)
5228 return MONO_EXC_INDEX_OUT_OF_RANGE;
5229 if (strcmp (name, "OverflowException") == 0)
5230 return MONO_EXC_OVERFLOW;
5231 if (strcmp (name, "ArithmeticException") == 0)
5232 return MONO_EXC_ARITHMETIC;
5233 if (strcmp (name, "DivideByZeroException") == 0)
5234 return MONO_EXC_DIVIDE_BY_ZERO;
5235 if (strcmp (name, "InvalidCastException") == 0)
5236 return MONO_EXC_INVALID_CAST;
5237 if (strcmp (name, "NullReferenceException") == 0)
5238 return MONO_EXC_NULL_REF;
5239 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5240 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5241 if (strcmp (name, "ArgumentException") == 0)
5242 return MONO_EXC_ARGUMENT;
5243 g_error ("Unknown intrinsic exception %s\n", name);
5249 mono_arch_emit_exceptions (MonoCompile *cfg)
5251 MonoJumpInfo *patch_info;
5254 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5255 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5256 int max_epilog_size = 50;
5258 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5259 exc_throw_pos [i] = NULL;
5260 exc_throw_found [i] = 0;
5263 /* count the number of exception infos */
5266 * make sure we have enough space for exceptions
5268 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5269 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5270 i = exception_id_by_name (patch_info->data.target);
5271 if (!exc_throw_found [i]) {
5272 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5273 exc_throw_found [i] = TRUE;
5275 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5276 max_epilog_size += 12;
5277 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5278 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5279 i = exception_id_by_name (ovfj->data.exception);
5280 if (!exc_throw_found [i]) {
5281 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5282 exc_throw_found [i] = TRUE;
5284 max_epilog_size += 8;
5288 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5289 cfg->code_size *= 2;
5290 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5291 cfg->stat_code_reallocs++;
5294 code = cfg->native_code + cfg->code_len;
5296 /* add code to raise exceptions */
5297 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5298 switch (patch_info->type) {
5299 case MONO_PATCH_INFO_BB_OVF: {
5300 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5301 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5302 /* patch the initial jump */
5303 ppc_patch (ip, code);
5304 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5306 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5307 /* jump back to the true target */
5309 ip = ovfj->data.bb->native_offset + cfg->native_code;
5310 ppc_patch (code - 4, ip);
5311 patch_info->type = MONO_PATCH_INFO_NONE;
5314 case MONO_PATCH_INFO_EXC_OVF: {
5315 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5316 MonoJumpInfo *newji;
5317 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5318 unsigned char *bcl = code;
5319 /* patch the initial jump: we arrived here with a call */
5320 ppc_patch (ip, code);
5321 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5323 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5324 /* patch the conditional jump to the right handler */
5325 /* make it processed next */
5326 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5327 newji->type = MONO_PATCH_INFO_EXC;
5328 newji->ip.i = bcl - cfg->native_code;
5329 newji->data.target = ovfj->data.exception;
5330 newji->next = patch_info->next;
5331 patch_info->next = newji;
5332 patch_info->type = MONO_PATCH_INFO_NONE;
5335 case MONO_PATCH_INFO_EXC: {
5336 MonoClass *exc_class;
5338 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5339 i = exception_id_by_name (patch_info->data.target);
5340 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5341 ppc_patch (ip, exc_throw_pos [i]);
5342 patch_info->type = MONO_PATCH_INFO_NONE;
5345 exc_throw_pos [i] = code;
5348 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5349 g_assert (exc_class);
5351 ppc_patch (ip, code);
5352 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5353 ppc_load (code, ppc_r3, exc_class->type_token);
5354 /* we got here from a conditional call, so the calling ip is set in lr */
5355 ppc_mflr (code, ppc_r4);
5356 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5357 patch_info->data.name = "mono_arch_throw_corlib_exception";
5358 patch_info->ip.i = code - cfg->native_code;
5359 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5360 ppc_load_func (code, ppc_r0, 0);
5361 ppc_mtctr (code, ppc_r0);
5362 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5374 cfg->code_len = code - cfg->native_code;
5376 g_assert (cfg->code_len <= cfg->code_size);
5382 try_offset_access (void *value, guint32 idx)
5384 register void* me __asm__ ("r2");
5385 void ***p = (void***)((char*)me + 284);
5386 int idx1 = idx / 32;
5387 int idx2 = idx % 32;
5390 if (value != p[idx1][idx2])
5397 setup_tls_access (void)
5399 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5400 size_t conf_size = 0;
5403 /* FIXME for darwin */
5404 guint32 *ins, *code;
5405 guint32 cmplwi_1023, li_0x48, blr_ins;
5409 tls_mode = TLS_MODE_FAILED;
5412 if (tls_mode == TLS_MODE_FAILED)
5414 if (g_getenv ("MONO_NO_TLS")) {
5415 tls_mode = TLS_MODE_FAILED;
5419 if (tls_mode == TLS_MODE_DETECT) {
5420 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5421 tls_mode = TLS_MODE_DARWIN_G4;
5422 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5423 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5424 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5425 tls_mode = TLS_MODE_NPTL;
5426 #elif !defined(TARGET_PS3)
5427 ins = (guint32*)pthread_getspecific;
5428 /* uncond branch to the real method */
5429 if ((*ins >> 26) == 18) {
5431 val = (*ins & ~3) << 6;
5435 ins = (guint32*)(long)val;
5437 ins = (guint32*) ((char*)ins + val);
5440 code = &cmplwi_1023;
5441 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5443 ppc_li (code, ppc_r4, 0x48);
5446 if (*ins == cmplwi_1023) {
5447 int found_lwz_284 = 0;
5449 for (ptk = 0; ptk < 20; ++ptk) {
5451 if (!*ins || *ins == blr_ins)
5453 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5458 if (!found_lwz_284) {
5459 tls_mode = TLS_MODE_FAILED;
5462 tls_mode = TLS_MODE_LTHREADS;
5463 } else if (*ins == li_0x48) {
5465 /* uncond branch to the real method */
5466 if ((*ins >> 26) == 18) {
5468 val = (*ins & ~3) << 6;
5472 ins = (guint32*)(long)val;
5474 ins = (guint32*) ((char*)ins + val);
5476 code = (guint32*)&val;
5477 ppc_li (code, ppc_r0, 0x7FF2);
5478 if (ins [1] == val) {
5479 /* Darwin on G4, implement */
5480 tls_mode = TLS_MODE_FAILED;
5483 code = (guint32*)&val;
5484 ppc_mfspr (code, ppc_r3, 104);
5485 if (ins [1] != val) {
5486 tls_mode = TLS_MODE_FAILED;
5489 tls_mode = TLS_MODE_DARWIN_G5;
5492 tls_mode = TLS_MODE_FAILED;
5496 tls_mode = TLS_MODE_FAILED;
5502 if (tls_mode == TLS_MODE_DETECT)
5503 tls_mode = TLS_MODE_FAILED;
5504 if (tls_mode == TLS_MODE_FAILED)
5506 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5507 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5511 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5512 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5513 if (lmf_pthread_key == -1) {
5514 guint32 ptk = mono_jit_tls_id;
5516 /*g_print ("MonoLMF at: %d\n", ptk);*/
5517 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5518 init_tls_failed = 1;
5521 lmf_pthread_key = ptk;
5530 mono_arch_finish_init (void)
5532 setup_tls_access ();
5536 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5540 #ifdef MONO_ARCH_HAVE_IMT
5542 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5544 #define LOADSTORE_SIZE 4
5545 #define JUMP_IMM_SIZE 12
5546 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5547 #define ENABLE_WRONG_METHOD_CHECK 0
5550 * LOCKING: called with the domain lock held
5553 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5554 gpointer fail_tramp)
5558 guint8 *code, *start;
5560 for (i = 0; i < count; ++i) {
5561 MonoIMTCheckItem *item = imt_entries [i];
5562 if (item->is_equals) {
5563 if (item->check_target_idx) {
5564 if (!item->compare_done)
5565 item->chunk_size += CMP_SIZE;
5566 if (item->has_target_code)
5567 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5569 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5572 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5573 if (!item->has_target_code)
5574 item->chunk_size += LOADSTORE_SIZE;
5576 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5577 #if ENABLE_WRONG_METHOD_CHECK
5578 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5583 item->chunk_size += CMP_SIZE + BR_SIZE;
5584 imt_entries [item->check_target_idx]->compare_done = TRUE;
5586 size += item->chunk_size;
5588 /* the initial load of the vtable address */
5589 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5591 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5593 code = mono_domain_code_reserve (domain, size);
5598 * We need to save and restore r11 because it might be
5599 * used by the caller as the vtable register, so
5600 * clobbering it will trip up the magic trampoline.
5602 * FIXME: Get rid of this by making sure that r11 is
5603 * not used as the vtable register in interface calls.
5605 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5606 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5608 for (i = 0; i < count; ++i) {
5609 MonoIMTCheckItem *item = imt_entries [i];
5610 item->code_target = code;
5611 if (item->is_equals) {
5612 if (item->check_target_idx) {
5613 if (!item->compare_done) {
5614 ppc_load (code, ppc_r0, (gsize)item->key);
5615 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5617 item->jmp_code = code;
5618 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5619 if (item->has_target_code) {
5620 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5622 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5623 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5625 ppc_mtctr (code, ppc_r0);
5626 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5629 ppc_load (code, ppc_r0, (gulong)item->key);
5630 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5631 item->jmp_code = code;
5632 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5633 if (item->has_target_code) {
5634 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5637 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5638 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5640 ppc_mtctr (code, ppc_r0);
5641 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5642 ppc_patch (item->jmp_code, code);
5643 ppc_load_ptr (code, ppc_r0, fail_tramp);
5644 ppc_mtctr (code, ppc_r0);
5645 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5646 item->jmp_code = NULL;
5648 /* enable the commented code to assert on wrong method */
5649 #if ENABLE_WRONG_METHOD_CHECK
5650 ppc_load (code, ppc_r0, (guint32)item->key);
5651 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5652 item->jmp_code = code;
5653 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5655 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5656 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5657 ppc_mtctr (code, ppc_r0);
5658 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5659 #if ENABLE_WRONG_METHOD_CHECK
5660 ppc_patch (item->jmp_code, code);
5662 item->jmp_code = NULL;
5667 ppc_load (code, ppc_r0, (gulong)item->key);
5668 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5669 item->jmp_code = code;
5670 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5673 /* patch the branches to get to the target items */
5674 for (i = 0; i < count; ++i) {
5675 MonoIMTCheckItem *item = imt_entries [i];
5676 if (item->jmp_code) {
5677 if (item->check_target_idx) {
5678 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5684 mono_stats.imt_thunks_size += code - start;
5685 g_assert (code - start <= size);
5686 mono_arch_flush_icache (start, size);
5691 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5693 mgreg_t *r = (mgreg_t*)regs;
5695 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5700 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5702 mgreg_t *r = (mgreg_t*)regs;
5704 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5708 mono_arch_get_cie_program (void)
5712 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5718 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5725 mono_arch_print_tree (MonoInst *tree, int arity)
5731 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5734 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5736 g_assert (reg >= ppc_r13);
5738 return ctx->regs [reg - ppc_r13];
5742 mono_arch_get_patch_offset (guint8 *code)
5748 * mono_aot_emit_load_got_addr:
5750 * Emit code to load the got address.
5751 * On PPC, the result is placed into r30.
5754 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5757 ppc_mflr (code, ppc_r30);
5759 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5761 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5762 /* arch_emit_got_address () patches this */
5763 #if defined(TARGET_POWERPC64)
5769 ppc_load32 (code, ppc_r0, 0);
5770 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5777 * mono_ppc_emit_load_aotconst:
5779 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5780 * TARGET from the mscorlib GOT in full-aot code.
5781 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5785 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5787 /* Load the mscorlib got address */
5788 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5789 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5790 /* arch_emit_got_access () patches this */
5791 ppc_load32 (code, ppc_r0, 0);
5792 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5797 /* Soft Debug support */
5798 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5805 * mono_arch_set_breakpoint:
5807 * See mini-amd64.c for docs.
5810 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5813 guint8 *orig_code = code;
5815 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5816 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5818 g_assert (code - orig_code == BREAKPOINT_SIZE);
5820 mono_arch_flush_icache (orig_code, code - orig_code);
5824 * mono_arch_clear_breakpoint:
5826 * See mini-amd64.c for docs.
5829 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5834 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5837 mono_arch_flush_icache (ip, code - ip);
5841 * mono_arch_is_breakpoint_event:
5843 * See mini-amd64.c for docs.
5846 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5848 siginfo_t* sinfo = (siginfo_t*) info;
5849 /* Sometimes the address is off by 4 */
5850 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5857 * mono_arch_skip_breakpoint:
5859 * See mini-amd64.c for docs.
5862 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5864 /* skip the ldptr */
5865 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5873 * mono_arch_start_single_stepping:
5875 * See mini-amd64.c for docs.
5878 mono_arch_start_single_stepping (void)
5880 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5884 * mono_arch_stop_single_stepping:
5886 * See mini-amd64.c for docs.
5889 mono_arch_stop_single_stepping (void)
5891 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5895 * mono_arch_is_single_step_event:
5897 * See mini-amd64.c for docs.
5900 mono_arch_is_single_step_event (void *info, void *sigctx)
5902 siginfo_t* sinfo = (siginfo_t*) info;
5903 /* Sometimes the address is off by 4 */
5904 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5911 * mono_arch_skip_single_step:
5913 * See mini-amd64.c for docs.
5916 mono_arch_skip_single_step (MonoContext *ctx)
5918 /* skip the ldptr */
5919 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5923 * mono_arch_create_seq_point_info:
5925 * See mini-amd64.c for docs.
5928 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5935 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5937 ext->lmf.previous_lmf = prev_lmf;
5938 /* Mark that this is a MonoLMFExt */
5939 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5940 ext->lmf.ebp = (gssize)ext;