2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-proclib.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-ppc.h>
23 #ifdef TARGET_POWERPC64
24 #include "cpu-ppc64.h"
31 #include <sys/sysctl.h>
37 #define FORCE_INDIR_CALL 1
48 /* cpu_hw_caps contains the flags defined below */
49 static int cpu_hw_caps = 0;
50 static int cachelinesize = 0;
51 static int cachelineinc = 0;
53 PPC_ICACHE_SNOOP = 1 << 0,
54 PPC_MULTIPLE_LS_UNITS = 1 << 1,
55 PPC_SMP_CAPABLE = 1 << 2,
58 PPC_MOVE_FPR_GPR = 1 << 5,
62 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
64 /* This mutex protects architecture specific caches */
65 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
67 static mono_mutex_t mini_arch_mutex;
69 int mono_exc_esp_offset = 0;
70 static int tls_mode = TLS_MODE_DETECT;
71 static int lmf_pthread_key = -1;
74 * The code generated for sequence points reads from this location, which is
75 * made read-only when single stepping is enabled.
77 static gpointer ss_trigger_page;
79 /* Enabled breakpoints read from this trigger page */
80 static gpointer bp_trigger_page;
83 offsets_from_pthread_key (guint32 key, int *offset2)
87 *offset2 = idx2 * sizeof (gpointer);
88 return 284 + idx1 * sizeof (gpointer);
91 #define emit_linuxthreads_tls(code,dreg,key) do {\
93 off1 = offsets_from_pthread_key ((key), &off2); \
94 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
95 ppc_ldptr ((code), (dreg), off2, (dreg)); \
98 #define emit_darwing5_tls(code,dreg,key) do {\
99 int off1 = 0x48 + key * sizeof (gpointer); \
100 ppc_mfspr ((code), (dreg), 104); \
101 ppc_ldptr ((code), (dreg), off1, (dreg)); \
104 /* FIXME: ensure the sc call preserves all but r3 */
105 #define emit_darwing4_tls(code,dreg,key) do {\
106 int off1 = 0x48 + key * sizeof (gpointer); \
107 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r12, ppc_r3); \
108 ppc_li ((code), ppc_r0, 0x7FF2); \
110 ppc_lwz ((code), (dreg), off1, ppc_r3); \
111 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r12); \
114 #ifdef PPC_THREAD_PTR_REG
115 #define emit_nptl_tls(code,dreg,key) do { \
117 int off2 = key >> 15; \
118 if ((off2 == 0) || (off2 == -1)) { \
119 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
121 int off3 = (off2 + 1) > 1; \
122 ppc_addis ((code), ppc_r12, PPC_THREAD_PTR_REG, off3); \
123 ppc_ldptr ((code), (dreg), off1, ppc_r12); \
127 #define emit_nptl_tls(code,dreg,key) do { \
128 g_assert_not_reached (); \
132 #define emit_tls_access(code,dreg,key) do { \
133 switch (tls_mode) { \
134 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
135 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
137 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
138 default: g_assert_not_reached (); \
142 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
144 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
145 inst->type = STACK_R8; \
147 inst->inst_p0 = (void*)(addr); \
148 mono_bblock_add_inst (cfg->cbb, inst); \
152 mono_arch_regname (int reg) {
153 static const char rnames[][4] = {
154 "r0", "sp", "r2", "r3", "r4",
155 "r5", "r6", "r7", "r8", "r9",
156 "r10", "r11", "r12", "r13", "r14",
157 "r15", "r16", "r17", "r18", "r19",
158 "r20", "r21", "r22", "r23", "r24",
159 "r25", "r26", "r27", "r28", "r29",
162 if (reg >= 0 && reg < 32)
168 mono_arch_fregname (int reg) {
169 static const char rnames[][4] = {
170 "f0", "f1", "f2", "f3", "f4",
171 "f5", "f6", "f7", "f8", "f9",
172 "f10", "f11", "f12", "f13", "f14",
173 "f15", "f16", "f17", "f18", "f19",
174 "f20", "f21", "f22", "f23", "f24",
175 "f25", "f26", "f27", "f28", "f29",
178 if (reg >= 0 && reg < 32)
183 /* this function overwrites r0, r11, r12 */
185 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
187 /* unrolled, use the counter in big */
188 if (size > sizeof (gpointer) * 5) {
189 long shifted = size / SIZEOF_VOID_P;
190 guint8 *copy_loop_start, *copy_loop_jump;
192 ppc_load (code, ppc_r0, shifted);
193 ppc_mtctr (code, ppc_r0);
194 //g_assert (sreg == ppc_r12);
195 ppc_addi (code, ppc_r11, dreg, (doffset - sizeof (gpointer)));
196 ppc_addi (code, ppc_r12, sreg, (soffset - sizeof (gpointer)));
197 copy_loop_start = code;
198 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
200 copy_loop_jump = code;
201 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
202 ppc_patch (copy_loop_jump, copy_loop_start);
203 size -= shifted * sizeof (gpointer);
204 doffset = soffset = 0;
207 #ifdef __mono_ppc64__
208 /* the hardware has multiple load/store units and the move is long
209 enough to use more then one register, then use load/load/store/store
210 to execute 2 instructions per cycle. */
211 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
213 ppc_ldptr (code, ppc_r0, soffset, sreg);
214 ppc_ldptr (code, ppc_r11, soffset+8, sreg);
215 ppc_stptr (code, ppc_r0, doffset, dreg);
216 ppc_stptr (code, ppc_r11, doffset+8, dreg);
223 ppc_ldr (code, ppc_r0, soffset, sreg);
224 ppc_str (code, ppc_r0, doffset, dreg);
230 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r11) && (sreg != ppc_r11)) {
232 ppc_lwz (code, ppc_r0, soffset, sreg);
233 ppc_lwz (code, ppc_r11, soffset+4, sreg);
234 ppc_stw (code, ppc_r0, doffset, dreg);
235 ppc_stw (code, ppc_r11, doffset+4, dreg);
243 ppc_lwz (code, ppc_r0, soffset, sreg);
244 ppc_stw (code, ppc_r0, doffset, dreg);
250 ppc_lhz (code, ppc_r0, soffset, sreg);
251 ppc_sth (code, ppc_r0, doffset, dreg);
257 ppc_lbz (code, ppc_r0, soffset, sreg);
258 ppc_stb (code, ppc_r0, doffset, dreg);
267 * mono_arch_get_argument_info:
268 * @csig: a method signature
269 * @param_count: the number of parameters to consider
270 * @arg_info: an array to store the result infos
272 * Gathers information on parameters such as size, alignment and
273 * padding. arg_info should be large enought to hold param_count + 1 entries.
275 * Returns the size of the activation frame.
278 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
284 int k, frame_size = 0;
285 int size, align, pad;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
293 arg_info [0].offset = offset;
296 frame_size += sizeof (gpointer);
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
307 size = mini_type_stack_size (csig->params [k], &align);
309 /* ignore alignment for now */
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
318 arg_info [k + 1].offset = offset;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
330 #ifdef __mono_ppc64__
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
367 return is_load_sequence (&code [-6]);
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
380 #define MAX_ARCH_DELEGATE_PARAMS 7
383 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot)
385 guint8 *code, *start;
388 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
390 start = code = mono_global_codeman_reserve (size);
392 code = mono_ppc_create_pre_code_ftnptr (code);
394 /* Replace the this argument with the target */
395 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
396 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
397 /* it's a function descriptor */
398 /* Can't use ldptr as it doesn't work with r0 */
399 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
401 ppc_mtctr (code, ppc_r0);
402 ppc_ldptr (code, ppc_r3, MONO_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
403 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
405 g_assert ((code - start) <= size);
407 mono_arch_flush_icache (start, size);
411 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
412 start = code = mono_global_codeman_reserve (size);
414 code = mono_ppc_create_pre_code_ftnptr (code);
416 ppc_ldptr (code, ppc_r0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
417 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
418 /* it's a function descriptor */
419 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
421 ppc_mtctr (code, ppc_r0);
422 /* slide down the arguments */
423 for (i = 0; i < param_count; ++i) {
424 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
428 g_assert ((code - start) <= size);
430 mono_arch_flush_icache (start, size);
434 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
436 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
437 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
445 mono_arch_get_delegate_invoke_impls (void)
451 get_delegate_invoke_impl (&info, TRUE, 0, TRUE);
452 res = g_slist_prepend (res, info);
454 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
455 get_delegate_invoke_impl (&info, FALSE, i, TRUE);
456 res = g_slist_prepend (res, info);
463 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
465 guint8 *code, *start;
467 /* FIXME: Support more cases */
468 if (MONO_TYPE_ISSTRUCT (sig->ret))
472 static guint8* cached = NULL;
478 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
481 start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE);
482 mono_tramp_info_register (info, NULL);
484 mono_memory_barrier ();
488 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
491 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
493 for (i = 0; i < sig->param_count; ++i)
494 if (!mono_is_regsize_var (sig->params [i]))
498 code = cache [sig->param_count];
503 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
504 start = mono_aot_get_trampoline (name);
508 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE);
509 mono_tramp_info_register (info, NULL);
512 mono_memory_barrier ();
514 cache [sig->param_count] = start;
520 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
526 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
528 mgreg_t *r = (mgreg_t*)regs;
530 return (gpointer)(gsize)r [ppc_r3];
538 #define MAX_AUX_ENTRIES 128
540 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
541 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
543 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
545 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
546 #define ISA_64 0x40000000
548 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
549 #define ISA_MOVE_FPR_GPR 0x00000200
551 * Initialize the cpu to execute managed code.
554 mono_arch_cpu_init (void)
559 * Initialize architecture specific code.
562 mono_arch_init (void)
564 #if defined(MONO_CROSS_COMPILE)
565 #elif defined(__APPLE__)
567 size_t len = sizeof (cachelinesize);
570 mib [1] = HW_CACHELINE;
572 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
576 cachelineinc = cachelinesize;
578 #elif defined(__linux__)
579 AuxVec vec [MAX_AUX_ENTRIES];
580 int i, vec_entries = 0;
581 /* sadly this will work only with 2.6 kernels... */
582 FILE* f = fopen ("/proc/self/auxv", "rb");
585 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
589 for (i = 0; i < vec_entries; i++) {
590 int type = vec [i].type;
592 if (type == 19) { /* AT_DCACHEBSIZE */
593 cachelinesize = vec [i].value;
597 #elif defined(G_COMPILER_CODEWARRIOR)
601 //#error Need a way to get cache line size
604 if (mono_hwcap_ppc_has_icache_snoop)
605 cpu_hw_caps |= PPC_ICACHE_SNOOP;
607 if (mono_hwcap_ppc_is_isa_2x)
608 cpu_hw_caps |= PPC_ISA_2X;
610 if (mono_hwcap_ppc_is_isa_64)
611 cpu_hw_caps |= PPC_ISA_64;
613 if (mono_hwcap_ppc_has_move_fpr_gpr)
614 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
616 if (mono_hwcap_ppc_has_multiple_ls_units)
617 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
623 cachelineinc = cachelinesize;
625 if (mono_cpu_count () > 1)
626 cpu_hw_caps |= PPC_SMP_CAPABLE;
628 mono_mutex_init_recursive (&mini_arch_mutex);
630 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
631 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
632 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
634 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
638 * Cleanup architecture specific code.
641 mono_arch_cleanup (void)
643 mono_mutex_destroy (&mini_arch_mutex);
647 * This function returns the optimizations supported on this cpu.
650 mono_arch_cpu_optimizations (guint32 *exclude_mask)
654 /* no ppc-specific optimizations yet */
660 * This function test for all SIMD functions supported.
662 * Returns a bitmask corresponding to all supported versions.
666 mono_arch_cpu_enumerate_simd_versions (void)
668 /* SIMD is currently unimplemented */
672 #ifdef __mono_ppc64__
673 #define CASE_PPC32(c)
674 #define CASE_PPC64(c) case c:
676 #define CASE_PPC32(c) case c:
677 #define CASE_PPC64(c)
681 is_regsize_var (MonoType *t) {
684 t = mini_get_underlying_type (t);
688 CASE_PPC64 (MONO_TYPE_I8)
689 CASE_PPC64 (MONO_TYPE_U8)
693 case MONO_TYPE_FNPTR:
695 case MONO_TYPE_OBJECT:
696 case MONO_TYPE_STRING:
697 case MONO_TYPE_CLASS:
698 case MONO_TYPE_SZARRAY:
699 case MONO_TYPE_ARRAY:
701 case MONO_TYPE_GENERICINST:
702 if (!mono_type_generic_inst_is_valuetype (t))
705 case MONO_TYPE_VALUETYPE:
713 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
718 for (i = 0; i < cfg->num_varinfo; i++) {
719 MonoInst *ins = cfg->varinfo [i];
720 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
723 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
726 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
729 /* we can only allocate 32 bit values */
730 if (is_regsize_var (ins->inst_vtype)) {
731 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
732 g_assert (i == vmv->idx);
733 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
739 #endif /* ifndef DISABLE_JIT */
742 mono_arch_get_global_int_regs (MonoCompile *cfg)
746 if (cfg->frame_reg != ppc_sp)
748 /* ppc_r13 is used by the system on PPC EABI */
749 for (i = 14; i < top; ++i) {
751 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
752 * since the trampolines can clobber r12.
754 if (!(cfg->compile_aot && i == 29))
755 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
762 * mono_arch_regalloc_cost:
764 * Return the cost, in number of memory references, of the action of
765 * allocating the variable VMV into a register during global register
769 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
776 mono_arch_flush_icache (guint8 *code, gint size)
778 #ifdef MONO_CROSS_COMPILE
781 guint8 *endp, *start;
785 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
786 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
787 #if defined(G_COMPILER_CODEWARRIOR)
788 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
789 for (p = start; p < endp; p += cachelineinc) {
793 for (p = start; p < endp; p += cachelineinc) {
799 for (p = start; p < endp; p += cachelineinc) {
810 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
811 * The sync is required to insure that the store queue is completely empty.
812 * While the icbi performs no cache operations, icbi/isync is required to
813 * kill local prefetch.
815 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
817 asm ("icbi 0,%0;" : : "r"(code) : "memory");
821 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
822 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
823 for (p = start; p < endp; p += cachelineinc) {
824 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
827 for (p = start; p < endp; p += cachelineinc) {
828 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
833 for (p = start; p < endp; p += cachelineinc) {
834 /* for ISA2.0+ implementations we should not need any extra sync between the
835 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
836 * So I am not sure which chip had this problem but its not an issue on
837 * of the ISA V2 chips.
839 if (cpu_hw_caps & PPC_ISA_2X)
840 asm ("icbi 0,%0;" : : "r"(p) : "memory");
842 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
844 if (!(cpu_hw_caps & PPC_ISA_2X))
852 mono_arch_flush_register_windows (void)
857 #define ALWAYS_ON_STACK(s) s
858 #define FP_ALSO_IN_REG(s) s
860 #ifdef __mono_ppc64__
861 #define ALWAYS_ON_STACK(s) s
862 #define FP_ALSO_IN_REG(s) s
864 #define ALWAYS_ON_STACK(s)
865 #define FP_ALSO_IN_REG(s)
867 #define ALIGN_DOUBLES
876 RegTypeFPStructByVal, // For the v2 ABI, floats should be passed in FRs instead of GRs. Only valid for ABI v2!
881 guint32 vtsize; /* in param area */
883 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal/RegTypeFPStructByVal */
884 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
885 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal/RegTypeFPStructByVal */
886 guint8 bytes : 4; /* size in bytes - only valid for
887 RegTypeStructByVal/RegTypeFPStructByVal if the struct fits
888 in one word, otherwise it's 0*/
897 gboolean vtype_retaddr;
905 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
907 #ifdef __mono_ppc64__
912 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
913 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
914 ainfo->reg = ppc_sp; /* in the caller */
915 ainfo->regtype = RegTypeBase;
916 *stack_size += sizeof (gpointer);
918 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
922 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
924 //*stack_size += (*stack_size % 8);
926 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
927 ainfo->reg = ppc_sp; /* in the caller */
928 ainfo->regtype = RegTypeBase;
935 ALWAYS_ON_STACK (*stack_size += 8);
943 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
945 has_only_a_r48_field (MonoClass *klass)
949 gboolean have_field = FALSE;
951 while ((f = mono_class_get_fields (klass, &iter))) {
952 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
955 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
966 get_call_info (MonoMethodSignature *sig)
968 guint i, fr, gr, pstart;
969 int n = sig->hasthis + sig->param_count;
970 MonoType *simpletype;
971 guint32 stack_size = 0;
972 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
973 gboolean is_pinvoke = sig->pinvoke;
975 fr = PPC_FIRST_FPARG_REG;
976 gr = PPC_FIRST_ARG_REG;
978 /* FIXME: handle returning a struct */
979 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
980 cinfo->vtype_retaddr = TRUE;
986 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
987 * the first argument, allowing 'this' to be always passed in the first arg reg.
988 * Also do this if the first argument is a reference type, since virtual calls
989 * are sometimes made using calli without sig->hasthis set, like in the delegate
992 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
994 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
997 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1001 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1002 cinfo->struct_ret = cinfo->ret.reg;
1003 cinfo->vret_arg_index = 1;
1007 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1011 if (cinfo->vtype_retaddr) {
1012 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1013 cinfo->struct_ret = cinfo->ret.reg;
1017 DEBUG(printf("params: %d\n", sig->param_count));
1018 for (i = pstart; i < sig->param_count; ++i) {
1019 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1020 /* Prevent implicit arguments and sig_cookie from
1021 being passed in registers */
1022 gr = PPC_LAST_ARG_REG + 1;
1023 /* FIXME: don't we have to set fr, too? */
1024 /* Emit the signature cookie just before the implicit arguments */
1025 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1027 DEBUG(printf("param %d: ", i));
1028 if (sig->params [i]->byref) {
1029 DEBUG(printf("byref\n"));
1030 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1034 simpletype = mini_get_underlying_type (sig->params [i]);
1035 switch (simpletype->type) {
1036 case MONO_TYPE_BOOLEAN:
1039 cinfo->args [n].size = 1;
1040 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1043 case MONO_TYPE_CHAR:
1046 cinfo->args [n].size = 2;
1047 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1052 cinfo->args [n].size = 4;
1053 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1059 case MONO_TYPE_FNPTR:
1060 case MONO_TYPE_CLASS:
1061 case MONO_TYPE_OBJECT:
1062 case MONO_TYPE_STRING:
1063 case MONO_TYPE_SZARRAY:
1064 case MONO_TYPE_ARRAY:
1065 cinfo->args [n].size = sizeof (gpointer);
1066 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1069 case MONO_TYPE_GENERICINST:
1070 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1071 cinfo->args [n].size = sizeof (gpointer);
1072 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1077 case MONO_TYPE_VALUETYPE:
1078 case MONO_TYPE_TYPEDBYREF: {
1080 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1081 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1082 size = sizeof (MonoTypedRef);
1083 else if (is_pinvoke)
1084 size = mono_class_native_size (klass, NULL);
1086 size = mono_class_value_size (klass, NULL);
1088 #if defined(__APPLE__) || (defined(__mono_ppc64__) && !PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS)
1089 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1090 cinfo->args [n].size = size;
1092 /* It was 7, now it is 8 in LinuxPPC */
1093 if (fr <= PPC_LAST_FPARG_REG) {
1094 cinfo->args [n].regtype = RegTypeFP;
1095 cinfo->args [n].reg = fr;
1097 FP_ALSO_IN_REG (gr ++);
1098 #if !defined(__mono_ppc64__)
1100 FP_ALSO_IN_REG (gr ++);
1102 ALWAYS_ON_STACK (stack_size += size);
1104 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1105 cinfo->args [n].regtype = RegTypeBase;
1106 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1113 DEBUG(printf ("load %d bytes struct\n",
1114 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1116 #if PPC_PASS_STRUCTS_BY_VALUE
1118 int align_size = size;
1120 int rest = PPC_LAST_ARG_REG - gr + 1;
1123 #if PPC_PASS_SMALL_FLOAT_STRUCTS_IN_FR_REGS
1126 gboolean is_all_floats = mini_type_is_hfa (sig->params [i], &mbr_cnt, &mbr_size);
1128 if (is_all_floats && (mbr_cnt <= 8)) {
1129 rest = PPC_LAST_FPARG_REG - fr + 1;
1131 // Pass small (<= 8 member) structures entirely made up of either float or double members
1132 // in FR registers. There have to be at least mbr_cnt registers left.
1133 if (is_all_floats &&
1134 (rest >= mbr_cnt) &&
1137 n_in_regs = MIN (rest, nregs);
1138 cinfo->args [n].regtype = RegTypeFPStructByVal;
1139 cinfo->args [n].vtregs = n_in_regs;
1140 cinfo->args [n].size = mbr_size;
1141 cinfo->args [n].vtsize = nregs - n_in_regs;
1142 cinfo->args [n].reg = fr;
1144 if (mbr_size == 4) {
1146 FP_ALSO_IN_REG (gr += (n_in_regs+1)/2);
1149 FP_ALSO_IN_REG (gr += (n_in_regs));
1154 align_size += (sizeof (gpointer) - 1);
1155 align_size &= ~(sizeof (gpointer) - 1);
1156 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1157 n_in_regs = MIN (rest, nregs);
1161 /* FIXME: check this */
1162 if (size >= 3 && size % 4 != 0)
1165 cinfo->args [n].regtype = RegTypeStructByVal;
1166 cinfo->args [n].vtregs = n_in_regs;
1167 cinfo->args [n].size = n_in_regs;
1168 cinfo->args [n].vtsize = nregs - n_in_regs;
1169 cinfo->args [n].reg = gr;
1173 #ifdef __mono_ppc64__
1174 if (nregs == 1 && is_pinvoke)
1175 cinfo->args [n].bytes = size;
1178 cinfo->args [n].bytes = 0;
1179 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1180 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1181 stack_size += nregs * sizeof (gpointer);
1184 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1185 cinfo->args [n].regtype = RegTypeStructByAddr;
1186 cinfo->args [n].vtsize = size;
1193 cinfo->args [n].size = 8;
1194 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1198 cinfo->args [n].size = 4;
1200 /* It was 7, now it is 8 in LinuxPPC */
1201 if (fr <= PPC_LAST_FPARG_REG
1202 // For non-native vararg calls the parms must go in storage
1203 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1205 cinfo->args [n].regtype = RegTypeFP;
1206 cinfo->args [n].reg = fr;
1208 FP_ALSO_IN_REG (gr ++);
1209 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1211 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1212 cinfo->args [n].regtype = RegTypeBase;
1213 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1214 stack_size += SIZEOF_REGISTER;
1219 cinfo->args [n].size = 8;
1220 /* It was 7, now it is 8 in LinuxPPC */
1221 if (fr <= PPC_LAST_FPARG_REG
1222 // For non-native vararg calls the parms must go in storage
1223 && !(!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1225 cinfo->args [n].regtype = RegTypeFP;
1226 cinfo->args [n].reg = fr;
1228 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1229 ALWAYS_ON_STACK (stack_size += 8);
1231 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1232 cinfo->args [n].regtype = RegTypeBase;
1233 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1239 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1244 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1245 /* Prevent implicit arguments and sig_cookie from
1246 being passed in registers */
1247 gr = PPC_LAST_ARG_REG + 1;
1248 /* Emit the signature cookie just before the implicit arguments */
1249 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1253 simpletype = mini_get_underlying_type (sig->ret);
1254 switch (simpletype->type) {
1255 case MONO_TYPE_BOOLEAN:
1260 case MONO_TYPE_CHAR:
1266 case MONO_TYPE_FNPTR:
1267 case MONO_TYPE_CLASS:
1268 case MONO_TYPE_OBJECT:
1269 case MONO_TYPE_SZARRAY:
1270 case MONO_TYPE_ARRAY:
1271 case MONO_TYPE_STRING:
1272 cinfo->ret.reg = ppc_r3;
1276 cinfo->ret.reg = ppc_r3;
1280 cinfo->ret.reg = ppc_f1;
1281 cinfo->ret.regtype = RegTypeFP;
1283 case MONO_TYPE_GENERICINST:
1284 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1285 cinfo->ret.reg = ppc_r3;
1289 case MONO_TYPE_VALUETYPE:
1291 case MONO_TYPE_TYPEDBYREF:
1292 case MONO_TYPE_VOID:
1295 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1299 /* align stack size to 16 */
1300 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1301 stack_size = (stack_size + 15) & ~15;
1303 cinfo->stack_usage = stack_size;
1308 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1314 c1 = get_call_info (caller_sig);
1315 c2 = get_call_info (callee_sig);
1316 res = c1->stack_usage >= c2->stack_usage;
1317 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1318 /* An address on the callee's stack is passed as the first argument */
1320 for (i = 0; i < c2->nargs; ++i) {
1321 if (c2->args [i].regtype == RegTypeStructByAddr)
1322 /* An address on the callee's stack is passed as the argument */
1327 if (!mono_debug_count ())
1338 * Set var information according to the calling convention. ppc version.
1339 * The locals var stuff should most likely be split in another method.
1342 mono_arch_allocate_vars (MonoCompile *m)
1344 MonoMethodSignature *sig;
1345 MonoMethodHeader *header;
1347 int i, offset, size, align, curinst;
1348 int frame_reg = ppc_sp;
1350 guint32 locals_stack_size, locals_stack_align;
1352 m->flags |= MONO_CFG_HAS_SPILLUP;
1354 /* allow room for the vararg method args: void* and long/double */
1355 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1356 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1357 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1358 * call convs needs to be handled this way.
1360 if (m->flags & MONO_CFG_HAS_VARARGS)
1361 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1362 /* gtk-sharp and other broken code will dllimport vararg functions even with
1363 * non-varargs signatures. Since there is little hope people will get this right
1364 * we assume they won't.
1366 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1367 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1372 * We use the frame register also for any method that has
1373 * exception clauses. This way, when the handlers are called,
1374 * the code will reference local variables using the frame reg instead of
1375 * the stack pointer: if we had to restore the stack pointer, we'd
1376 * corrupt the method frames that are already on the stack (since
1377 * filters get called before stack unwinding happens) when the filter
1378 * code would call any method (this also applies to finally etc.).
1380 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1381 frame_reg = ppc_r31;
1382 m->frame_reg = frame_reg;
1383 if (frame_reg != ppc_sp) {
1384 m->used_int_regs |= 1 << frame_reg;
1387 sig = mono_method_signature (m->method);
1391 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1392 m->ret->opcode = OP_REGVAR;
1393 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1395 /* FIXME: handle long values? */
1396 switch (mini_get_underlying_type (sig->ret)->type) {
1397 case MONO_TYPE_VOID:
1401 m->ret->opcode = OP_REGVAR;
1402 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1405 m->ret->opcode = OP_REGVAR;
1406 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1410 /* local vars are at a positive offset from the stack pointer */
1412 * also note that if the function uses alloca, we use ppc_r31
1413 * to point at the local variables.
1415 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1416 /* align the offset to 16 bytes: not sure this is needed here */
1418 //offset &= ~(16 - 1);
1420 /* add parameter area size for called functions */
1421 offset += m->param_area;
1423 offset &= ~(16 - 1);
1425 /* allow room to save the return value */
1426 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1429 /* the MonoLMF structure is stored just below the stack pointer */
1432 /* this stuff should not be needed on ppc and the new jit,
1433 * because a call on ppc to the handlers doesn't change the
1434 * stack pointer and the jist doesn't manipulate the stack pointer
1435 * for operations involving valuetypes.
1437 /* reserve space to store the esp */
1438 offset += sizeof (gpointer);
1440 /* this is a global constant */
1441 mono_exc_esp_offset = offset;
1444 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1445 offset += sizeof(gpointer) - 1;
1446 offset &= ~(sizeof(gpointer) - 1);
1448 m->vret_addr->opcode = OP_REGOFFSET;
1449 m->vret_addr->inst_basereg = frame_reg;
1450 m->vret_addr->inst_offset = offset;
1452 if (G_UNLIKELY (m->verbose_level > 1)) {
1453 printf ("vret_addr =");
1454 mono_print_ins (m->vret_addr);
1457 offset += sizeof(gpointer);
1460 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1461 if (locals_stack_align) {
1462 offset += (locals_stack_align - 1);
1463 offset &= ~(locals_stack_align - 1);
1465 for (i = m->locals_start; i < m->num_varinfo; i++) {
1466 if (offsets [i] != -1) {
1467 MonoInst *inst = m->varinfo [i];
1468 inst->opcode = OP_REGOFFSET;
1469 inst->inst_basereg = frame_reg;
1470 inst->inst_offset = offset + offsets [i];
1472 g_print ("allocating local %d (%s) to %d\n",
1473 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1477 offset += locals_stack_size;
1481 inst = m->args [curinst];
1482 if (inst->opcode != OP_REGVAR) {
1483 inst->opcode = OP_REGOFFSET;
1484 inst->inst_basereg = frame_reg;
1485 offset += sizeof (gpointer) - 1;
1486 offset &= ~(sizeof (gpointer) - 1);
1487 inst->inst_offset = offset;
1488 offset += sizeof (gpointer);
1493 for (i = 0; i < sig->param_count; ++i) {
1494 inst = m->args [curinst];
1495 if (inst->opcode != OP_REGVAR) {
1496 inst->opcode = OP_REGOFFSET;
1497 inst->inst_basereg = frame_reg;
1499 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1500 inst->backend.is_pinvoke = 1;
1502 size = mono_type_size (sig->params [i], &align);
1504 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1505 size = align = sizeof (gpointer);
1507 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1508 * they are saved using std in the prolog.
1510 align = sizeof (gpointer);
1511 offset += align - 1;
1512 offset &= ~(align - 1);
1513 inst->inst_offset = offset;
1519 /* some storage for fp conversions */
1522 m->arch.fp_conv_var_offset = offset;
1525 /* align the offset to 16 bytes */
1527 offset &= ~(16 - 1);
1530 m->stack_offset = offset;
1532 if (sig->call_convention == MONO_CALL_VARARG) {
1533 CallInfo *cinfo = get_call_info (m->method->signature);
1535 m->sig_cookie = cinfo->sig_cookie.offset;
1542 mono_arch_create_vars (MonoCompile *cfg)
1544 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1546 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1547 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1551 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1552 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1556 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1558 int sig_reg = mono_alloc_ireg (cfg);
1560 /* FIXME: Add support for signature tokens to AOT */
1561 cfg->disable_aot = TRUE;
1563 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1564 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1565 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1569 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1572 MonoMethodSignature *sig;
1576 sig = call->signature;
1577 n = sig->param_count + sig->hasthis;
1579 cinfo = get_call_info (sig);
1581 for (i = 0; i < n; ++i) {
1582 ArgInfo *ainfo = cinfo->args + i;
1585 if (i >= sig->hasthis)
1586 t = sig->params [i - sig->hasthis];
1588 t = &mono_defaults.int_class->byval_arg;
1589 t = mini_get_underlying_type (t);
1591 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1592 emit_sig_cookie (cfg, call, cinfo);
1594 in = call->args [i];
1596 if (ainfo->regtype == RegTypeGeneral) {
1597 #ifndef __mono_ppc64__
1598 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1599 MONO_INST_NEW (cfg, ins, OP_MOVE);
1600 ins->dreg = mono_alloc_ireg (cfg);
1601 ins->sreg1 = in->dreg + 1;
1602 MONO_ADD_INS (cfg->cbb, ins);
1603 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1605 MONO_INST_NEW (cfg, ins, OP_MOVE);
1606 ins->dreg = mono_alloc_ireg (cfg);
1607 ins->sreg1 = in->dreg + 2;
1608 MONO_ADD_INS (cfg->cbb, ins);
1609 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1613 MONO_INST_NEW (cfg, ins, OP_MOVE);
1614 ins->dreg = mono_alloc_ireg (cfg);
1615 ins->sreg1 = in->dreg;
1616 MONO_ADD_INS (cfg->cbb, ins);
1618 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1620 } else if (ainfo->regtype == RegTypeStructByAddr) {
1621 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1622 ins->opcode = OP_OUTARG_VT;
1623 ins->sreg1 = in->dreg;
1624 ins->klass = in->klass;
1625 ins->inst_p0 = call;
1626 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1627 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1628 MONO_ADD_INS (cfg->cbb, ins);
1629 } else if (ainfo->regtype == RegTypeStructByVal) {
1630 /* this is further handled in mono_arch_emit_outarg_vt () */
1631 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1632 ins->opcode = OP_OUTARG_VT;
1633 ins->sreg1 = in->dreg;
1634 ins->klass = in->klass;
1635 ins->inst_p0 = call;
1636 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1637 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1638 MONO_ADD_INS (cfg->cbb, ins);
1639 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1640 /* this is further handled in mono_arch_emit_outarg_vt () */
1641 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1642 ins->opcode = OP_OUTARG_VT;
1643 ins->sreg1 = in->dreg;
1644 ins->klass = in->klass;
1645 ins->inst_p0 = call;
1646 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1647 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1648 MONO_ADD_INS (cfg->cbb, ins);
1649 cfg->flags |= MONO_CFG_HAS_FPOUT;
1650 } else if (ainfo->regtype == RegTypeBase) {
1651 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1652 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1653 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1654 if (t->type == MONO_TYPE_R8)
1655 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1657 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1659 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1661 } else if (ainfo->regtype == RegTypeFP) {
1662 if (t->type == MONO_TYPE_VALUETYPE) {
1663 /* this is further handled in mono_arch_emit_outarg_vt () */
1664 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1665 ins->opcode = OP_OUTARG_VT;
1666 ins->sreg1 = in->dreg;
1667 ins->klass = in->klass;
1668 ins->inst_p0 = call;
1669 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1670 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1671 MONO_ADD_INS (cfg->cbb, ins);
1673 cfg->flags |= MONO_CFG_HAS_FPOUT;
1675 int dreg = mono_alloc_freg (cfg);
1677 if (ainfo->size == 4) {
1678 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1680 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1682 ins->sreg1 = in->dreg;
1683 MONO_ADD_INS (cfg->cbb, ins);
1686 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1687 cfg->flags |= MONO_CFG_HAS_FPOUT;
1690 g_assert_not_reached ();
1694 /* Emit the signature cookie in the case that there is no
1695 additional argument */
1696 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1697 emit_sig_cookie (cfg, call, cinfo);
1699 if (cinfo->struct_ret) {
1702 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1703 vtarg->sreg1 = call->vret_var->dreg;
1704 vtarg->dreg = mono_alloc_preg (cfg);
1705 MONO_ADD_INS (cfg->cbb, vtarg);
1707 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1710 call->stack_usage = cinfo->stack_usage;
1711 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1712 cfg->flags |= MONO_CFG_HAS_CALLS;
1720 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1722 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1723 ArgInfo *ainfo = ins->inst_p1;
1724 int ovf_size = ainfo->vtsize;
1725 int doffset = ainfo->offset;
1726 int i, soffset, dreg;
1728 if (ainfo->regtype == RegTypeStructByVal) {
1735 * Darwin pinvokes needs some special handling for 1
1736 * and 2 byte arguments
1738 g_assert (ins->klass);
1739 if (call->signature->pinvoke)
1740 size = mono_class_native_size (ins->klass, NULL);
1741 if (size == 2 || size == 1) {
1742 int tmpr = mono_alloc_ireg (cfg);
1744 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1746 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1747 dreg = mono_alloc_ireg (cfg);
1748 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1749 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1752 for (i = 0; i < ainfo->vtregs; ++i) {
1753 dreg = mono_alloc_ireg (cfg);
1754 #if G_BYTE_ORDER == G_BIG_ENDIAN
1755 int antipadding = 0;
1758 antipadding = sizeof (gpointer) - ainfo->bytes;
1760 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1764 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1766 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1767 soffset += sizeof (gpointer);
1770 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1771 } else if (ainfo->regtype == RegTypeFPStructByVal) {
1773 for (i = 0; i < ainfo->vtregs; ++i) {
1774 int tmpr = mono_alloc_freg (cfg);
1775 if (ainfo->size == 4)
1776 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, soffset);
1778 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, soffset);
1779 dreg = mono_alloc_freg (cfg);
1780 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1781 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg+i, TRUE);
1782 soffset += ainfo->size;
1785 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1786 } else if (ainfo->regtype == RegTypeFP) {
1787 int tmpr = mono_alloc_freg (cfg);
1788 if (ainfo->size == 4)
1789 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1791 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1792 dreg = mono_alloc_freg (cfg);
1793 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1794 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1796 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1800 /* FIXME: alignment? */
1801 if (call->signature->pinvoke) {
1802 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1803 vtcopy->backend.is_pinvoke = 1;
1805 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1808 g_assert (ovf_size > 0);
1810 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1811 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1814 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1816 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1821 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1823 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1826 #ifndef __mono_ppc64__
1827 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1830 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1831 ins->sreg1 = val->dreg + 1;
1832 ins->sreg2 = val->dreg + 2;
1833 MONO_ADD_INS (cfg->cbb, ins);
1837 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1838 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1842 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1845 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1847 mono_arch_is_inst_imm (gint64 imm)
1852 #endif /* DISABLE_JIT */
1855 * Allow tracing to work with this interface (with an optional argument)
1859 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1863 ppc_load_ptr (code, ppc_r3, cfg->method);
1864 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1865 ppc_load_func (code, PPC_CALL_REG, func);
1866 ppc_mtlr (code, PPC_CALL_REG);
1880 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1883 int save_mode = SAVE_NONE;
1885 MonoMethod *method = cfg->method;
1886 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
1887 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1891 offset = code - cfg->native_code;
1892 /* we need about 16 instructions */
1893 if (offset > (cfg->code_size - 16 * 4)) {
1894 cfg->code_size *= 2;
1895 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1896 code = cfg->native_code + offset;
1900 case MONO_TYPE_VOID:
1901 /* special case string .ctor icall */
1902 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1903 save_mode = SAVE_ONE;
1905 save_mode = SAVE_NONE;
1907 #ifndef __mono_ppc64__
1910 save_mode = SAVE_TWO;
1915 save_mode = SAVE_FP;
1917 case MONO_TYPE_VALUETYPE:
1918 save_mode = SAVE_STRUCT;
1921 save_mode = SAVE_ONE;
1925 switch (save_mode) {
1927 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1928 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1929 if (enable_arguments) {
1930 ppc_mr (code, ppc_r5, ppc_r4);
1931 ppc_mr (code, ppc_r4, ppc_r3);
1935 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1936 if (enable_arguments) {
1937 ppc_mr (code, ppc_r4, ppc_r3);
1941 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1942 if (enable_arguments) {
1943 /* FIXME: what reg? */
1944 ppc_fmr (code, ppc_f3, ppc_f1);
1945 /* FIXME: use 8 byte load on PPC64 */
1946 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1947 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1951 if (enable_arguments) {
1952 /* FIXME: get the actual address */
1953 ppc_mr (code, ppc_r4, ppc_r3);
1954 // FIXME: Support the new v2 ABI!
1962 ppc_load_ptr (code, ppc_r3, cfg->method);
1963 ppc_load_func (code, PPC_CALL_REG, func);
1964 ppc_mtlr (code, PPC_CALL_REG);
1967 switch (save_mode) {
1969 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1970 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1973 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1976 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1986 * Conditional branches have a small offset, so if it is likely overflowed,
1987 * we do a branch to the end of the method (uncond branches have much larger
1988 * offsets) where we perform the conditional and jump back unconditionally.
1989 * It's slightly slower, since we add two uncond branches, but it's very simple
1990 * with the current patch implementation and such large methods are likely not
1991 * going to be perf critical anyway.
1996 const char *exception;
2003 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
2004 if (0 && ins->inst_true_bb->native_offset) { \
2005 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
2007 int br_disp = ins->inst_true_bb->max_offset - offset; \
2008 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2009 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2010 ovfj->data.bb = ins->inst_true_bb; \
2011 ovfj->ip_offset = 0; \
2012 ovfj->b0_cond = (b0); \
2013 ovfj->b1_cond = (b1); \
2014 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
2017 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2018 ppc_bc (code, (b0), (b1), 0); \
2022 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
2024 /* emit an exception if condition is fail
2026 * We assign the extra code used to throw the implicit exceptions
2027 * to cfg->bb_exit as far as the big branch handling is concerned
2029 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
2031 int br_disp = cfg->bb_exit->max_offset - offset; \
2032 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
2033 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
2034 ovfj->data.exception = (exc_name); \
2035 ovfj->ip_offset = code - cfg->native_code; \
2036 ovfj->b0_cond = (b0); \
2037 ovfj->b1_cond = (b1); \
2038 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
2040 cfg->bb_exit->max_offset += 24; \
2042 mono_add_patch_info (cfg, code - cfg->native_code, \
2043 MONO_PATCH_INFO_EXC, exc_name); \
2044 ppc_bcl (code, (b0), (b1), 0); \
2048 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
2051 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2056 normalize_opcode (int opcode)
2059 #ifndef __mono_ilp32__
2060 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2061 return OP_LOAD_MEMBASE;
2062 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2063 return OP_LOAD_MEMINDEX;
2064 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2065 return OP_STORE_MEMBASE_REG;
2066 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2067 return OP_STORE_MEMBASE_IMM;
2068 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2069 return OP_STORE_MEMINDEX;
2071 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2073 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2074 return OP_SHR_UN_IMM;
2081 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2083 MonoInst *ins, *n, *last_ins = NULL;
2085 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2086 switch (normalize_opcode (ins->opcode)) {
2088 /* remove unnecessary multiplication with 1 */
2089 if (ins->inst_imm == 1) {
2090 if (ins->dreg != ins->sreg1) {
2091 ins->opcode = OP_MOVE;
2093 MONO_DELETE_INS (bb, ins);
2097 int power2 = mono_is_power_of_two (ins->inst_imm);
2099 ins->opcode = OP_SHL_IMM;
2100 ins->inst_imm = power2;
2104 case OP_LOAD_MEMBASE:
2106 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2107 * OP_LOAD_MEMBASE offset(basereg), reg
2109 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2110 ins->inst_basereg == last_ins->inst_destbasereg &&
2111 ins->inst_offset == last_ins->inst_offset) {
2112 if (ins->dreg == last_ins->sreg1) {
2113 MONO_DELETE_INS (bb, ins);
2116 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2117 ins->opcode = OP_MOVE;
2118 ins->sreg1 = last_ins->sreg1;
2122 * Note: reg1 must be different from the basereg in the second load
2123 * OP_LOAD_MEMBASE offset(basereg), reg1
2124 * OP_LOAD_MEMBASE offset(basereg), reg2
2126 * OP_LOAD_MEMBASE offset(basereg), reg1
2127 * OP_MOVE reg1, reg2
2129 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2130 ins->inst_basereg != last_ins->dreg &&
2131 ins->inst_basereg == last_ins->inst_basereg &&
2132 ins->inst_offset == last_ins->inst_offset) {
2134 if (ins->dreg == last_ins->dreg) {
2135 MONO_DELETE_INS (bb, ins);
2138 ins->opcode = OP_MOVE;
2139 ins->sreg1 = last_ins->dreg;
2142 //g_assert_not_reached ();
2146 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2147 * OP_LOAD_MEMBASE offset(basereg), reg
2149 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2150 * OP_ICONST reg, imm
2152 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2153 ins->inst_basereg == last_ins->inst_destbasereg &&
2154 ins->inst_offset == last_ins->inst_offset) {
2155 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2156 ins->opcode = OP_ICONST;
2157 ins->inst_c0 = last_ins->inst_imm;
2158 g_assert_not_reached (); // check this rule
2162 case OP_LOADU1_MEMBASE:
2163 case OP_LOADI1_MEMBASE:
2164 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2165 ins->inst_basereg == last_ins->inst_destbasereg &&
2166 ins->inst_offset == last_ins->inst_offset) {
2167 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2168 ins->sreg1 = last_ins->sreg1;
2171 case OP_LOADU2_MEMBASE:
2172 case OP_LOADI2_MEMBASE:
2173 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2174 ins->inst_basereg == last_ins->inst_destbasereg &&
2175 ins->inst_offset == last_ins->inst_offset) {
2176 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2177 ins->sreg1 = last_ins->sreg1;
2180 #ifdef __mono_ppc64__
2181 case OP_LOADU4_MEMBASE:
2182 case OP_LOADI4_MEMBASE:
2183 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2184 ins->inst_basereg == last_ins->inst_destbasereg &&
2185 ins->inst_offset == last_ins->inst_offset) {
2186 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2187 ins->sreg1 = last_ins->sreg1;
2192 ins->opcode = OP_MOVE;
2196 if (ins->dreg == ins->sreg1) {
2197 MONO_DELETE_INS (bb, ins);
2201 * OP_MOVE sreg, dreg
2202 * OP_MOVE dreg, sreg
2204 if (last_ins && last_ins->opcode == OP_MOVE &&
2205 ins->sreg1 == last_ins->dreg &&
2206 ins->dreg == last_ins->sreg1) {
2207 MONO_DELETE_INS (bb, ins);
2215 bb->last_ins = last_ins;
2219 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2221 switch (ins->opcode) {
2222 case OP_ICONV_TO_R_UN: {
2223 // This value is OK as-is for both big and little endian because of how it is stored
2224 static const guint64 adjust_val = 0x4330000000000000ULL;
2225 int msw_reg = mono_alloc_ireg (cfg);
2226 int adj_reg = mono_alloc_freg (cfg);
2227 int tmp_reg = mono_alloc_freg (cfg);
2228 int basereg = ppc_sp;
2230 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2231 if (!ppc_is_imm16 (offset + 4)) {
2232 basereg = mono_alloc_ireg (cfg);
2233 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2235 #if G_BYTE_ORDER == G_BIG_ENDIAN
2236 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2237 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2239 // For little endian the words are reversed
2240 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, msw_reg);
2241 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, ins->sreg1);
2243 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2244 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2246 ins->opcode = OP_NOP;
2249 #ifndef __mono_ppc64__
2250 case OP_ICONV_TO_R4:
2251 case OP_ICONV_TO_R8: {
2252 /* If we have a PPC_FEATURE_64 machine we can avoid
2253 this and use the fcfid instruction. Otherwise
2254 on an old 32-bit chip and we have to do this the
2256 if (!(cpu_hw_caps & PPC_ISA_64)) {
2257 /* FIXME: change precision for CEE_CONV_R4 */
2258 static const guint64 adjust_val = 0x4330000080000000ULL;
2259 int msw_reg = mono_alloc_ireg (cfg);
2260 int xored = mono_alloc_ireg (cfg);
2261 int adj_reg = mono_alloc_freg (cfg);
2262 int tmp_reg = mono_alloc_freg (cfg);
2263 int basereg = ppc_sp;
2265 if (!ppc_is_imm16 (offset + 4)) {
2266 basereg = mono_alloc_ireg (cfg);
2267 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2269 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2270 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2271 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2272 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2273 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2274 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2276 if (ins->opcode == OP_ICONV_TO_R4)
2277 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2278 ins->opcode = OP_NOP;
2284 int msw_reg = mono_alloc_ireg (cfg);
2285 int basereg = ppc_sp;
2287 if (!ppc_is_imm16 (offset + 4)) {
2288 basereg = mono_alloc_ireg (cfg);
2289 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2291 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2292 #if G_BYTE_ORDER == G_BIG_ENDIAN
2293 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2295 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset+4);
2297 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2298 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2299 ins->opcode = OP_NOP;
2302 #ifdef __mono_ppc64__
2304 case OP_IADD_OVF_UN:
2306 int shifted1_reg = mono_alloc_ireg (cfg);
2307 int shifted2_reg = mono_alloc_ireg (cfg);
2308 int result_shifted_reg = mono_alloc_ireg (cfg);
2310 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2311 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2312 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2313 if (ins->opcode == OP_IADD_OVF_UN)
2314 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2316 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2317 ins->opcode = OP_NOP;
2324 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2326 switch (ins->opcode) {
2328 /* ADC sets the condition code */
2329 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2330 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2333 case OP_LADD_OVF_UN:
2334 /* ADC sets the condition code */
2335 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2336 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2340 /* SBB sets the condition code */
2341 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2345 case OP_LSUB_OVF_UN:
2346 /* SBB sets the condition code */
2347 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2348 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2352 /* From gcc generated code */
2353 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2354 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2363 * the branch_b0_table should maintain the order of these
2377 branch_b0_table [] = {
2392 branch_b1_table [] = {
2406 #define NEW_INS(cfg,dest,op) do { \
2407 MONO_INST_NEW((cfg), (dest), (op)); \
2408 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2412 map_to_reg_reg_op (int op)
2421 case OP_COMPARE_IMM:
2423 case OP_ICOMPARE_IMM:
2425 case OP_LCOMPARE_IMM:
2441 case OP_LOAD_MEMBASE:
2442 return OP_LOAD_MEMINDEX;
2443 case OP_LOADI4_MEMBASE:
2444 return OP_LOADI4_MEMINDEX;
2445 case OP_LOADU4_MEMBASE:
2446 return OP_LOADU4_MEMINDEX;
2447 case OP_LOADI8_MEMBASE:
2448 return OP_LOADI8_MEMINDEX;
2449 case OP_LOADU1_MEMBASE:
2450 return OP_LOADU1_MEMINDEX;
2451 case OP_LOADI2_MEMBASE:
2452 return OP_LOADI2_MEMINDEX;
2453 case OP_LOADU2_MEMBASE:
2454 return OP_LOADU2_MEMINDEX;
2455 case OP_LOADI1_MEMBASE:
2456 return OP_LOADI1_MEMINDEX;
2457 case OP_LOADR4_MEMBASE:
2458 return OP_LOADR4_MEMINDEX;
2459 case OP_LOADR8_MEMBASE:
2460 return OP_LOADR8_MEMINDEX;
2461 case OP_STOREI1_MEMBASE_REG:
2462 return OP_STOREI1_MEMINDEX;
2463 case OP_STOREI2_MEMBASE_REG:
2464 return OP_STOREI2_MEMINDEX;
2465 case OP_STOREI4_MEMBASE_REG:
2466 return OP_STOREI4_MEMINDEX;
2467 case OP_STOREI8_MEMBASE_REG:
2468 return OP_STOREI8_MEMINDEX;
2469 case OP_STORE_MEMBASE_REG:
2470 return OP_STORE_MEMINDEX;
2471 case OP_STORER4_MEMBASE_REG:
2472 return OP_STORER4_MEMINDEX;
2473 case OP_STORER8_MEMBASE_REG:
2474 return OP_STORER8_MEMINDEX;
2475 case OP_STORE_MEMBASE_IMM:
2476 return OP_STORE_MEMBASE_REG;
2477 case OP_STOREI1_MEMBASE_IMM:
2478 return OP_STOREI1_MEMBASE_REG;
2479 case OP_STOREI2_MEMBASE_IMM:
2480 return OP_STOREI2_MEMBASE_REG;
2481 case OP_STOREI4_MEMBASE_IMM:
2482 return OP_STOREI4_MEMBASE_REG;
2483 case OP_STOREI8_MEMBASE_IMM:
2484 return OP_STOREI8_MEMBASE_REG;
2486 return mono_op_imm_to_op (op);
2489 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2491 #define compare_opcode_is_unsigned(opcode) \
2492 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2493 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2494 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2495 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2496 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2497 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2498 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2499 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2502 * Remove from the instruction list the instructions that can't be
2503 * represented with very simple instructions with no register
2507 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2509 MonoInst *ins, *next, *temp, *last_ins = NULL;
2512 MONO_BB_FOR_EACH_INS (bb, ins) {
2514 switch (ins->opcode) {
2515 case OP_IDIV_UN_IMM:
2518 case OP_IREM_UN_IMM:
2519 CASE_PPC64 (OP_LREM_IMM) {
2520 NEW_INS (cfg, temp, OP_ICONST);
2521 temp->inst_c0 = ins->inst_imm;
2522 temp->dreg = mono_alloc_ireg (cfg);
2523 ins->sreg2 = temp->dreg;
2524 if (ins->opcode == OP_IDIV_IMM)
2525 ins->opcode = OP_IDIV;
2526 else if (ins->opcode == OP_IREM_IMM)
2527 ins->opcode = OP_IREM;
2528 else if (ins->opcode == OP_IDIV_UN_IMM)
2529 ins->opcode = OP_IDIV_UN;
2530 else if (ins->opcode == OP_IREM_UN_IMM)
2531 ins->opcode = OP_IREM_UN;
2532 else if (ins->opcode == OP_LREM_IMM)
2533 ins->opcode = OP_LREM;
2535 /* handle rem separately */
2540 CASE_PPC64 (OP_LREM)
2541 CASE_PPC64 (OP_LREM_UN) {
2543 /* we change a rem dest, src1, src2 to
2544 * div temp1, src1, src2
2545 * mul temp2, temp1, src2
2546 * sub dest, src1, temp2
2548 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2549 NEW_INS (cfg, mul, OP_IMUL);
2550 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2551 ins->opcode = OP_ISUB;
2553 NEW_INS (cfg, mul, OP_LMUL);
2554 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2555 ins->opcode = OP_LSUB;
2557 temp->sreg1 = ins->sreg1;
2558 temp->sreg2 = ins->sreg2;
2559 temp->dreg = mono_alloc_ireg (cfg);
2560 mul->sreg1 = temp->dreg;
2561 mul->sreg2 = ins->sreg2;
2562 mul->dreg = mono_alloc_ireg (cfg);
2563 ins->sreg2 = mul->dreg;
2567 CASE_PPC64 (OP_LADD_IMM)
2570 if (!ppc_is_imm16 (ins->inst_imm)) {
2571 NEW_INS (cfg, temp, OP_ICONST);
2572 temp->inst_c0 = ins->inst_imm;
2573 temp->dreg = mono_alloc_ireg (cfg);
2574 ins->sreg2 = temp->dreg;
2575 ins->opcode = map_to_reg_reg_op (ins->opcode);
2579 CASE_PPC64 (OP_LSUB_IMM)
2581 if (!ppc_is_imm16 (-ins->inst_imm)) {
2582 NEW_INS (cfg, temp, OP_ICONST);
2583 temp->inst_c0 = ins->inst_imm;
2584 temp->dreg = mono_alloc_ireg (cfg);
2585 ins->sreg2 = temp->dreg;
2586 ins->opcode = map_to_reg_reg_op (ins->opcode);
2598 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2599 #ifdef __mono_ppc64__
2600 if (ins->inst_imm & 0xffffffff00000000ULL)
2604 NEW_INS (cfg, temp, OP_ICONST);
2605 temp->inst_c0 = ins->inst_imm;
2606 temp->dreg = mono_alloc_ireg (cfg);
2607 ins->sreg2 = temp->dreg;
2608 ins->opcode = map_to_reg_reg_op (ins->opcode);
2617 NEW_INS (cfg, temp, OP_ICONST);
2618 temp->inst_c0 = ins->inst_imm;
2619 temp->dreg = mono_alloc_ireg (cfg);
2620 ins->sreg2 = temp->dreg;
2621 ins->opcode = map_to_reg_reg_op (ins->opcode);
2623 case OP_COMPARE_IMM:
2624 case OP_ICOMPARE_IMM:
2625 CASE_PPC64 (OP_LCOMPARE_IMM)
2627 /* Branch opts can eliminate the branch */
2628 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2629 ins->opcode = OP_NOP;
2633 if (compare_opcode_is_unsigned (next->opcode)) {
2634 if (!ppc_is_uimm16 (ins->inst_imm)) {
2635 NEW_INS (cfg, temp, OP_ICONST);
2636 temp->inst_c0 = ins->inst_imm;
2637 temp->dreg = mono_alloc_ireg (cfg);
2638 ins->sreg2 = temp->dreg;
2639 ins->opcode = map_to_reg_reg_op (ins->opcode);
2642 if (!ppc_is_imm16 (ins->inst_imm)) {
2643 NEW_INS (cfg, temp, OP_ICONST);
2644 temp->inst_c0 = ins->inst_imm;
2645 temp->dreg = mono_alloc_ireg (cfg);
2646 ins->sreg2 = temp->dreg;
2647 ins->opcode = map_to_reg_reg_op (ins->opcode);
2653 if (ins->inst_imm == 1) {
2654 ins->opcode = OP_MOVE;
2657 if (ins->inst_imm == 0) {
2658 ins->opcode = OP_ICONST;
2662 imm = mono_is_power_of_two (ins->inst_imm);
2664 ins->opcode = OP_SHL_IMM;
2665 ins->inst_imm = imm;
2668 if (!ppc_is_imm16 (ins->inst_imm)) {
2669 NEW_INS (cfg, temp, OP_ICONST);
2670 temp->inst_c0 = ins->inst_imm;
2671 temp->dreg = mono_alloc_ireg (cfg);
2672 ins->sreg2 = temp->dreg;
2673 ins->opcode = map_to_reg_reg_op (ins->opcode);
2676 case OP_LOCALLOC_IMM:
2677 NEW_INS (cfg, temp, OP_ICONST);
2678 temp->inst_c0 = ins->inst_imm;
2679 temp->dreg = mono_alloc_ireg (cfg);
2680 ins->sreg1 = temp->dreg;
2681 ins->opcode = OP_LOCALLOC;
2683 case OP_LOAD_MEMBASE:
2684 case OP_LOADI4_MEMBASE:
2685 CASE_PPC64 (OP_LOADI8_MEMBASE)
2686 case OP_LOADU4_MEMBASE:
2687 case OP_LOADI2_MEMBASE:
2688 case OP_LOADU2_MEMBASE:
2689 case OP_LOADI1_MEMBASE:
2690 case OP_LOADU1_MEMBASE:
2691 case OP_LOADR4_MEMBASE:
2692 case OP_LOADR8_MEMBASE:
2693 case OP_STORE_MEMBASE_REG:
2694 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2695 case OP_STOREI4_MEMBASE_REG:
2696 case OP_STOREI2_MEMBASE_REG:
2697 case OP_STOREI1_MEMBASE_REG:
2698 case OP_STORER4_MEMBASE_REG:
2699 case OP_STORER8_MEMBASE_REG:
2700 /* we can do two things: load the immed in a register
2701 * and use an indexed load, or see if the immed can be
2702 * represented as an ad_imm + a load with a smaller offset
2703 * that fits. We just do the first for now, optimize later.
2705 if (ppc_is_imm16 (ins->inst_offset))
2707 NEW_INS (cfg, temp, OP_ICONST);
2708 temp->inst_c0 = ins->inst_offset;
2709 temp->dreg = mono_alloc_ireg (cfg);
2710 ins->sreg2 = temp->dreg;
2711 ins->opcode = map_to_reg_reg_op (ins->opcode);
2713 case OP_STORE_MEMBASE_IMM:
2714 case OP_STOREI1_MEMBASE_IMM:
2715 case OP_STOREI2_MEMBASE_IMM:
2716 case OP_STOREI4_MEMBASE_IMM:
2717 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2718 NEW_INS (cfg, temp, OP_ICONST);
2719 temp->inst_c0 = ins->inst_imm;
2720 temp->dreg = mono_alloc_ireg (cfg);
2721 ins->sreg1 = temp->dreg;
2722 ins->opcode = map_to_reg_reg_op (ins->opcode);
2724 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2727 if (cfg->compile_aot) {
2728 /* Keep these in the aot case */
2731 NEW_INS (cfg, temp, OP_ICONST);
2732 temp->inst_c0 = (gulong)ins->inst_p0;
2733 temp->dreg = mono_alloc_ireg (cfg);
2734 ins->inst_basereg = temp->dreg;
2735 ins->inst_offset = 0;
2736 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2738 /* make it handle the possibly big ins->inst_offset
2739 * later optimize to use lis + load_membase
2745 bb->last_ins = last_ins;
2746 bb->max_vreg = cfg->next_vreg;
2750 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2752 long offset = cfg->arch.fp_conv_var_offset;
2754 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2755 #ifdef __mono_ppc64__
2757 ppc_fctidz (code, ppc_f0, sreg);
2762 ppc_fctiwz (code, ppc_f0, sreg);
2765 if (ppc_is_imm16 (offset + sub_offset)) {
2766 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2768 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2770 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2772 ppc_load (code, dreg, offset);
2773 ppc_add (code, dreg, dreg, cfg->frame_reg);
2774 ppc_stfd (code, ppc_f0, 0, dreg);
2776 ppc_ldr (code, dreg, sub_offset, dreg);
2778 ppc_lwz (code, dreg, sub_offset, dreg);
2782 ppc_andid (code, dreg, dreg, 0xff);
2784 ppc_andid (code, dreg, dreg, 0xffff);
2785 #ifdef __mono_ppc64__
2787 ppc_clrldi (code, dreg, dreg, 32);
2791 ppc_extsb (code, dreg, dreg);
2793 ppc_extsh (code, dreg, dreg);
2794 #ifdef __mono_ppc64__
2796 ppc_extsw (code, dreg, dreg);
2804 const guchar *target;
2809 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2812 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2813 #ifdef __mono_ppc64__
2814 g_assert_not_reached ();
2816 PatchData *pdata = (PatchData*)user_data;
2817 guchar *code = data;
2818 guint32 *thunks = data;
2819 guint32 *endthunks = (guint32*)(code + bsize);
2823 int difflow, diffhigh;
2825 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2826 difflow = (char*)pdata->code - (char*)thunks;
2827 diffhigh = (char*)pdata->code - (char*)endthunks;
2828 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2831 templ = (guchar*)load;
2832 ppc_load_sequence (templ, ppc_r0, pdata->target);
2834 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2835 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2836 while (thunks < endthunks) {
2837 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2838 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2839 ppc_patch (pdata->code, (guchar*)thunks);
2842 static int num_thunks = 0;
2844 if ((num_thunks % 20) == 0)
2845 g_print ("num_thunks lookup: %d\n", num_thunks);
2848 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2849 /* found a free slot instead: emit thunk */
2850 code = (guchar*)thunks;
2851 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2852 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2853 ppc_mtctr (code, ppc_r0);
2854 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2855 mono_arch_flush_icache ((guchar*)thunks, 16);
2857 ppc_patch (pdata->code, (guchar*)thunks);
2860 static int num_thunks = 0;
2862 if ((num_thunks % 20) == 0)
2863 g_print ("num_thunks: %d\n", num_thunks);
2867 /* skip 16 bytes, the size of the thunk */
2871 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2878 handle_thunk (int absolute, guchar *code, const guchar *target) {
2879 MonoDomain *domain = mono_domain_get ();
2883 pdata.target = target;
2884 pdata.absolute = absolute;
2887 mono_domain_lock (domain);
2888 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2891 /* this uses the first available slot */
2893 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2895 mono_domain_unlock (domain);
2897 if (pdata.found != 1)
2898 g_print ("thunk failed for %p from %p\n", target, code);
2899 g_assert (pdata.found == 1);
2903 patch_ins (guint8 *code, guint32 ins)
2905 *(guint32*)code = ins;
2906 mono_arch_flush_icache (code, 4);
2910 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2912 guint32 ins = *(guint32*)code;
2913 guint32 prim = ins >> 26;
2916 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2918 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2919 gint diff = target - code;
2922 if (diff <= 33554431){
2923 ins = (18 << 26) | (diff) | (ins & 1);
2924 patch_ins (code, ins);
2928 /* diff between 0 and -33554432 */
2929 if (diff >= -33554432){
2930 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2931 patch_ins (code, ins);
2936 if ((glong)target >= 0){
2937 if ((glong)target <= 33554431){
2938 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2939 patch_ins (code, ins);
2943 if ((glong)target >= -33554432){
2944 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2945 patch_ins (code, ins);
2950 handle_thunk (TRUE, code, target);
2953 g_assert_not_reached ();
2961 guint32 li = (gulong)target;
2962 ins = (ins & 0xffff0000) | (ins & 3);
2963 ovf = li & 0xffff0000;
2964 if (ovf != 0 && ovf != 0xffff0000)
2965 g_assert_not_reached ();
2968 // FIXME: assert the top bits of li are 0
2970 gint diff = target - code;
2971 ins = (ins & 0xffff0000) | (ins & 3);
2972 ovf = diff & 0xffff0000;
2973 if (ovf != 0 && ovf != 0xffff0000)
2974 g_assert_not_reached ();
2978 patch_ins (code, ins);
2982 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2983 #ifdef __mono_ppc64__
2984 guint32 *seq = (guint32*)code;
2985 guint32 *branch_ins;
2987 /* the trampoline code will try to patch the blrl, blr, bcctr */
2988 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2990 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2995 if (ppc_is_load_op (seq [5])
2996 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
2997 /* With function descs we need to do more careful
2999 || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3002 branch_ins = seq + 8;
3004 branch_ins = seq + 6;
3007 seq = (guint32*)code;
3008 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3009 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3011 if (ppc_is_load_op (seq [5])) {
3012 g_assert (ppc_is_load_op (seq [6]));
3015 guint8 *buf = (guint8*)&seq [5];
3016 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3021 target = mono_get_addr_from_ftnptr ((gpointer)target);
3024 /* FIXME: make this thread safe */
3025 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3026 /* FIXME: we're assuming we're using r12 here */
3027 ppc_load_ptr_sequence (code, ppc_r12, target);
3029 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3031 mono_arch_flush_icache ((guint8*)seq, 28);
3034 /* the trampoline code will try to patch the blrl, blr, bcctr */
3035 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3038 /* this is the lis/ori/mtlr/blrl sequence */
3039 seq = (guint32*)code;
3040 g_assert ((seq [0] >> 26) == 15);
3041 g_assert ((seq [1] >> 26) == 24);
3042 g_assert ((seq [2] >> 26) == 31);
3043 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3044 /* FIXME: make this thread safe */
3045 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3046 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3047 mono_arch_flush_icache (code - 8, 8);
3050 g_assert_not_reached ();
3052 // g_print ("patched with 0x%08x\n", ins);
3056 ppc_patch (guchar *code, const guchar *target)
3058 ppc_patch_full (code, target, FALSE);
3062 mono_ppc_patch (guchar *code, const guchar *target)
3064 ppc_patch (code, target);
3068 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3070 switch (ins->opcode) {
3073 case OP_FCALL_MEMBASE:
3074 if (ins->dreg != ppc_f1)
3075 ppc_fmr (code, ins->dreg, ppc_f1);
3083 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3085 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3089 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3091 long size = cfg->param_area;
3093 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3094 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3099 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3100 if (ppc_is_imm16 (-size)) {
3101 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3103 ppc_load (code, ppc_r12, -size);
3104 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3111 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3113 long size = cfg->param_area;
3115 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3116 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3121 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3122 if (ppc_is_imm16 (size)) {
3123 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3125 ppc_load (code, ppc_r12, size);
3126 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3132 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3136 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3138 MonoInst *ins, *next;
3141 guint8 *code = cfg->native_code + cfg->code_len;
3142 MonoInst *last_ins = NULL;
3143 guint last_offset = 0;
3147 /* we don't align basic blocks of loops on ppc */
3149 if (cfg->verbose_level > 2)
3150 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3152 cpos = bb->max_offset;
3154 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3155 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3156 //g_assert (!mono_compile_aot);
3159 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3160 /* this is not thread save, but good enough */
3161 /* fixme: howto handle overflows? */
3162 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3165 MONO_BB_FOR_EACH_INS (bb, ins) {
3166 offset = code - cfg->native_code;
3168 max_len = ins_native_length (cfg, ins);
3170 if (offset > (cfg->code_size - max_len - 16)) {
3171 cfg->code_size *= 2;
3172 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3173 code = cfg->native_code + offset;
3175 // if (ins->cil_code)
3176 // g_print ("cil code\n");
3177 mono_debug_record_line_number (cfg, ins, offset);
3179 switch (normalize_opcode (ins->opcode)) {
3180 case OP_RELAXED_NOP:
3183 case OP_DUMMY_STORE:
3184 case OP_NOT_REACHED:
3187 case OP_IL_SEQ_POINT:
3188 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3190 case OP_SEQ_POINT: {
3193 if (cfg->compile_aot)
3197 * Read from the single stepping trigger page. This will cause a
3198 * SIGSEGV when single stepping is enabled.
3199 * We do this _before_ the breakpoint, so single stepping after
3200 * a breakpoint is hit will step to the next IL offset.
3202 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3203 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3204 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3207 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3210 * A placeholder for a possible breakpoint inserted by
3211 * mono_arch_set_breakpoint ().
3213 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3218 emit_tls_access (code, ins->dreg, ins->inst_offset);
3221 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3222 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3223 ppc_mr (code, ppc_r4, ppc_r0);
3226 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3227 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3228 ppc_mr (code, ppc_r4, ppc_r0);
3230 case OP_MEMORY_BARRIER:
3233 case OP_STOREI1_MEMBASE_REG:
3234 if (ppc_is_imm16 (ins->inst_offset)) {
3235 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3237 if (ppc_is_imm32 (ins->inst_offset)) {
3238 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3239 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3241 ppc_load (code, ppc_r0, ins->inst_offset);
3242 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3246 case OP_STOREI2_MEMBASE_REG:
3247 if (ppc_is_imm16 (ins->inst_offset)) {
3248 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3250 if (ppc_is_imm32 (ins->inst_offset)) {
3251 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3252 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3254 ppc_load (code, ppc_r0, ins->inst_offset);
3255 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3259 case OP_STORE_MEMBASE_REG:
3260 if (ppc_is_imm16 (ins->inst_offset)) {
3261 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3263 if (ppc_is_imm32 (ins->inst_offset)) {
3264 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3265 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3267 ppc_load (code, ppc_r0, ins->inst_offset);
3268 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3272 #ifdef __mono_ilp32__
3273 case OP_STOREI8_MEMBASE_REG:
3274 if (ppc_is_imm16 (ins->inst_offset)) {
3275 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3277 ppc_load (code, ppc_r0, ins->inst_offset);
3278 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3282 case OP_STOREI1_MEMINDEX:
3283 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3285 case OP_STOREI2_MEMINDEX:
3286 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3288 case OP_STORE_MEMINDEX:
3289 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3292 g_assert_not_reached ();
3294 case OP_LOAD_MEMBASE:
3295 if (ppc_is_imm16 (ins->inst_offset)) {
3296 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3298 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3299 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3300 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3302 ppc_load (code, ppc_r0, ins->inst_offset);
3303 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3307 case OP_LOADI4_MEMBASE:
3308 #ifdef __mono_ppc64__
3309 if (ppc_is_imm16 (ins->inst_offset)) {
3310 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3312 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3313 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3314 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3316 ppc_load (code, ppc_r0, ins->inst_offset);
3317 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3322 case OP_LOADU4_MEMBASE:
3323 if (ppc_is_imm16 (ins->inst_offset)) {
3324 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3326 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3327 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3328 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3330 ppc_load (code, ppc_r0, ins->inst_offset);
3331 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3335 case OP_LOADI1_MEMBASE:
3336 case OP_LOADU1_MEMBASE:
3337 if (ppc_is_imm16 (ins->inst_offset)) {
3338 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3340 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3341 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3342 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3344 ppc_load (code, ppc_r0, ins->inst_offset);
3345 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3348 if (ins->opcode == OP_LOADI1_MEMBASE)
3349 ppc_extsb (code, ins->dreg, ins->dreg);
3351 case OP_LOADU2_MEMBASE:
3352 if (ppc_is_imm16 (ins->inst_offset)) {
3353 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3355 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3356 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3357 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3359 ppc_load (code, ppc_r0, ins->inst_offset);
3360 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3364 case OP_LOADI2_MEMBASE:
3365 if (ppc_is_imm16 (ins->inst_offset)) {
3366 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3368 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3369 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3370 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3372 ppc_load (code, ppc_r0, ins->inst_offset);
3373 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3377 #ifdef __mono_ilp32__
3378 case OP_LOADI8_MEMBASE:
3379 if (ppc_is_imm16 (ins->inst_offset)) {
3380 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3382 ppc_load (code, ppc_r0, ins->inst_offset);
3383 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3387 case OP_LOAD_MEMINDEX:
3388 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3390 case OP_LOADI4_MEMINDEX:
3391 #ifdef __mono_ppc64__
3392 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3395 case OP_LOADU4_MEMINDEX:
3396 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3398 case OP_LOADU2_MEMINDEX:
3399 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3401 case OP_LOADI2_MEMINDEX:
3402 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3404 case OP_LOADU1_MEMINDEX:
3405 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3407 case OP_LOADI1_MEMINDEX:
3408 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3409 ppc_extsb (code, ins->dreg, ins->dreg);
3411 case OP_ICONV_TO_I1:
3412 CASE_PPC64 (OP_LCONV_TO_I1)
3413 ppc_extsb (code, ins->dreg, ins->sreg1);
3415 case OP_ICONV_TO_I2:
3416 CASE_PPC64 (OP_LCONV_TO_I2)
3417 ppc_extsh (code, ins->dreg, ins->sreg1);
3419 case OP_ICONV_TO_U1:
3420 CASE_PPC64 (OP_LCONV_TO_U1)
3421 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3423 case OP_ICONV_TO_U2:
3424 CASE_PPC64 (OP_LCONV_TO_U2)
3425 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3429 CASE_PPC64 (OP_LCOMPARE)
3430 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3432 if (next && compare_opcode_is_unsigned (next->opcode))
3433 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3435 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3437 case OP_COMPARE_IMM:
3438 case OP_ICOMPARE_IMM:
3439 CASE_PPC64 (OP_LCOMPARE_IMM)
3440 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3442 if (next && compare_opcode_is_unsigned (next->opcode)) {
3443 if (ppc_is_uimm16 (ins->inst_imm)) {
3444 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3446 g_assert_not_reached ();
3449 if (ppc_is_imm16 (ins->inst_imm)) {
3450 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3452 g_assert_not_reached ();
3458 * gdb does not like encountering a trap in the debugged code. So
3459 * instead of emitting a trap, we emit a call a C function and place a
3463 ppc_mr (code, ppc_r3, ins->sreg1);
3464 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3465 (gpointer)"mono_break");
3466 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3467 ppc_load_func (code, PPC_CALL_REG, 0);
3468 ppc_mtlr (code, PPC_CALL_REG);
3476 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3479 CASE_PPC64 (OP_LADD)
3480 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3484 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3487 if (ppc_is_imm16 (ins->inst_imm)) {
3488 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3490 g_assert_not_reached ();
3495 CASE_PPC64 (OP_LADD_IMM)
3496 if (ppc_is_imm16 (ins->inst_imm)) {
3497 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3499 g_assert_not_reached ();
3503 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3505 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3506 ppc_mfspr (code, ppc_r0, ppc_xer);
3507 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3508 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3510 case OP_IADD_OVF_UN:
3511 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3513 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3514 ppc_mfspr (code, ppc_r0, ppc_xer);
3515 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3516 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3519 CASE_PPC64 (OP_LSUB_OVF)
3520 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3522 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3523 ppc_mfspr (code, ppc_r0, ppc_xer);
3524 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3525 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3527 case OP_ISUB_OVF_UN:
3528 CASE_PPC64 (OP_LSUB_OVF_UN)
3529 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3531 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3532 ppc_mfspr (code, ppc_r0, ppc_xer);
3533 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3534 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3536 case OP_ADD_OVF_CARRY:
3537 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3539 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3540 ppc_mfspr (code, ppc_r0, ppc_xer);
3541 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3542 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3544 case OP_ADD_OVF_UN_CARRY:
3545 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3547 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3548 ppc_mfspr (code, ppc_r0, ppc_xer);
3549 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3550 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3552 case OP_SUB_OVF_CARRY:
3553 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3555 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3556 ppc_mfspr (code, ppc_r0, ppc_xer);
3557 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3558 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3560 case OP_SUB_OVF_UN_CARRY:
3561 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3563 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3564 ppc_mfspr (code, ppc_r0, ppc_xer);
3565 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3566 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3570 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3573 CASE_PPC64 (OP_LSUB)
3574 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3578 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3582 CASE_PPC64 (OP_LSUB_IMM)
3583 // we add the negated value
3584 if (ppc_is_imm16 (-ins->inst_imm))
3585 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3587 g_assert_not_reached ();
3591 g_assert (ppc_is_imm16 (ins->inst_imm));
3592 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3595 ppc_subfze (code, ins->dreg, ins->sreg1);
3598 CASE_PPC64 (OP_LAND)
3599 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3600 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3604 CASE_PPC64 (OP_LAND_IMM)
3605 if (!(ins->inst_imm & 0xffff0000)) {
3606 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3607 } else if (!(ins->inst_imm & 0xffff)) {
3608 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3610 g_assert_not_reached ();
3614 CASE_PPC64 (OP_LDIV) {
3615 guint8 *divisor_is_m1;
3616 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3618 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3619 divisor_is_m1 = code;
3620 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3621 ppc_lis (code, ppc_r0, 0x8000);
3622 #ifdef __mono_ppc64__
3623 if (ins->opcode == OP_LDIV)
3624 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3626 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3627 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3628 ppc_patch (divisor_is_m1, code);
3629 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3631 if (ins->opcode == OP_IDIV)
3632 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3633 #ifdef __mono_ppc64__
3635 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 ppc_mfspr (code, ppc_r0, ppc_xer);
3638 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3639 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3643 CASE_PPC64 (OP_LDIV_UN)
3644 if (ins->opcode == OP_IDIV_UN)
3645 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3646 #ifdef __mono_ppc64__
3648 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3650 ppc_mfspr (code, ppc_r0, ppc_xer);
3651 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3652 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3658 g_assert_not_reached ();
3661 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3665 CASE_PPC64 (OP_LOR_IMM)
3666 if (!(ins->inst_imm & 0xffff0000)) {
3667 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3668 } else if (!(ins->inst_imm & 0xffff)) {
3669 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3671 g_assert_not_reached ();
3675 CASE_PPC64 (OP_LXOR)
3676 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3680 CASE_PPC64 (OP_LXOR_IMM)
3681 if (!(ins->inst_imm & 0xffff0000)) {
3682 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3683 } else if (!(ins->inst_imm & 0xffff)) {
3684 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3686 g_assert_not_reached ();
3690 CASE_PPC64 (OP_LSHL)
3691 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3695 CASE_PPC64 (OP_LSHL_IMM)
3696 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3699 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3702 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3705 if (MASK_SHIFT_IMM (ins->inst_imm))
3706 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3708 ppc_mr (code, ins->dreg, ins->sreg1);
3711 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3714 CASE_PPC64 (OP_LNOT)
3715 ppc_not (code, ins->dreg, ins->sreg1);
3718 CASE_PPC64 (OP_LNEG)
3719 ppc_neg (code, ins->dreg, ins->sreg1);
3722 CASE_PPC64 (OP_LMUL)
3723 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3727 CASE_PPC64 (OP_LMUL_IMM)
3728 if (ppc_is_imm16 (ins->inst_imm)) {
3729 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3731 g_assert_not_reached ();
3735 CASE_PPC64 (OP_LMUL_OVF)
3736 /* we annot use mcrxr, since it's not implemented on some processors
3737 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3739 if (ins->opcode == OP_IMUL_OVF)
3740 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3741 #ifdef __mono_ppc64__
3743 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3745 ppc_mfspr (code, ppc_r0, ppc_xer);
3746 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3747 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3749 case OP_IMUL_OVF_UN:
3750 CASE_PPC64 (OP_LMUL_OVF_UN)
3751 /* we first multiply to get the high word and compare to 0
3752 * to set the flags, then the result is discarded and then
3753 * we multiply to get the lower * bits result
3755 if (ins->opcode == OP_IMUL_OVF_UN)
3756 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3757 #ifdef __mono_ppc64__
3759 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3761 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3762 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3763 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3766 ppc_load (code, ins->dreg, ins->inst_c0);
3769 ppc_load (code, ins->dreg, ins->inst_l);
3772 case OP_LOAD_GOTADDR:
3773 /* The PLT implementation depends on this */
3774 g_assert (ins->dreg == ppc_r30);
3776 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3779 // FIXME: Fix max instruction length
3780 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3781 /* arch_emit_got_access () patches this */
3782 ppc_load32 (code, ppc_r0, 0);
3783 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3786 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3787 ppc_load_sequence (code, ins->dreg, 0);
3789 CASE_PPC32 (OP_ICONV_TO_I4)
3790 CASE_PPC32 (OP_ICONV_TO_U4)
3792 if (ins->dreg != ins->sreg1)
3793 ppc_mr (code, ins->dreg, ins->sreg1);
3796 int saved = ins->sreg1;
3797 if (ins->sreg1 == ppc_r3) {
3798 ppc_mr (code, ppc_r0, ins->sreg1);
3801 if (ins->sreg2 != ppc_r3)
3802 ppc_mr (code, ppc_r3, ins->sreg2);
3803 if (saved != ppc_r4)
3804 ppc_mr (code, ppc_r4, saved);
3808 if (ins->dreg != ins->sreg1)
3809 ppc_fmr (code, ins->dreg, ins->sreg1);
3811 case OP_MOVE_F_TO_I4:
3812 ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3813 ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3815 case OP_MOVE_I4_TO_F:
3816 ppc_stw (code, ins->sreg1, -4, ppc_r1);
3817 ppc_lfs (code, ins->dreg, -4, ppc_r1);
3819 case OP_FCONV_TO_R4:
3820 ppc_frsp (code, ins->dreg, ins->sreg1);
3824 MonoCallInst *call = (MonoCallInst*)ins;
3827 * Keep in sync with mono_arch_emit_epilog
3829 g_assert (!cfg->method->save_lmf);
3831 * Note: we can use ppc_r12 here because it is dead anyway:
3832 * we're leaving the method.
3834 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3835 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3836 if (ppc_is_imm16 (ret_offset)) {
3837 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3839 ppc_load (code, ppc_r12, ret_offset);
3840 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3842 ppc_mtlr (code, ppc_r0);
3845 if (ppc_is_imm16 (cfg->stack_usage)) {
3846 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3848 /* cfg->stack_usage is an int, so we can use
3849 * an addis/addi sequence here even in 64-bit. */
3850 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3851 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3853 if (!cfg->method->save_lmf) {
3855 for (i = 31; i >= 13; --i) {
3856 if (cfg->used_int_regs & (1 << i)) {
3857 pos += sizeof (gpointer);
3858 ppc_ldptr (code, i, -pos, ppc_r12);
3862 /* FIXME restore from MonoLMF: though this can't happen yet */
3865 /* Copy arguments on the stack to our argument area */
3866 if (call->stack_usage) {
3867 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3868 /* r12 was clobbered */
3869 g_assert (cfg->frame_reg == ppc_sp);
3870 if (ppc_is_imm16 (cfg->stack_usage)) {
3871 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3873 /* cfg->stack_usage is an int, so we can use
3874 * an addis/addi sequence here even in 64-bit. */
3875 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3876 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3880 ppc_mr (code, ppc_sp, ppc_r12);
3881 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3882 if (cfg->compile_aot) {
3883 /* arch_emit_got_access () patches this */
3884 ppc_load32 (code, ppc_r0, 0);
3885 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3886 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3887 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3889 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3891 ppc_mtctr (code, ppc_r0);
3892 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3899 /* ensure ins->sreg1 is not NULL */
3900 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3903 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3904 if (ppc_is_imm16 (cookie_offset)) {
3905 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3907 ppc_load (code, ppc_r0, cookie_offset);
3908 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3910 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3919 call = (MonoCallInst*)ins;
3920 if (ins->flags & MONO_INST_HAS_METHOD)
3921 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3923 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3924 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3925 ppc_load_func (code, PPC_CALL_REG, 0);
3926 ppc_mtlr (code, PPC_CALL_REG);
3931 /* FIXME: this should be handled somewhere else in the new jit */
3932 code = emit_move_return_value (cfg, ins, code);
3938 case OP_VOIDCALL_REG:
3940 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3941 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3942 /* FIXME: if we know that this is a method, we
3943 can omit this load */
3944 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3945 ppc_mtlr (code, ppc_r0);
3947 #if (_CALL_ELF == 2)
3948 if (ins->flags & MONO_INST_HAS_METHOD) {
3949 // Not a global entry point
3951 // Need to set up r12 with function entry address for global entry point
3952 if (ppc_r12 != ins->sreg1) {
3953 ppc_mr(code,ppc_r12,ins->sreg1);
3957 ppc_mtlr (code, ins->sreg1);
3960 /* FIXME: this should be handled somewhere else in the new jit */
3961 code = emit_move_return_value (cfg, ins, code);
3963 case OP_FCALL_MEMBASE:
3964 case OP_LCALL_MEMBASE:
3965 case OP_VCALL_MEMBASE:
3966 case OP_VCALL2_MEMBASE:
3967 case OP_VOIDCALL_MEMBASE:
3968 case OP_CALL_MEMBASE:
3969 if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3970 /* The trampolines clobber this */
3971 ppc_mr (code, ppc_r29, ins->sreg1);
3972 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3974 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3976 ppc_mtlr (code, ppc_r0);
3978 /* FIXME: this should be handled somewhere else in the new jit */
3979 code = emit_move_return_value (cfg, ins, code);
3982 guint8 * zero_loop_jump, * zero_loop_start;
3983 /* keep alignment */
3984 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3985 int area_offset = alloca_waste;
3987 ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
3988 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3989 ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
3990 /* use ctr to store the number of words to 0 if needed */
3991 if (ins->flags & MONO_INST_INIT) {
3992 /* we zero 4 bytes at a time:
3993 * we add 7 instead of 3 so that we set the counter to
3994 * at least 1, otherwise the bdnz instruction will make
3995 * it negative and iterate billions of times.
3997 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3998 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3999 ppc_mtctr (code, ppc_r0);
4001 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4002 ppc_neg (code, ppc_r12, ppc_r12);
4003 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4005 /* FIXME: make this loop work in 8 byte
4006 increments on PPC64 */
4007 if (ins->flags & MONO_INST_INIT) {
4008 /* adjust the dest reg by -4 so we can use stwu */
4009 /* we actually adjust -8 because we let the loop
4012 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4013 ppc_li (code, ppc_r12, 0);
4014 zero_loop_start = code;
4015 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4016 zero_loop_jump = code;
4017 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4018 ppc_patch (zero_loop_jump, zero_loop_start);
4020 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4025 ppc_mr (code, ppc_r3, ins->sreg1);
4026 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4027 (gpointer)"mono_arch_throw_exception");
4028 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4029 ppc_load_func (code, PPC_CALL_REG, 0);
4030 ppc_mtlr (code, PPC_CALL_REG);
4039 ppc_mr (code, ppc_r3, ins->sreg1);
4040 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4041 (gpointer)"mono_arch_rethrow_exception");
4042 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4043 ppc_load_func (code, PPC_CALL_REG, 0);
4044 ppc_mtlr (code, PPC_CALL_REG);
4051 case OP_START_HANDLER: {
4052 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4053 g_assert (spvar->inst_basereg != ppc_sp);
4054 code = emit_reserve_param_area (cfg, code);
4055 ppc_mflr (code, ppc_r0);
4056 if (ppc_is_imm16 (spvar->inst_offset)) {
4057 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4059 ppc_load (code, ppc_r12, spvar->inst_offset);
4060 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4064 case OP_ENDFILTER: {
4065 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4066 g_assert (spvar->inst_basereg != ppc_sp);
4067 code = emit_unreserve_param_area (cfg, code);
4068 if (ins->sreg1 != ppc_r3)
4069 ppc_mr (code, ppc_r3, ins->sreg1);
4070 if (ppc_is_imm16 (spvar->inst_offset)) {
4071 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4073 ppc_load (code, ppc_r12, spvar->inst_offset);
4074 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4076 ppc_mtlr (code, ppc_r0);
4080 case OP_ENDFINALLY: {
4081 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4082 g_assert (spvar->inst_basereg != ppc_sp);
4083 code = emit_unreserve_param_area (cfg, code);
4084 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4085 ppc_mtlr (code, ppc_r0);
4089 case OP_CALL_HANDLER:
4090 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4092 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4095 ins->inst_c0 = code - cfg->native_code;
4098 /*if (ins->inst_target_bb->native_offset) {
4100 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4102 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4107 ppc_mtctr (code, ins->sreg1);
4108 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4112 CASE_PPC64 (OP_LCEQ)
4113 ppc_li (code, ins->dreg, 0);
4114 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4115 ppc_li (code, ins->dreg, 1);
4121 CASE_PPC64 (OP_LCLT)
4122 CASE_PPC64 (OP_LCLT_UN)
4123 ppc_li (code, ins->dreg, 1);
4124 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4125 ppc_li (code, ins->dreg, 0);
4131 CASE_PPC64 (OP_LCGT)
4132 CASE_PPC64 (OP_LCGT_UN)
4133 ppc_li (code, ins->dreg, 1);
4134 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4135 ppc_li (code, ins->dreg, 0);
4137 case OP_COND_EXC_EQ:
4138 case OP_COND_EXC_NE_UN:
4139 case OP_COND_EXC_LT:
4140 case OP_COND_EXC_LT_UN:
4141 case OP_COND_EXC_GT:
4142 case OP_COND_EXC_GT_UN:
4143 case OP_COND_EXC_GE:
4144 case OP_COND_EXC_GE_UN:
4145 case OP_COND_EXC_LE:
4146 case OP_COND_EXC_LE_UN:
4147 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4149 case OP_COND_EXC_IEQ:
4150 case OP_COND_EXC_INE_UN:
4151 case OP_COND_EXC_ILT:
4152 case OP_COND_EXC_ILT_UN:
4153 case OP_COND_EXC_IGT:
4154 case OP_COND_EXC_IGT_UN:
4155 case OP_COND_EXC_IGE:
4156 case OP_COND_EXC_IGE_UN:
4157 case OP_COND_EXC_ILE:
4158 case OP_COND_EXC_ILE_UN:
4159 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4171 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4174 /* floating point opcodes */
4176 g_assert (cfg->compile_aot);
4178 /* FIXME: Optimize this */
4180 ppc_mflr (code, ppc_r12);
4182 *(double*)code = *(double*)ins->inst_p0;
4184 ppc_lfd (code, ins->dreg, 8, ppc_r12);
4187 g_assert_not_reached ();
4189 case OP_STORER8_MEMBASE_REG:
4190 if (ppc_is_imm16 (ins->inst_offset)) {
4191 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4193 if (ppc_is_imm32 (ins->inst_offset)) {
4194 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4195 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4197 ppc_load (code, ppc_r0, ins->inst_offset);
4198 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4202 case OP_LOADR8_MEMBASE:
4203 if (ppc_is_imm16 (ins->inst_offset)) {
4204 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4206 if (ppc_is_imm32 (ins->inst_offset)) {
4207 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4208 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4210 ppc_load (code, ppc_r0, ins->inst_offset);
4211 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4215 case OP_STORER4_MEMBASE_REG:
4216 ppc_frsp (code, ins->sreg1, ins->sreg1);
4217 if (ppc_is_imm16 (ins->inst_offset)) {
4218 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4220 if (ppc_is_imm32 (ins->inst_offset)) {
4221 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4222 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4224 ppc_load (code, ppc_r0, ins->inst_offset);
4225 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4229 case OP_LOADR4_MEMBASE:
4230 if (ppc_is_imm16 (ins->inst_offset)) {
4231 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4233 if (ppc_is_imm32 (ins->inst_offset)) {
4234 ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4235 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4237 ppc_load (code, ppc_r0, ins->inst_offset);
4238 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4242 case OP_LOADR4_MEMINDEX:
4243 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4245 case OP_LOADR8_MEMINDEX:
4246 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4248 case OP_STORER4_MEMINDEX:
4249 ppc_frsp (code, ins->sreg1, ins->sreg1);
4250 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4252 case OP_STORER8_MEMINDEX:
4253 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4256 case CEE_CONV_R4: /* FIXME: change precision */
4258 g_assert_not_reached ();
4259 case OP_FCONV_TO_I1:
4260 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4262 case OP_FCONV_TO_U1:
4263 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4265 case OP_FCONV_TO_I2:
4266 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4268 case OP_FCONV_TO_U2:
4269 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4271 case OP_FCONV_TO_I4:
4273 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4275 case OP_FCONV_TO_U4:
4277 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4279 case OP_LCONV_TO_R_UN:
4280 g_assert_not_reached ();
4281 /* Implemented as helper calls */
4283 case OP_LCONV_TO_OVF_I4_2:
4284 case OP_LCONV_TO_OVF_I: {
4285 #ifdef __mono_ppc64__
4288 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4289 // Check if its negative
4290 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4291 negative_branch = code;
4292 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4293 // Its positive msword == 0
4294 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4295 msword_positive_branch = code;
4296 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4298 ovf_ex_target = code;
4299 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4301 ppc_patch (negative_branch, code);
4302 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4303 msword_negative_branch = code;
4304 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4305 ppc_patch (msword_negative_branch, ovf_ex_target);
4307 ppc_patch (msword_positive_branch, code);
4308 if (ins->dreg != ins->sreg1)
4309 ppc_mr (code, ins->dreg, ins->sreg1);
4314 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4317 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4320 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4323 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4326 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4329 ppc_fneg (code, ins->dreg, ins->sreg1);
4333 g_assert_not_reached ();
4336 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4339 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4340 ppc_li (code, ins->dreg, 0);
4341 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4342 ppc_li (code, ins->dreg, 1);
4345 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4346 ppc_li (code, ins->dreg, 1);
4347 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4348 ppc_li (code, ins->dreg, 0);
4351 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4352 ppc_li (code, ins->dreg, 1);
4353 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4354 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4355 ppc_li (code, ins->dreg, 0);
4358 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4359 ppc_li (code, ins->dreg, 1);
4360 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4361 ppc_li (code, ins->dreg, 0);
4364 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4365 ppc_li (code, ins->dreg, 1);
4366 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4367 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4368 ppc_li (code, ins->dreg, 0);
4371 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4374 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4377 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4378 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4381 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4382 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4385 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4386 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4389 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4390 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4393 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4394 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4397 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4400 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4401 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4404 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4407 g_assert_not_reached ();
4408 case OP_CHECK_FINITE: {
4409 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4410 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4411 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4412 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4415 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4416 #ifdef __mono_ppc64__
4417 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4419 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4424 #ifdef __mono_ppc64__
4425 case OP_ICONV_TO_I4:
4427 ppc_extsw (code, ins->dreg, ins->sreg1);
4429 case OP_ICONV_TO_U4:
4431 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4433 case OP_ICONV_TO_R4:
4434 case OP_ICONV_TO_R8:
4435 case OP_LCONV_TO_R4:
4436 case OP_LCONV_TO_R8: {
4438 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4439 ppc_extsw (code, ppc_r0, ins->sreg1);
4444 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4445 ppc_mffgpr (code, ins->dreg, tmp);
4447 ppc_str (code, tmp, -8, ppc_r1);
4448 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4450 ppc_fcfid (code, ins->dreg, ins->dreg);
4451 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4452 ppc_frsp (code, ins->dreg, ins->dreg);
4456 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4459 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4462 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4464 ppc_mfspr (code, ppc_r0, ppc_xer);
4465 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4466 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4468 case OP_COND_EXC_OV:
4469 ppc_mfspr (code, ppc_r0, ppc_xer);
4470 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4471 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4483 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4485 case OP_FCONV_TO_I8:
4486 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4488 case OP_FCONV_TO_U8:
4489 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4491 case OP_STOREI4_MEMBASE_REG:
4492 if (ppc_is_imm16 (ins->inst_offset)) {
4493 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4495 ppc_load (code, ppc_r0, ins->inst_offset);
4496 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4499 case OP_STOREI4_MEMINDEX:
4500 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4503 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4505 case OP_ISHR_UN_IMM:
4506 if (ins->inst_imm & 0x1f)
4507 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4509 ppc_mr (code, ins->dreg, ins->sreg1);
4512 case OP_ICONV_TO_R4:
4513 case OP_ICONV_TO_R8: {
4514 if (cpu_hw_caps & PPC_ISA_64) {
4515 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4516 ppc_stw (code, ppc_r0, -8, ppc_r1);
4517 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4518 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4519 ppc_fcfid (code, ins->dreg, ins->dreg);
4520 if (ins->opcode == OP_ICONV_TO_R4)
4521 ppc_frsp (code, ins->dreg, ins->dreg);
4527 case OP_ATOMIC_ADD_I4:
4528 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4529 int location = ins->inst_basereg;
4530 int addend = ins->sreg2;
4531 guint8 *loop, *branch;
4532 g_assert (ins->inst_offset == 0);
4536 if (ins->opcode == OP_ATOMIC_ADD_I4)
4537 ppc_lwarx (code, ppc_r0, 0, location);
4538 #ifdef __mono_ppc64__
4540 ppc_ldarx (code, ppc_r0, 0, location);
4543 ppc_add (code, ppc_r0, ppc_r0, addend);
4545 if (ins->opcode == OP_ATOMIC_ADD_I4)
4546 ppc_stwcxd (code, ppc_r0, 0, location);
4547 #ifdef __mono_ppc64__
4549 ppc_stdcxd (code, ppc_r0, 0, location);
4553 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4554 ppc_patch (branch, loop);
4557 ppc_mr (code, ins->dreg, ppc_r0);
4560 case OP_ATOMIC_CAS_I4:
4561 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4562 int location = ins->sreg1;
4563 int value = ins->sreg2;
4564 int comparand = ins->sreg3;
4565 guint8 *start, *not_equal, *lost_reservation;
4569 if (ins->opcode == OP_ATOMIC_CAS_I4)
4570 ppc_lwarx (code, ppc_r0, 0, location);
4571 #ifdef __mono_ppc64__
4573 ppc_ldarx (code, ppc_r0, 0, location);
4576 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4578 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4580 if (ins->opcode == OP_ATOMIC_CAS_I4)
4581 ppc_stwcxd (code, value, 0, location);
4582 #ifdef __mono_ppc64__
4584 ppc_stdcxd (code, value, 0, location);
4587 lost_reservation = code;
4588 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4589 ppc_patch (lost_reservation, start);
4590 ppc_patch (not_equal, code);
4593 ppc_mr (code, ins->dreg, ppc_r0);
4598 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4599 g_assert_not_reached ();
4602 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4603 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4604 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4605 g_assert_not_reached ();
4611 last_offset = offset;
4614 cfg->code_len = code - cfg->native_code;
4616 #endif /* !DISABLE_JIT */
4619 mono_arch_register_lowlevel_calls (void)
4621 /* The signature doesn't matter */
4622 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4625 #ifdef __mono_ppc64__
4626 #ifdef _LITTLE_ENDIAN
4627 #define patch_load_sequence(ip,val) do {\
4628 guint16 *__load = (guint16*)(ip); \
4629 g_assert (sizeof (val) == sizeof (gsize)); \
4630 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4631 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4632 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4633 __load [8] = ((guint64)(gsize)(val)) & 0xffff; \
4635 #elif defined _BIG_ENDIAN
4636 #define patch_load_sequence(ip,val) do {\
4637 guint16 *__load = (guint16*)(ip); \
4638 g_assert (sizeof (val) == sizeof (gsize)); \
4639 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4640 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4641 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4642 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4645 #error huh? No endianess defined by compiler
4648 #define patch_load_sequence(ip,val) do {\
4649 guint16 *__lis_ori = (guint16*)(ip); \
4650 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4651 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4657 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4659 MonoJumpInfo *patch_info;
4660 gboolean compile_aot = !run_cctors;
4662 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4663 unsigned char *ip = patch_info->ip.i + code;
4664 unsigned char *target;
4665 gboolean is_fd = FALSE;
4667 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4670 switch (patch_info->type) {
4671 case MONO_PATCH_INFO_BB:
4672 case MONO_PATCH_INFO_LABEL:
4675 /* No need to patch these */
4680 switch (patch_info->type) {
4681 case MONO_PATCH_INFO_IP:
4682 patch_load_sequence (ip, ip);
4684 case MONO_PATCH_INFO_METHOD_REL:
4685 g_assert_not_reached ();
4686 *((gpointer *)(ip)) = code + patch_info->data.offset;
4688 case MONO_PATCH_INFO_SWITCH: {
4689 gpointer *table = (gpointer *)patch_info->data.table->table;
4692 patch_load_sequence (ip, table);
4694 for (i = 0; i < patch_info->data.table->table_size; i++) {
4695 table [i] = (glong)patch_info->data.table->table [i] + code;
4697 /* we put into the table the absolute address, no need for ppc_patch in this case */
4700 case MONO_PATCH_INFO_METHODCONST:
4701 case MONO_PATCH_INFO_CLASS:
4702 case MONO_PATCH_INFO_IMAGE:
4703 case MONO_PATCH_INFO_FIELD:
4704 case MONO_PATCH_INFO_VTABLE:
4705 case MONO_PATCH_INFO_IID:
4706 case MONO_PATCH_INFO_SFLDA:
4707 case MONO_PATCH_INFO_LDSTR:
4708 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4709 case MONO_PATCH_INFO_LDTOKEN:
4710 /* from OP_AOTCONST : lis + ori */
4711 patch_load_sequence (ip, target);
4713 case MONO_PATCH_INFO_R4:
4714 case MONO_PATCH_INFO_R8:
4715 g_assert_not_reached ();
4716 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4718 case MONO_PATCH_INFO_EXC_NAME:
4719 g_assert_not_reached ();
4720 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4722 case MONO_PATCH_INFO_NONE:
4723 case MONO_PATCH_INFO_BB_OVF:
4724 case MONO_PATCH_INFO_EXC_OVF:
4725 /* everything is dealt with at epilog output time */
4727 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4728 case MONO_PATCH_INFO_INTERNAL_METHOD:
4729 case MONO_PATCH_INFO_ABS:
4730 case MONO_PATCH_INFO_RGCTX_FETCH:
4731 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4738 ppc_patch_full (ip, target, is_fd);
4743 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4744 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4745 * the instruction offset immediate for all the registers.
4748 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4752 for (i = 13; i <= 31; i++) {
4753 if (used_int_regs & (1 << i)) {
4754 ppc_str (code, i, pos, base_reg);
4755 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4756 pos += sizeof (mgreg_t);
4760 /* pos is the start of the MonoLMF structure */
4761 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4762 for (i = 13; i <= 31; i++) {
4763 ppc_str (code, i, offset, base_reg);
4764 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4765 offset += sizeof (mgreg_t);
4767 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4768 for (i = 14; i < 32; i++) {
4769 ppc_stfd (code, i, offset, base_reg);
4770 offset += sizeof (gdouble);
4777 * Stack frame layout:
4779 * ------------------- sp
4780 * MonoLMF structure or saved registers
4781 * -------------------
4783 * -------------------
4785 * -------------------
4786 * optional 8 bytes for tracing
4787 * -------------------
4788 * param area size is cfg->param_area
4789 * -------------------
4790 * linkage area size is PPC_STACK_PARAM_OFFSET
4791 * ------------------- sp
4795 mono_arch_emit_prolog (MonoCompile *cfg)
4797 MonoMethod *method = cfg->method;
4799 MonoMethodSignature *sig;
4801 long alloc_size, pos, max_offset, cfa_offset;
4807 int tailcall_struct_index;
4809 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4812 sig = mono_method_signature (method);
4813 cfg->code_size = 512 + sig->param_count * 32;
4814 code = cfg->native_code = g_malloc (cfg->code_size);
4818 /* We currently emit unwind info for aot, but don't use it */
4819 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4821 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4822 ppc_mflr (code, ppc_r0);
4823 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4824 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4827 alloc_size = cfg->stack_offset;
4830 if (!method->save_lmf) {
4831 for (i = 31; i >= 13; --i) {
4832 if (cfg->used_int_regs & (1 << i)) {
4833 pos += sizeof (mgreg_t);
4837 pos += sizeof (MonoLMF);
4841 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4842 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4843 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4844 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4847 cfg->stack_usage = alloc_size;
4848 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4850 if (ppc_is_imm16 (-alloc_size)) {
4851 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4852 cfa_offset = alloc_size;
4853 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4854 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4857 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4858 ppc_load (code, ppc_r0, -alloc_size);
4859 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4860 cfa_offset = alloc_size;
4861 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4862 code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4865 if (cfg->frame_reg != ppc_sp) {
4866 ppc_mr (code, cfg->frame_reg, ppc_sp);
4867 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4870 /* store runtime generic context */
4871 if (cfg->rgctx_var) {
4872 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4873 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4875 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4878 /* compute max_offset in order to use short forward jumps
4879 * we always do it on ppc because the immediate displacement
4880 * for jumps is too small
4883 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4885 bb->max_offset = max_offset;
4887 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4890 MONO_BB_FOR_EACH_INS (bb, ins)
4891 max_offset += ins_native_length (cfg, ins);
4894 /* load arguments allocated to register from the stack */
4897 cinfo = get_call_info (sig);
4899 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4900 ArgInfo *ainfo = &cinfo->ret;
4902 inst = cfg->vret_addr;
4905 if (ppc_is_imm16 (inst->inst_offset)) {
4906 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4908 ppc_load (code, ppc_r12, inst->inst_offset);
4909 ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4913 tailcall_struct_index = 0;
4914 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4915 ArgInfo *ainfo = cinfo->args + i;
4916 inst = cfg->args [pos];
4918 if (cfg->verbose_level > 2)
4919 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4920 if (inst->opcode == OP_REGVAR) {
4921 if (ainfo->regtype == RegTypeGeneral)
4922 ppc_mr (code, inst->dreg, ainfo->reg);
4923 else if (ainfo->regtype == RegTypeFP)
4924 ppc_fmr (code, inst->dreg, ainfo->reg);
4925 else if (ainfo->regtype == RegTypeBase) {
4926 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4927 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4929 g_assert_not_reached ();
4931 if (cfg->verbose_level > 2)
4932 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4934 /* the argument should be put on the stack: FIXME handle size != word */
4935 if (ainfo->regtype == RegTypeGeneral) {
4936 switch (ainfo->size) {
4938 if (ppc_is_imm16 (inst->inst_offset)) {
4939 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4941 if (ppc_is_imm32 (inst->inst_offset)) {
4942 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4943 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4945 ppc_load (code, ppc_r12, inst->inst_offset);
4946 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4951 if (ppc_is_imm16 (inst->inst_offset)) {
4952 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4954 if (ppc_is_imm32 (inst->inst_offset)) {
4955 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4956 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4958 ppc_load (code, ppc_r12, inst->inst_offset);
4959 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4963 #ifdef __mono_ppc64__
4965 if (ppc_is_imm16 (inst->inst_offset)) {
4966 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4968 if (ppc_is_imm32 (inst->inst_offset)) {
4969 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4970 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
4972 ppc_load (code, ppc_r12, inst->inst_offset);
4973 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4978 if (ppc_is_imm16 (inst->inst_offset)) {
4979 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4981 ppc_load (code, ppc_r12, inst->inst_offset);
4982 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4987 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4988 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4989 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4991 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4992 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
4993 ppc_stw (code, ainfo->reg, 0, ppc_r12);
4994 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
4999 if (ppc_is_imm16 (inst->inst_offset)) {
5000 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5002 if (ppc_is_imm32 (inst->inst_offset)) {
5003 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5004 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5006 ppc_load (code, ppc_r12, inst->inst_offset);
5007 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5012 } else if (ainfo->regtype == RegTypeBase) {
5013 g_assert (ppc_is_imm16 (ainfo->offset));
5014 /* load the previous stack pointer in r12 */
5015 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5016 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5017 switch (ainfo->size) {
5019 if (ppc_is_imm16 (inst->inst_offset)) {
5020 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5022 if (ppc_is_imm32 (inst->inst_offset)) {
5023 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5024 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5026 ppc_load (code, ppc_r12, inst->inst_offset);
5027 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5032 if (ppc_is_imm16 (inst->inst_offset)) {
5033 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5035 if (ppc_is_imm32 (inst->inst_offset)) {
5036 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5037 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5039 ppc_load (code, ppc_r12, inst->inst_offset);
5040 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5044 #ifdef __mono_ppc64__
5046 if (ppc_is_imm16 (inst->inst_offset)) {
5047 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5049 if (ppc_is_imm32 (inst->inst_offset)) {
5050 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5051 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5053 ppc_load (code, ppc_r12, inst->inst_offset);
5054 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5059 if (ppc_is_imm16 (inst->inst_offset)) {
5060 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5062 ppc_load (code, ppc_r12, inst->inst_offset);
5063 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5068 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5069 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5070 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5071 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5072 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5074 /* use r11 to load the 2nd half of the long before we clobber r12. */
5075 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5076 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5077 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5078 ppc_stw (code, ppc_r0, 0, ppc_r12);
5079 ppc_stw (code, ppc_r11, 4, ppc_r12);
5084 if (ppc_is_imm16 (inst->inst_offset)) {
5085 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5087 if (ppc_is_imm32 (inst->inst_offset)) {
5088 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5089 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5091 ppc_load (code, ppc_r12, inst->inst_offset);
5092 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5097 } else if (ainfo->regtype == RegTypeFP) {
5098 g_assert (ppc_is_imm16 (inst->inst_offset));
5099 if (ainfo->size == 8)
5100 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5101 else if (ainfo->size == 4)
5102 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5104 g_assert_not_reached ();
5105 } else if (ainfo->regtype == RegTypeFPStructByVal) {
5106 int doffset = inst->inst_offset;
5110 g_assert (ppc_is_imm16 (inst->inst_offset));
5111 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5112 /* FIXME: what if there is no class? */
5113 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5114 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5115 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5116 if (ainfo->size == 4) {
5117 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5119 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5121 soffset += ainfo->size;
5122 doffset += ainfo->size;
5124 } else if (ainfo->regtype == RegTypeStructByVal) {
5125 int doffset = inst->inst_offset;
5129 g_assert (ppc_is_imm16 (inst->inst_offset));
5130 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5131 /* FIXME: what if there is no class? */
5132 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5133 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5134 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5137 * Darwin handles 1 and 2 byte
5138 * structs specially by
5139 * loading h/b into the arg
5140 * register. Only done for
5144 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5146 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5150 #ifdef __mono_ppc64__
5152 g_assert (cur_reg == 0);
5153 #if G_BYTE_ORDER == G_BIG_ENDIAN
5154 ppc_sldi (code, ppc_r0, ainfo->reg,
5155 (sizeof (gpointer) - ainfo->bytes) * 8);
5156 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5158 if (mono_class_native_size (inst->klass, NULL) == 1) {
5159 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5160 } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5161 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5162 } else if (mono_class_native_size (inst->klass, NULL) == 4) { // WDS -- maybe <=4?
5163 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5165 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg); // WDS -- Better way?
5171 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5172 inst->inst_basereg);
5175 soffset += sizeof (gpointer);
5176 doffset += sizeof (gpointer);
5178 if (ainfo->vtsize) {
5179 /* FIXME: we need to do the shifting here, too */
5182 /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5183 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5184 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5185 code = emit_memcpy (code, size - soffset,
5186 inst->inst_basereg, doffset,
5187 ppc_r12, ainfo->offset + soffset);
5189 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5190 inst->inst_basereg, doffset,
5191 ppc_r12, ainfo->offset + soffset);
5194 } else if (ainfo->regtype == RegTypeStructByAddr) {
5195 /* if it was originally a RegTypeBase */
5196 if (ainfo->offset) {
5197 /* load the previous stack pointer in r12 */
5198 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5199 ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5201 ppc_mr (code, ppc_r12, ainfo->reg);
5204 if (cfg->tailcall_valuetype_addrs) {
5205 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5207 g_assert (ppc_is_imm16 (addr->inst_offset));
5208 ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5210 tailcall_struct_index++;
5213 g_assert (ppc_is_imm16 (inst->inst_offset));
5214 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5215 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5217 g_assert_not_reached ();
5222 if (method->save_lmf) {
5223 if (lmf_pthread_key != -1) {
5224 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5225 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5226 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5228 if (cfg->compile_aot) {
5229 /* Compute the got address which is needed by the PLT entry */
5230 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5232 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5233 (gpointer)"mono_get_lmf_addr");
5234 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5235 ppc_load_func (code, PPC_CALL_REG, 0);
5236 ppc_mtlr (code, PPC_CALL_REG);
5242 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5243 /* lmf_offset is the offset from the previous stack pointer,
5244 * alloc_size is the total stack space allocated, so the offset
5245 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5246 * The pointer to the struct is put in ppc_r12 (new_lmf).
5247 * The callee-saved registers are already in the MonoLMF structure
5249 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5250 /* ppc_r3 is the result from mono_get_lmf_addr () */
5251 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5252 /* new_lmf->previous_lmf = *lmf_addr */
5253 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5254 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5255 /* *(lmf_addr) = r12 */
5256 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5257 /* save method info */
5258 if (cfg->compile_aot)
5260 ppc_load (code, ppc_r0, 0);
5262 ppc_load_ptr (code, ppc_r0, method);
5263 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5264 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5265 /* save the current IP */
5266 if (cfg->compile_aot) {
5268 ppc_mflr (code, ppc_r0);
5270 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5271 #ifdef __mono_ppc64__
5272 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5274 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5277 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5281 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5283 cfg->code_len = code - cfg->native_code;
5284 g_assert (cfg->code_len <= cfg->code_size);
5291 mono_arch_emit_epilog (MonoCompile *cfg)
5293 MonoMethod *method = cfg->method;
5295 int max_epilog_size = 16 + 20*4;
5298 if (cfg->method->save_lmf)
5299 max_epilog_size += 128;
5301 if (mono_jit_trace_calls != NULL)
5302 max_epilog_size += 50;
5304 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5305 max_epilog_size += 50;
5307 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5308 cfg->code_size *= 2;
5309 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5310 cfg->stat_code_reallocs++;
5314 * Keep in sync with OP_JMP
5316 code = cfg->native_code + cfg->code_len;
5318 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5319 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5323 if (method->save_lmf) {
5325 pos += sizeof (MonoLMF);
5327 /* save the frame reg in r8 */
5328 ppc_mr (code, ppc_r8, cfg->frame_reg);
5329 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5330 /* r5 = previous_lmf */
5331 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5333 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5334 /* *(lmf_addr) = previous_lmf */
5335 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5336 /* FIXME: speedup: there is no actual need to restore the registers if
5337 * we didn't actually change them (idea from Zoltan).
5340 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5342 /*for (i = 14; i < 32; i++) {
5343 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5345 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5346 /* use the saved copy of the frame reg in r8 */
5347 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5348 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5349 ppc_mtlr (code, ppc_r0);
5351 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5353 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5354 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5355 if (ppc_is_imm16 (return_offset)) {
5356 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5358 ppc_load (code, ppc_r12, return_offset);
5359 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5361 ppc_mtlr (code, ppc_r0);
5363 if (ppc_is_imm16 (cfg->stack_usage)) {
5364 int offset = cfg->stack_usage;
5365 for (i = 13; i <= 31; i++) {
5366 if (cfg->used_int_regs & (1 << i))
5367 offset -= sizeof (mgreg_t);
5369 if (cfg->frame_reg != ppc_sp)
5370 ppc_mr (code, ppc_r12, cfg->frame_reg);
5371 /* note r31 (possibly the frame register) is restored last */
5372 for (i = 13; i <= 31; i++) {
5373 if (cfg->used_int_regs & (1 << i)) {
5374 ppc_ldr (code, i, offset, cfg->frame_reg);
5375 offset += sizeof (mgreg_t);
5378 if (cfg->frame_reg != ppc_sp)
5379 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5381 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5383 ppc_load32 (code, ppc_r12, cfg->stack_usage);
5384 if (cfg->used_int_regs) {
5385 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5386 for (i = 31; i >= 13; --i) {
5387 if (cfg->used_int_regs & (1 << i)) {
5388 pos += sizeof (mgreg_t);
5389 ppc_ldr (code, i, -pos, ppc_r12);
5392 ppc_mr (code, ppc_sp, ppc_r12);
5394 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5401 cfg->code_len = code - cfg->native_code;
5403 g_assert (cfg->code_len < cfg->code_size);
5406 #endif /* ifndef DISABLE_JIT */
5408 /* remove once throw_exception_by_name is eliminated */
5410 exception_id_by_name (const char *name)
5412 if (strcmp (name, "IndexOutOfRangeException") == 0)
5413 return MONO_EXC_INDEX_OUT_OF_RANGE;
5414 if (strcmp (name, "OverflowException") == 0)
5415 return MONO_EXC_OVERFLOW;
5416 if (strcmp (name, "ArithmeticException") == 0)
5417 return MONO_EXC_ARITHMETIC;
5418 if (strcmp (name, "DivideByZeroException") == 0)
5419 return MONO_EXC_DIVIDE_BY_ZERO;
5420 if (strcmp (name, "InvalidCastException") == 0)
5421 return MONO_EXC_INVALID_CAST;
5422 if (strcmp (name, "NullReferenceException") == 0)
5423 return MONO_EXC_NULL_REF;
5424 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5425 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5426 if (strcmp (name, "ArgumentException") == 0)
5427 return MONO_EXC_ARGUMENT;
5428 g_error ("Unknown intrinsic exception %s\n", name);
5434 mono_arch_emit_exceptions (MonoCompile *cfg)
5436 MonoJumpInfo *patch_info;
5439 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5440 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5441 int max_epilog_size = 50;
5443 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5444 exc_throw_pos [i] = NULL;
5445 exc_throw_found [i] = 0;
5448 /* count the number of exception infos */
5451 * make sure we have enough space for exceptions
5453 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5454 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5455 i = exception_id_by_name (patch_info->data.target);
5456 if (!exc_throw_found [i]) {
5457 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5458 exc_throw_found [i] = TRUE;
5460 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5461 max_epilog_size += 12;
5462 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5463 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5464 i = exception_id_by_name (ovfj->data.exception);
5465 if (!exc_throw_found [i]) {
5466 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5467 exc_throw_found [i] = TRUE;
5469 max_epilog_size += 8;
5473 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5474 cfg->code_size *= 2;
5475 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5476 cfg->stat_code_reallocs++;
5479 code = cfg->native_code + cfg->code_len;
5481 /* add code to raise exceptions */
5482 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5483 switch (patch_info->type) {
5484 case MONO_PATCH_INFO_BB_OVF: {
5485 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5486 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5487 /* patch the initial jump */
5488 ppc_patch (ip, code);
5489 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5491 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5492 /* jump back to the true target */
5494 ip = ovfj->data.bb->native_offset + cfg->native_code;
5495 ppc_patch (code - 4, ip);
5496 patch_info->type = MONO_PATCH_INFO_NONE;
5499 case MONO_PATCH_INFO_EXC_OVF: {
5500 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5501 MonoJumpInfo *newji;
5502 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5503 unsigned char *bcl = code;
5504 /* patch the initial jump: we arrived here with a call */
5505 ppc_patch (ip, code);
5506 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5508 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5509 /* patch the conditional jump to the right handler */
5510 /* make it processed next */
5511 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5512 newji->type = MONO_PATCH_INFO_EXC;
5513 newji->ip.i = bcl - cfg->native_code;
5514 newji->data.target = ovfj->data.exception;
5515 newji->next = patch_info->next;
5516 patch_info->next = newji;
5517 patch_info->type = MONO_PATCH_INFO_NONE;
5520 case MONO_PATCH_INFO_EXC: {
5521 MonoClass *exc_class;
5523 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5524 i = exception_id_by_name (patch_info->data.target);
5525 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5526 ppc_patch (ip, exc_throw_pos [i]);
5527 patch_info->type = MONO_PATCH_INFO_NONE;
5530 exc_throw_pos [i] = code;
5533 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5534 g_assert (exc_class);
5536 ppc_patch (ip, code);
5537 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5538 ppc_load (code, ppc_r3, exc_class->type_token);
5539 /* we got here from a conditional call, so the calling ip is set in lr */
5540 ppc_mflr (code, ppc_r4);
5541 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5542 patch_info->data.name = "mono_arch_throw_corlib_exception";
5543 patch_info->ip.i = code - cfg->native_code;
5544 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5545 ppc_load_func (code, PPC_CALL_REG, 0);
5546 ppc_mtctr (code, PPC_CALL_REG);
5547 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5559 cfg->code_len = code - cfg->native_code;
5561 g_assert (cfg->code_len <= cfg->code_size);
5567 try_offset_access (void *value, guint32 idx)
5569 register void* me __asm__ ("r2");
5570 void ***p = (void***)((char*)me + 284);
5571 int idx1 = idx / 32;
5572 int idx2 = idx % 32;
5575 if (value != p[idx1][idx2])
5582 setup_tls_access (void)
5584 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5585 size_t conf_size = 0;
5588 /* FIXME for darwin */
5589 guint32 *ins, *code;
5590 guint32 cmplwi_1023, li_0x48, blr_ins;
5594 tls_mode = TLS_MODE_FAILED;
5597 if (tls_mode == TLS_MODE_FAILED)
5599 if (g_getenv ("MONO_NO_TLS")) {
5600 tls_mode = TLS_MODE_FAILED;
5604 if (tls_mode == TLS_MODE_DETECT) {
5605 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5606 tls_mode = TLS_MODE_DARWIN_G4;
5607 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5608 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5609 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5610 tls_mode = TLS_MODE_NPTL;
5611 #elif !defined(TARGET_PS3)
5612 ins = (guint32*)pthread_getspecific;
5613 /* uncond branch to the real method */
5614 if ((*ins >> 26) == 18) {
5616 val = (*ins & ~3) << 6;
5620 ins = (guint32*)(long)val;
5622 ins = (guint32*) ((char*)ins + val);
5625 code = &cmplwi_1023;
5626 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5628 ppc_li (code, ppc_r4, 0x48);
5631 if (*ins == cmplwi_1023) {
5632 int found_lwz_284 = 0;
5634 for (ptk = 0; ptk < 20; ++ptk) {
5636 if (!*ins || *ins == blr_ins)
5638 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5643 if (!found_lwz_284) {
5644 tls_mode = TLS_MODE_FAILED;
5647 tls_mode = TLS_MODE_LTHREADS;
5648 } else if (*ins == li_0x48) {
5650 /* uncond branch to the real method */
5651 if ((*ins >> 26) == 18) {
5653 val = (*ins & ~3) << 6;
5657 ins = (guint32*)(long)val;
5659 ins = (guint32*) ((char*)ins + val);
5661 code = (guint32*)&val;
5662 ppc_li (code, ppc_r0, 0x7FF2);
5663 if (ins [1] == val) {
5664 /* Darwin on G4, implement */
5665 tls_mode = TLS_MODE_FAILED;
5668 code = (guint32*)&val;
5669 ppc_mfspr (code, ppc_r3, 104);
5670 if (ins [1] != val) {
5671 tls_mode = TLS_MODE_FAILED;
5674 tls_mode = TLS_MODE_DARWIN_G5;
5677 tls_mode = TLS_MODE_FAILED;
5681 tls_mode = TLS_MODE_FAILED;
5687 if (tls_mode == TLS_MODE_DETECT)
5688 tls_mode = TLS_MODE_FAILED;
5689 if (tls_mode == TLS_MODE_FAILED)
5691 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5692 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5696 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5697 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5698 if (lmf_pthread_key == -1) {
5699 guint32 ptk = mono_jit_tls_id;
5701 /*g_print ("MonoLMF at: %d\n", ptk);*/
5702 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5703 init_tls_failed = 1;
5706 lmf_pthread_key = ptk;
5715 mono_arch_finish_init (void)
5717 setup_tls_access ();
5721 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5725 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5727 #define LOADSTORE_SIZE 4
5728 #define JUMP_IMM_SIZE 12
5729 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5730 #define ENABLE_WRONG_METHOD_CHECK 0
5733 * LOCKING: called with the domain lock held
5736 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5737 gpointer fail_tramp)
5741 guint8 *code, *start;
5743 for (i = 0; i < count; ++i) {
5744 MonoIMTCheckItem *item = imt_entries [i];
5745 if (item->is_equals) {
5746 if (item->check_target_idx) {
5747 if (!item->compare_done)
5748 item->chunk_size += CMP_SIZE;
5749 if (item->has_target_code)
5750 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5752 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5755 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5756 if (!item->has_target_code)
5757 item->chunk_size += LOADSTORE_SIZE;
5759 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5760 #if ENABLE_WRONG_METHOD_CHECK
5761 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5766 item->chunk_size += CMP_SIZE + BR_SIZE;
5767 imt_entries [item->check_target_idx]->compare_done = TRUE;
5769 size += item->chunk_size;
5771 /* the initial load of the vtable address */
5772 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5774 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5776 code = mono_domain_code_reserve (domain, size);
5781 * We need to save and restore r12 because it might be
5782 * used by the caller as the vtable register, so
5783 * clobbering it will trip up the magic trampoline.
5785 * FIXME: Get rid of this by making sure that r12 is
5786 * not used as the vtable register in interface calls.
5788 ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5789 ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5791 for (i = 0; i < count; ++i) {
5792 MonoIMTCheckItem *item = imt_entries [i];
5793 item->code_target = code;
5794 if (item->is_equals) {
5795 if (item->check_target_idx) {
5796 if (!item->compare_done) {
5797 ppc_load (code, ppc_r0, (gsize)item->key);
5798 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5800 item->jmp_code = code;
5801 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5802 if (item->has_target_code) {
5803 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5805 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5806 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5808 ppc_mtctr (code, ppc_r0);
5809 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5812 ppc_load (code, ppc_r0, (gulong)item->key);
5813 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5814 item->jmp_code = code;
5815 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5816 if (item->has_target_code) {
5817 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5820 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5821 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5823 ppc_mtctr (code, ppc_r0);
5824 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5825 ppc_patch (item->jmp_code, code);
5826 ppc_load_ptr (code, ppc_r0, fail_tramp);
5827 ppc_mtctr (code, ppc_r0);
5828 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5829 item->jmp_code = NULL;
5831 /* enable the commented code to assert on wrong method */
5832 #if ENABLE_WRONG_METHOD_CHECK
5833 ppc_load (code, ppc_r0, (guint32)item->key);
5834 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5835 item->jmp_code = code;
5836 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5838 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5839 ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5840 ppc_mtctr (code, ppc_r0);
5841 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5842 #if ENABLE_WRONG_METHOD_CHECK
5843 ppc_patch (item->jmp_code, code);
5845 item->jmp_code = NULL;
5850 ppc_load (code, ppc_r0, (gulong)item->key);
5851 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5852 item->jmp_code = code;
5853 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5856 /* patch the branches to get to the target items */
5857 for (i = 0; i < count; ++i) {
5858 MonoIMTCheckItem *item = imt_entries [i];
5859 if (item->jmp_code) {
5860 if (item->check_target_idx) {
5861 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5867 mono_stats.imt_thunks_size += code - start;
5868 g_assert (code - start <= size);
5869 mono_arch_flush_icache (start, size);
5871 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5877 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5879 mgreg_t *r = (mgreg_t*)regs;
5881 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5885 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5887 mgreg_t *r = (mgreg_t*)regs;
5889 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5893 mono_arch_get_cie_program (void)
5897 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5903 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5910 mono_arch_print_tree (MonoInst *tree, int arity)
5916 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5919 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5921 g_assert (reg >= ppc_r13);
5923 return ctx->regs [reg - ppc_r13];
5927 mono_arch_get_patch_offset (guint8 *code)
5933 * mono_aot_emit_load_got_addr:
5935 * Emit code to load the got address.
5936 * On PPC, the result is placed into r30.
5939 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5942 ppc_mflr (code, ppc_r30);
5944 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5946 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5947 /* arch_emit_got_address () patches this */
5948 #if defined(TARGET_POWERPC64)
5954 ppc_load32 (code, ppc_r0, 0);
5955 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5962 * mono_ppc_emit_load_aotconst:
5964 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5965 * TARGET from the mscorlib GOT in full-aot code.
5966 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5970 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5972 /* Load the mscorlib got address */
5973 ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5974 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5975 /* arch_emit_got_access () patches this */
5976 ppc_load32 (code, ppc_r0, 0);
5977 ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5982 /* Soft Debug support */
5983 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5990 * mono_arch_set_breakpoint:
5992 * See mini-amd64.c for docs.
5995 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5998 guint8 *orig_code = code;
6000 ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6001 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6003 g_assert (code - orig_code == BREAKPOINT_SIZE);
6005 mono_arch_flush_icache (orig_code, code - orig_code);
6009 * mono_arch_clear_breakpoint:
6011 * See mini-amd64.c for docs.
6014 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6019 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6022 mono_arch_flush_icache (ip, code - ip);
6026 * mono_arch_is_breakpoint_event:
6028 * See mini-amd64.c for docs.
6031 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6033 siginfo_t* sinfo = (siginfo_t*) info;
6034 /* Sometimes the address is off by 4 */
6035 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6042 * mono_arch_skip_breakpoint:
6044 * See mini-amd64.c for docs.
6047 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6049 /* skip the ldptr */
6050 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6058 * mono_arch_start_single_stepping:
6060 * See mini-amd64.c for docs.
6063 mono_arch_start_single_stepping (void)
6065 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6069 * mono_arch_stop_single_stepping:
6071 * See mini-amd64.c for docs.
6074 mono_arch_stop_single_stepping (void)
6076 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6080 * mono_arch_is_single_step_event:
6082 * See mini-amd64.c for docs.
6085 mono_arch_is_single_step_event (void *info, void *sigctx)
6087 siginfo_t* sinfo = (siginfo_t*) info;
6088 /* Sometimes the address is off by 4 */
6089 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6096 * mono_arch_skip_single_step:
6098 * See mini-amd64.c for docs.
6101 mono_arch_skip_single_step (MonoContext *ctx)
6103 /* skip the ldptr */
6104 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6108 * mono_arch_create_seq_point_info:
6110 * See mini-amd64.c for docs.
6113 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6120 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6122 ext->lmf.previous_lmf = prev_lmf;
6123 /* Mark that this is a MonoLMFExt */
6124 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6125 ext->lmf.ebp = (gssize)ext;
6131 mono_arch_opcode_supported (int opcode)
6134 case OP_ATOMIC_ADD_I4:
6135 case OP_ATOMIC_CAS_I4:
6136 #ifdef TARGET_POWERPC64
6137 case OP_ATOMIC_ADD_I8:
6138 case OP_ATOMIC_CAS_I8:
6148 // FIXME: To get the test case finally_block_ending_in_dead_bb to work properly we need to define the following
6149 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6150 // #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6153 mono_arch_create_handler_block_trampoline (void)