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_I4:
4388 case OP_ATOMIC_ADD_I8: {
4389 guint8 *loop = code, *branch;
4390 g_assert (ins->inst_offset == 0);
4392 if (ins->opcode == OP_ATOMIC_ADD_I4)
4393 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4395 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4396 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4397 if (ins->opcode == OP_ATOMIC_ADD_I4)
4398 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4400 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4402 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4403 ppc_patch (branch, loop);
4405 ppc_mr (code, ins->dreg, ppc_r0);
4409 case OP_ICONV_TO_R4:
4410 case OP_ICONV_TO_R8: {
4411 if (cpu_hw_caps & PPC_ISA_64) {
4412 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4413 ppc_stw (code, ppc_r0, -8, ppc_r1);
4414 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4415 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4416 ppc_fcfid (code, ins->dreg, ins->dreg);
4417 if (ins->opcode == OP_ICONV_TO_R4)
4418 ppc_frsp (code, ins->dreg, ins->dreg);
4423 case OP_ATOMIC_CAS_I4:
4424 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4425 int location = ins->sreg1;
4426 int value = ins->sreg2;
4427 int comparand = ins->sreg3;
4428 guint8 *start, *not_equal, *lost_reservation;
4432 if (ins->opcode == OP_ATOMIC_CAS_I4)
4433 ppc_lwarx (code, ppc_r0, 0, location);
4434 #ifdef __mono_ppc64__
4436 ppc_ldarx (code, ppc_r0, 0, location);
4438 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4441 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4442 if (ins->opcode == OP_ATOMIC_CAS_I4)
4443 ppc_stwcxd (code, value, 0, location);
4444 #ifdef __mono_ppc64__
4446 ppc_stdcxd (code, value, 0, location);
4449 lost_reservation = code;
4450 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4451 ppc_patch (lost_reservation, start);
4453 ppc_patch (not_equal, code);
4455 ppc_mr (code, ins->dreg, ppc_r0);
4460 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4461 g_assert_not_reached ();
4464 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4465 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4466 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4467 g_assert_not_reached ();
4473 last_offset = offset;
4476 cfg->code_len = code - cfg->native_code;
4478 #endif /* !DISABLE_JIT */
4481 mono_arch_register_lowlevel_calls (void)
4483 /* The signature doesn't matter */
4484 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4487 #ifdef __mono_ppc64__
4488 #define patch_load_sequence(ip,val) do {\
4489 guint16 *__load = (guint16*)(ip); \
4490 g_assert (sizeof (val) == sizeof (gsize)); \
4491 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4492 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4493 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4494 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4497 #define patch_load_sequence(ip,val) do {\
4498 guint16 *__lis_ori = (guint16*)(ip); \
4499 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4500 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4506 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4508 MonoJumpInfo *patch_info;
4509 gboolean compile_aot = !run_cctors;
4511 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4512 unsigned char *ip = patch_info->ip.i + code;
4513 unsigned char *target;
4514 gboolean is_fd = FALSE;
4516 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4519 switch (patch_info->type) {
4520 case MONO_PATCH_INFO_BB:
4521 case MONO_PATCH_INFO_LABEL:
4524 /* No need to patch these */
4529 switch (patch_info->type) {
4530 case MONO_PATCH_INFO_IP:
4531 patch_load_sequence (ip, ip);
4533 case MONO_PATCH_INFO_METHOD_REL:
4534 g_assert_not_reached ();
4535 *((gpointer *)(ip)) = code + patch_info->data.offset;
4537 case MONO_PATCH_INFO_SWITCH: {
4538 gpointer *table = (gpointer *)patch_info->data.table->table;
4541 patch_load_sequence (ip, table);
4543 for (i = 0; i < patch_info->data.table->table_size; i++) {
4544 table [i] = (glong)patch_info->data.table->table [i] + code;
4546 /* we put into the table the absolute address, no need for ppc_patch in this case */
4549 case MONO_PATCH_INFO_METHODCONST:
4550 case MONO_PATCH_INFO_CLASS:
4551 case MONO_PATCH_INFO_IMAGE:
4552 case MONO_PATCH_INFO_FIELD:
4553 case MONO_PATCH_INFO_VTABLE:
4554 case MONO_PATCH_INFO_IID:
4555 case MONO_PATCH_INFO_SFLDA:
4556 case MONO_PATCH_INFO_LDSTR:
4557 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4558 case MONO_PATCH_INFO_LDTOKEN:
4559 /* from OP_AOTCONST : lis + ori */
4560 patch_load_sequence (ip, target);
4562 case MONO_PATCH_INFO_R4:
4563 case MONO_PATCH_INFO_R8:
4564 g_assert_not_reached ();
4565 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4567 case MONO_PATCH_INFO_EXC_NAME:
4568 g_assert_not_reached ();
4569 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4571 case MONO_PATCH_INFO_NONE:
4572 case MONO_PATCH_INFO_BB_OVF:
4573 case MONO_PATCH_INFO_EXC_OVF:
4574 /* everything is dealt with at epilog output time */
4576 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4577 case MONO_PATCH_INFO_INTERNAL_METHOD:
4578 case MONO_PATCH_INFO_ABS:
4579 case MONO_PATCH_INFO_CLASS_INIT:
4580 case MONO_PATCH_INFO_RGCTX_FETCH:
4581 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4588 ppc_patch_full (ip, target, is_fd);
4593 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4594 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4595 * the instruction offset immediate for all the registers.
4598 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4602 for (i = 13; i <= 31; i++) {
4603 if (used_int_regs & (1 << i)) {
4604 ppc_str (code, i, pos, base_reg);
4605 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4606 pos += sizeof (mgreg_t);
4610 /* pos is the start of the MonoLMF structure */
4611 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4612 for (i = 13; i <= 31; i++) {
4613 ppc_str (code, i, offset, base_reg);
4614 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4615 offset += sizeof (mgreg_t);
4617 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4618 for (i = 14; i < 32; i++) {
4619 ppc_stfd (code, i, offset, base_reg);
4620 offset += sizeof (gdouble);
4627 * Stack frame layout:
4629 * ------------------- sp
4630 * MonoLMF structure or saved registers
4631 * -------------------
4633 * -------------------
4635 * -------------------
4636 * optional 8 bytes for tracing
4637 * -------------------
4638 * param area size is cfg->param_area
4639 * -------------------
4640 * linkage area size is PPC_STACK_PARAM_OFFSET
4641 * ------------------- sp
4645 mono_arch_emit_prolog (MonoCompile *cfg)
4647 MonoMethod *method = cfg->method;
4649 MonoMethodSignature *sig;
4651 long alloc_size, pos, max_offset, cfa_offset;
4657 int tailcall_struct_index;
4659 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4662 sig = mono_method_signature (method);
4663 cfg->code_size = 512 + sig->param_count * 32;
4664 code = cfg->native_code = g_malloc (cfg->code_size);
4668 /* We currently emit unwind info for aot, but don't use it */
4669 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4671 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4672 ppc_mflr (code, ppc_r0);
4673 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4674 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4677 alloc_size = cfg->stack_offset;
4680 if (!method->save_lmf) {
4681 for (i = 31; i >= 13; --i) {
4682 if (cfg->used_int_regs & (1 << i)) {
4683 pos += sizeof (mgreg_t);
4687 pos += sizeof (MonoLMF);
4691 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4692 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4693 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4694 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4697 cfg->stack_usage = alloc_size;
4698 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4700 if (ppc_is_imm16 (-alloc_size)) {
4701 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4702 cfa_offset = alloc_size;
4703 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4704 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4707 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4708 ppc_load (code, ppc_r0, -alloc_size);
4709 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4710 cfa_offset = alloc_size;
4711 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4712 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4715 if (cfg->frame_reg != ppc_sp) {
4716 ppc_mr (code, cfg->frame_reg, ppc_sp);
4717 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4720 /* store runtime generic context */
4721 if (cfg->rgctx_var) {
4722 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4723 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4725 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4728 /* compute max_offset in order to use short forward jumps
4729 * we always do it on ppc because the immediate displacement
4730 * for jumps is too small
4733 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4735 bb->max_offset = max_offset;
4737 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4740 MONO_BB_FOR_EACH_INS (bb, ins)
4741 max_offset += ins_native_length (cfg, ins);
4744 /* load arguments allocated to register from the stack */
4747 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4749 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4750 ArgInfo *ainfo = &cinfo->ret;
4752 inst = cfg->vret_addr;
4755 if (ppc_is_imm16 (inst->inst_offset)) {
4756 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4758 ppc_load (code, ppc_r11, inst->inst_offset);
4759 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4763 tailcall_struct_index = 0;
4764 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4765 ArgInfo *ainfo = cinfo->args + i;
4766 inst = cfg->args [pos];
4768 if (cfg->verbose_level > 2)
4769 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4770 if (inst->opcode == OP_REGVAR) {
4771 if (ainfo->regtype == RegTypeGeneral)
4772 ppc_mr (code, inst->dreg, ainfo->reg);
4773 else if (ainfo->regtype == RegTypeFP)
4774 ppc_fmr (code, inst->dreg, ainfo->reg);
4775 else if (ainfo->regtype == RegTypeBase) {
4776 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4777 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4779 g_assert_not_reached ();
4781 if (cfg->verbose_level > 2)
4782 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4784 /* the argument should be put on the stack: FIXME handle size != word */
4785 if (ainfo->regtype == RegTypeGeneral) {
4786 switch (ainfo->size) {
4788 if (ppc_is_imm16 (inst->inst_offset)) {
4789 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4791 if (ppc_is_imm32 (inst->inst_offset)) {
4792 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4793 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4795 ppc_load (code, ppc_r11, inst->inst_offset);
4796 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4801 if (ppc_is_imm16 (inst->inst_offset)) {
4802 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4804 if (ppc_is_imm32 (inst->inst_offset)) {
4805 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4806 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4808 ppc_load (code, ppc_r11, inst->inst_offset);
4809 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4813 #ifdef __mono_ppc64__
4815 if (ppc_is_imm16 (inst->inst_offset)) {
4816 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4818 if (ppc_is_imm32 (inst->inst_offset)) {
4819 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4820 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4822 ppc_load (code, ppc_r11, inst->inst_offset);
4823 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4828 if (ppc_is_imm16 (inst->inst_offset)) {
4829 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4831 ppc_load (code, ppc_r11, inst->inst_offset);
4832 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4837 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4838 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4839 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4841 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4842 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4843 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4844 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4849 if (ppc_is_imm16 (inst->inst_offset)) {
4850 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4852 if (ppc_is_imm32 (inst->inst_offset)) {
4853 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4854 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4856 ppc_load (code, ppc_r11, inst->inst_offset);
4857 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4862 } else if (ainfo->regtype == RegTypeBase) {
4863 g_assert (ppc_is_imm16 (ainfo->offset));
4864 /* load the previous stack pointer in r11 */
4865 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4866 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4867 switch (ainfo->size) {
4869 if (ppc_is_imm16 (inst->inst_offset)) {
4870 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4872 if (ppc_is_imm32 (inst->inst_offset)) {
4873 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4874 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4876 ppc_load (code, ppc_r11, inst->inst_offset);
4877 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4882 if (ppc_is_imm16 (inst->inst_offset)) {
4883 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4885 if (ppc_is_imm32 (inst->inst_offset)) {
4886 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4887 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4889 ppc_load (code, ppc_r11, inst->inst_offset);
4890 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4894 #ifdef __mono_ppc64__
4896 if (ppc_is_imm16 (inst->inst_offset)) {
4897 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4899 if (ppc_is_imm32 (inst->inst_offset)) {
4900 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4901 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4903 ppc_load (code, ppc_r11, inst->inst_offset);
4904 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4909 if (ppc_is_imm16 (inst->inst_offset)) {
4910 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4912 ppc_load (code, ppc_r11, inst->inst_offset);
4913 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4918 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4919 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4920 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4921 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4922 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4924 /* use r12 to load the 2nd half of the long before we clobber r11. */
4925 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4926 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4927 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4928 ppc_stw (code, ppc_r0, 0, ppc_r11);
4929 ppc_stw (code, ppc_r12, 4, ppc_r11);
4934 if (ppc_is_imm16 (inst->inst_offset)) {
4935 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4937 if (ppc_is_imm32 (inst->inst_offset)) {
4938 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4939 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4941 ppc_load (code, ppc_r11, inst->inst_offset);
4942 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4947 } else if (ainfo->regtype == RegTypeFP) {
4948 g_assert (ppc_is_imm16 (inst->inst_offset));
4949 if (ainfo->size == 8)
4950 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4951 else if (ainfo->size == 4)
4952 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4954 g_assert_not_reached ();
4955 } else if (ainfo->regtype == RegTypeStructByVal) {
4956 int doffset = inst->inst_offset;
4960 g_assert (ppc_is_imm16 (inst->inst_offset));
4961 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4962 /* FIXME: what if there is no class? */
4963 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4964 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4965 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4968 * Darwin handles 1 and 2 byte
4969 * structs specially by
4970 * loading h/b into the arg
4971 * register. Only done for
4975 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4977 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4981 #ifdef __mono_ppc64__
4983 g_assert (cur_reg == 0);
4984 ppc_sldi (code, ppc_r0, ainfo->reg,
4985 (sizeof (gpointer) - ainfo->bytes) * 8);
4986 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
4990 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
4991 inst->inst_basereg);
4994 soffset += sizeof (gpointer);
4995 doffset += sizeof (gpointer);
4997 if (ainfo->vtsize) {
4998 /* FIXME: we need to do the shifting here, too */
5001 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5002 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5003 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5004 code = emit_memcpy (code, size - soffset,
5005 inst->inst_basereg, doffset,
5006 ppc_r11, ainfo->offset + soffset);
5008 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5009 inst->inst_basereg, doffset,
5010 ppc_r11, ainfo->offset + soffset);
5013 } else if (ainfo->regtype == RegTypeStructByAddr) {
5014 /* if it was originally a RegTypeBase */
5015 if (ainfo->offset) {
5016 /* load the previous stack pointer in r11 */
5017 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5018 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5020 ppc_mr (code, ppc_r11, ainfo->reg);
5023 if (cfg->tailcall_valuetype_addrs) {
5024 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5026 g_assert (ppc_is_imm16 (addr->inst_offset));
5027 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5029 tailcall_struct_index++;
5032 g_assert (ppc_is_imm16 (inst->inst_offset));
5033 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5034 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5036 g_assert_not_reached ();
5041 if (method->save_lmf) {
5042 if (lmf_pthread_key != -1) {
5043 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5044 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5045 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5047 if (cfg->compile_aot) {
5048 /* Compute the got address which is needed by the PLT entry */
5049 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5051 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5052 (gpointer)"mono_get_lmf_addr");
5053 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5054 ppc_load_func (code, ppc_r0, 0);
5055 ppc_mtlr (code, ppc_r0);
5061 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5062 /* lmf_offset is the offset from the previous stack pointer,
5063 * alloc_size is the total stack space allocated, so the offset
5064 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5065 * The pointer to the struct is put in ppc_r11 (new_lmf).
5066 * The callee-saved registers are already in the MonoLMF structure
5068 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5069 /* ppc_r3 is the result from mono_get_lmf_addr () */
5070 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5071 /* new_lmf->previous_lmf = *lmf_addr */
5072 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5073 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5074 /* *(lmf_addr) = r11 */
5075 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5076 /* save method info */
5077 if (cfg->compile_aot)
5079 ppc_load (code, ppc_r0, 0);
5081 ppc_load_ptr (code, ppc_r0, method);
5082 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5083 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5084 /* save the current IP */
5085 if (cfg->compile_aot) {
5087 ppc_mflr (code, ppc_r0);
5089 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5090 #ifdef __mono_ppc64__
5091 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5093 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5096 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5100 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5102 cfg->code_len = code - cfg->native_code;
5103 g_assert (cfg->code_len <= cfg->code_size);
5110 mono_arch_emit_epilog (MonoCompile *cfg)
5112 MonoMethod *method = cfg->method;
5114 int max_epilog_size = 16 + 20*4;
5117 if (cfg->method->save_lmf)
5118 max_epilog_size += 128;
5120 if (mono_jit_trace_calls != NULL)
5121 max_epilog_size += 50;
5123 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5124 max_epilog_size += 50;
5126 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5127 cfg->code_size *= 2;
5128 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5129 cfg->stat_code_reallocs++;
5133 * Keep in sync with OP_JMP
5135 code = cfg->native_code + cfg->code_len;
5137 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5138 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5142 if (method->save_lmf) {
5144 pos += sizeof (MonoLMF);
5146 /* save the frame reg in r8 */
5147 ppc_mr (code, ppc_r8, cfg->frame_reg);
5148 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5149 /* r5 = previous_lmf */
5150 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5152 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5153 /* *(lmf_addr) = previous_lmf */
5154 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5155 /* FIXME: speedup: there is no actual need to restore the registers if
5156 * we didn't actually change them (idea from Zoltan).
5159 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5161 /*for (i = 14; i < 32; i++) {
5162 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5164 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5165 /* use the saved copy of the frame reg in r8 */
5166 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5167 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5168 ppc_mtlr (code, ppc_r0);
5170 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5172 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5173 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5174 if (ppc_is_imm16 (return_offset)) {
5175 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5177 ppc_load (code, ppc_r11, return_offset);
5178 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5180 ppc_mtlr (code, ppc_r0);
5182 if (ppc_is_imm16 (cfg->stack_usage)) {
5183 int offset = cfg->stack_usage;
5184 for (i = 13; i <= 31; i++) {
5185 if (cfg->used_int_regs & (1 << i))
5186 offset -= sizeof (mgreg_t);
5188 if (cfg->frame_reg != ppc_sp)
5189 ppc_mr (code, ppc_r11, cfg->frame_reg);
5190 /* note r31 (possibly the frame register) is restored last */
5191 for (i = 13; i <= 31; i++) {
5192 if (cfg->used_int_regs & (1 << i)) {
5193 ppc_ldr (code, i, offset, cfg->frame_reg);
5194 offset += sizeof (mgreg_t);
5197 if (cfg->frame_reg != ppc_sp)
5198 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5200 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5202 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5203 if (cfg->used_int_regs) {
5204 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5205 for (i = 31; i >= 13; --i) {
5206 if (cfg->used_int_regs & (1 << i)) {
5207 pos += sizeof (mgreg_t);
5208 ppc_ldr (code, i, -pos, ppc_r11);
5211 ppc_mr (code, ppc_sp, ppc_r11);
5213 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5220 cfg->code_len = code - cfg->native_code;
5222 g_assert (cfg->code_len < cfg->code_size);
5225 #endif /* ifndef DISABLE_JIT */
5227 /* remove once throw_exception_by_name is eliminated */
5229 exception_id_by_name (const char *name)
5231 if (strcmp (name, "IndexOutOfRangeException") == 0)
5232 return MONO_EXC_INDEX_OUT_OF_RANGE;
5233 if (strcmp (name, "OverflowException") == 0)
5234 return MONO_EXC_OVERFLOW;
5235 if (strcmp (name, "ArithmeticException") == 0)
5236 return MONO_EXC_ARITHMETIC;
5237 if (strcmp (name, "DivideByZeroException") == 0)
5238 return MONO_EXC_DIVIDE_BY_ZERO;
5239 if (strcmp (name, "InvalidCastException") == 0)
5240 return MONO_EXC_INVALID_CAST;
5241 if (strcmp (name, "NullReferenceException") == 0)
5242 return MONO_EXC_NULL_REF;
5243 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5244 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5245 if (strcmp (name, "ArgumentException") == 0)
5246 return MONO_EXC_ARGUMENT;
5247 g_error ("Unknown intrinsic exception %s\n", name);
5253 mono_arch_emit_exceptions (MonoCompile *cfg)
5255 MonoJumpInfo *patch_info;
5258 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5259 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5260 int max_epilog_size = 50;
5262 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5263 exc_throw_pos [i] = NULL;
5264 exc_throw_found [i] = 0;
5267 /* count the number of exception infos */
5270 * make sure we have enough space for exceptions
5272 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5273 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5274 i = exception_id_by_name (patch_info->data.target);
5275 if (!exc_throw_found [i]) {
5276 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5277 exc_throw_found [i] = TRUE;
5279 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5280 max_epilog_size += 12;
5281 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5282 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5283 i = exception_id_by_name (ovfj->data.exception);
5284 if (!exc_throw_found [i]) {
5285 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5286 exc_throw_found [i] = TRUE;
5288 max_epilog_size += 8;
5292 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5293 cfg->code_size *= 2;
5294 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5295 cfg->stat_code_reallocs++;
5298 code = cfg->native_code + cfg->code_len;
5300 /* add code to raise exceptions */
5301 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5302 switch (patch_info->type) {
5303 case MONO_PATCH_INFO_BB_OVF: {
5304 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5305 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5306 /* patch the initial jump */
5307 ppc_patch (ip, code);
5308 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5310 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5311 /* jump back to the true target */
5313 ip = ovfj->data.bb->native_offset + cfg->native_code;
5314 ppc_patch (code - 4, ip);
5315 patch_info->type = MONO_PATCH_INFO_NONE;
5318 case MONO_PATCH_INFO_EXC_OVF: {
5319 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5320 MonoJumpInfo *newji;
5321 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5322 unsigned char *bcl = code;
5323 /* patch the initial jump: we arrived here with a call */
5324 ppc_patch (ip, code);
5325 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5327 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5328 /* patch the conditional jump to the right handler */
5329 /* make it processed next */
5330 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5331 newji->type = MONO_PATCH_INFO_EXC;
5332 newji->ip.i = bcl - cfg->native_code;
5333 newji->data.target = ovfj->data.exception;
5334 newji->next = patch_info->next;
5335 patch_info->next = newji;
5336 patch_info->type = MONO_PATCH_INFO_NONE;
5339 case MONO_PATCH_INFO_EXC: {
5340 MonoClass *exc_class;
5342 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5343 i = exception_id_by_name (patch_info->data.target);
5344 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5345 ppc_patch (ip, exc_throw_pos [i]);
5346 patch_info->type = MONO_PATCH_INFO_NONE;
5349 exc_throw_pos [i] = code;
5352 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5353 g_assert (exc_class);
5355 ppc_patch (ip, code);
5356 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5357 ppc_load (code, ppc_r3, exc_class->type_token);
5358 /* we got here from a conditional call, so the calling ip is set in lr */
5359 ppc_mflr (code, ppc_r4);
5360 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5361 patch_info->data.name = "mono_arch_throw_corlib_exception";
5362 patch_info->ip.i = code - cfg->native_code;
5363 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5364 ppc_load_func (code, ppc_r0, 0);
5365 ppc_mtctr (code, ppc_r0);
5366 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5378 cfg->code_len = code - cfg->native_code;
5380 g_assert (cfg->code_len <= cfg->code_size);
5386 try_offset_access (void *value, guint32 idx)
5388 register void* me __asm__ ("r2");
5389 void ***p = (void***)((char*)me + 284);
5390 int idx1 = idx / 32;
5391 int idx2 = idx % 32;
5394 if (value != p[idx1][idx2])
5401 setup_tls_access (void)
5403 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5404 size_t conf_size = 0;
5407 /* FIXME for darwin */
5408 guint32 *ins, *code;
5409 guint32 cmplwi_1023, li_0x48, blr_ins;
5413 tls_mode = TLS_MODE_FAILED;
5416 if (tls_mode == TLS_MODE_FAILED)
5418 if (g_getenv ("MONO_NO_TLS")) {
5419 tls_mode = TLS_MODE_FAILED;
5423 if (tls_mode == TLS_MODE_DETECT) {
5424 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5425 tls_mode = TLS_MODE_DARWIN_G4;
5426 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5427 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5428 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5429 tls_mode = TLS_MODE_NPTL;
5430 #elif !defined(TARGET_PS3)
5431 ins = (guint32*)pthread_getspecific;
5432 /* uncond branch to the real method */
5433 if ((*ins >> 26) == 18) {
5435 val = (*ins & ~3) << 6;
5439 ins = (guint32*)(long)val;
5441 ins = (guint32*) ((char*)ins + val);
5444 code = &cmplwi_1023;
5445 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5447 ppc_li (code, ppc_r4, 0x48);
5450 if (*ins == cmplwi_1023) {
5451 int found_lwz_284 = 0;
5453 for (ptk = 0; ptk < 20; ++ptk) {
5455 if (!*ins || *ins == blr_ins)
5457 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5462 if (!found_lwz_284) {
5463 tls_mode = TLS_MODE_FAILED;
5466 tls_mode = TLS_MODE_LTHREADS;
5467 } else if (*ins == li_0x48) {
5469 /* uncond branch to the real method */
5470 if ((*ins >> 26) == 18) {
5472 val = (*ins & ~3) << 6;
5476 ins = (guint32*)(long)val;
5478 ins = (guint32*) ((char*)ins + val);
5480 code = (guint32*)&val;
5481 ppc_li (code, ppc_r0, 0x7FF2);
5482 if (ins [1] == val) {
5483 /* Darwin on G4, implement */
5484 tls_mode = TLS_MODE_FAILED;
5487 code = (guint32*)&val;
5488 ppc_mfspr (code, ppc_r3, 104);
5489 if (ins [1] != val) {
5490 tls_mode = TLS_MODE_FAILED;
5493 tls_mode = TLS_MODE_DARWIN_G5;
5496 tls_mode = TLS_MODE_FAILED;
5500 tls_mode = TLS_MODE_FAILED;
5506 if (tls_mode == TLS_MODE_DETECT)
5507 tls_mode = TLS_MODE_FAILED;
5508 if (tls_mode == TLS_MODE_FAILED)
5510 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5511 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5515 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5516 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5517 if (lmf_pthread_key == -1) {
5518 guint32 ptk = mono_jit_tls_id;
5520 /*g_print ("MonoLMF at: %d\n", ptk);*/
5521 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5522 init_tls_failed = 1;
5525 lmf_pthread_key = ptk;
5534 mono_arch_finish_init (void)
5536 setup_tls_access ();
5540 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5544 #ifdef MONO_ARCH_HAVE_IMT
5546 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5548 #define LOADSTORE_SIZE 4
5549 #define JUMP_IMM_SIZE 12
5550 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5551 #define ENABLE_WRONG_METHOD_CHECK 0
5554 * LOCKING: called with the domain lock held
5557 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5558 gpointer fail_tramp)
5562 guint8 *code, *start;
5564 for (i = 0; i < count; ++i) {
5565 MonoIMTCheckItem *item = imt_entries [i];
5566 if (item->is_equals) {
5567 if (item->check_target_idx) {
5568 if (!item->compare_done)
5569 item->chunk_size += CMP_SIZE;
5570 if (item->has_target_code)
5571 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5573 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5576 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5577 if (!item->has_target_code)
5578 item->chunk_size += LOADSTORE_SIZE;
5580 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5581 #if ENABLE_WRONG_METHOD_CHECK
5582 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5587 item->chunk_size += CMP_SIZE + BR_SIZE;
5588 imt_entries [item->check_target_idx]->compare_done = TRUE;
5590 size += item->chunk_size;
5592 /* the initial load of the vtable address */
5593 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5595 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5597 code = mono_domain_code_reserve (domain, size);
5602 * We need to save and restore r11 because it might be
5603 * used by the caller as the vtable register, so
5604 * clobbering it will trip up the magic trampoline.
5606 * FIXME: Get rid of this by making sure that r11 is
5607 * not used as the vtable register in interface calls.
5609 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5610 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5612 for (i = 0; i < count; ++i) {
5613 MonoIMTCheckItem *item = imt_entries [i];
5614 item->code_target = code;
5615 if (item->is_equals) {
5616 if (item->check_target_idx) {
5617 if (!item->compare_done) {
5618 ppc_load (code, ppc_r0, (gsize)item->key);
5619 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5621 item->jmp_code = code;
5622 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5623 if (item->has_target_code) {
5624 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5626 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5627 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5629 ppc_mtctr (code, ppc_r0);
5630 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5633 ppc_load (code, ppc_r0, (gulong)item->key);
5634 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5635 item->jmp_code = code;
5636 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5637 if (item->has_target_code) {
5638 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5641 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5642 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5644 ppc_mtctr (code, ppc_r0);
5645 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5646 ppc_patch (item->jmp_code, code);
5647 ppc_load_ptr (code, ppc_r0, fail_tramp);
5648 ppc_mtctr (code, ppc_r0);
5649 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5650 item->jmp_code = NULL;
5652 /* enable the commented code to assert on wrong method */
5653 #if ENABLE_WRONG_METHOD_CHECK
5654 ppc_load (code, ppc_r0, (guint32)item->key);
5655 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5656 item->jmp_code = code;
5657 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5659 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5660 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5661 ppc_mtctr (code, ppc_r0);
5662 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5663 #if ENABLE_WRONG_METHOD_CHECK
5664 ppc_patch (item->jmp_code, code);
5666 item->jmp_code = NULL;
5671 ppc_load (code, ppc_r0, (gulong)item->key);
5672 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5673 item->jmp_code = code;
5674 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5677 /* patch the branches to get to the target items */
5678 for (i = 0; i < count; ++i) {
5679 MonoIMTCheckItem *item = imt_entries [i];
5680 if (item->jmp_code) {
5681 if (item->check_target_idx) {
5682 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5688 mono_stats.imt_thunks_size += code - start;
5689 g_assert (code - start <= size);
5690 mono_arch_flush_icache (start, size);
5695 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5697 mgreg_t *r = (mgreg_t*)regs;
5699 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5704 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5706 mgreg_t *r = (mgreg_t*)regs;
5708 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5712 mono_arch_get_cie_program (void)
5716 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5722 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5729 mono_arch_print_tree (MonoInst *tree, int arity)
5735 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5738 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5740 g_assert (reg >= ppc_r13);
5742 return ctx->regs [reg - ppc_r13];
5746 mono_arch_get_patch_offset (guint8 *code)
5752 * mono_aot_emit_load_got_addr:
5754 * Emit code to load the got address.
5755 * On PPC, the result is placed into r30.
5758 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5761 ppc_mflr (code, ppc_r30);
5763 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5765 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5766 /* arch_emit_got_address () patches this */
5767 #if defined(TARGET_POWERPC64)
5773 ppc_load32 (code, ppc_r0, 0);
5774 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5781 * mono_ppc_emit_load_aotconst:
5783 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5784 * TARGET from the mscorlib GOT in full-aot code.
5785 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5789 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5791 /* Load the mscorlib got address */
5792 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5793 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5794 /* arch_emit_got_access () patches this */
5795 ppc_load32 (code, ppc_r0, 0);
5796 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5801 /* Soft Debug support */
5802 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5809 * mono_arch_set_breakpoint:
5811 * See mini-amd64.c for docs.
5814 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5817 guint8 *orig_code = code;
5819 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5820 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5822 g_assert (code - orig_code == BREAKPOINT_SIZE);
5824 mono_arch_flush_icache (orig_code, code - orig_code);
5828 * mono_arch_clear_breakpoint:
5830 * See mini-amd64.c for docs.
5833 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5838 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5841 mono_arch_flush_icache (ip, code - ip);
5845 * mono_arch_is_breakpoint_event:
5847 * See mini-amd64.c for docs.
5850 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5852 siginfo_t* sinfo = (siginfo_t*) info;
5853 /* Sometimes the address is off by 4 */
5854 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5861 * mono_arch_skip_breakpoint:
5863 * See mini-amd64.c for docs.
5866 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5868 /* skip the ldptr */
5869 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5877 * mono_arch_start_single_stepping:
5879 * See mini-amd64.c for docs.
5882 mono_arch_start_single_stepping (void)
5884 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5888 * mono_arch_stop_single_stepping:
5890 * See mini-amd64.c for docs.
5893 mono_arch_stop_single_stepping (void)
5895 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5899 * mono_arch_is_single_step_event:
5901 * See mini-amd64.c for docs.
5904 mono_arch_is_single_step_event (void *info, void *sigctx)
5906 siginfo_t* sinfo = (siginfo_t*) info;
5907 /* Sometimes the address is off by 4 */
5908 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5915 * mono_arch_skip_single_step:
5917 * See mini-amd64.c for docs.
5920 mono_arch_skip_single_step (MonoContext *ctx)
5922 /* skip the ldptr */
5923 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5927 * mono_arch_create_seq_point_info:
5929 * See mini-amd64.c for docs.
5932 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5939 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5941 ext->lmf.previous_lmf = prev_lmf;
5942 /* Mark that this is a MonoLMFExt */
5943 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5944 ext->lmf.ebp = (gssize)ext;
5950 mono_arch_opcode_supported (int opcode)
5953 case OP_ATOMIC_CAS_I4:
5954 #ifdef TARGET_POWERPC64
5955 case OP_ATOMIC_ADD_I4: /* Yes, really - see cpu-ppc(64).md. */
5956 case OP_ATOMIC_ADD_I8:
5957 case OP_ATOMIC_CAS_I8: