2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
29 #include <sys/sysctl.h>
35 #define FORCE_INDIR_CALL 1
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps = 0;
48 static int cachelinesize = 0;
49 static int cachelineinc = 0;
51 PPC_ICACHE_SNOOP = 1 << 0,
52 PPC_MULTIPLE_LS_UNITS = 1 << 1,
53 PPC_SMP_CAPABLE = 1 << 2,
56 PPC_MOVE_FPR_GPR = 1 << 5,
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex;
67 int mono_exc_esp_offset = 0;
68 static int tls_mode = TLS_MODE_DETECT;
69 static int lmf_pthread_key = -1;
70 static int monodomain_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
82 offsets_from_pthread_key (guint32 key, int *offset2)
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
161 if (reg >= 0 && reg < 32)
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
177 if (reg >= 0 && reg < 32)
182 /* this function overwrites r0, r11, r12 */
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
283 int k, frame_size = 0;
284 int size, align, pad;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
292 arg_info [0].offset = offset;
295 frame_size += sizeof (gpointer);
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
317 arg_info [k + 1].offset = offset;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
329 #ifdef __mono_ppc64__
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
349 mono_ppc_is_direct_call_sequence (guint32 *code)
351 #ifdef __mono_ppc64__
352 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
357 if (!is_load_sequence (&code [-8]))
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
361 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
363 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code [-8]);
366 return is_load_sequence (&code [-6]);
370 g_assert(*code == 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code [-1]) == 31 &&
374 ppc_opcode (code [-2]) == 24 &&
375 ppc_opcode (code [-3]) == 15;
379 #define MAX_ARCH_DELEGATE_PARAMS 7
382 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
384 guint8 *code, *start;
387 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
389 start = code = mono_global_codeman_reserve (size);
391 code = mono_ppc_create_pre_code_ftnptr (code);
393 /* Replace the this argument with the target */
394 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
395 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
396 /* it's a function descriptor */
397 /* Can't use ldptr as it doesn't work with r0 */
398 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
400 ppc_mtctr (code, ppc_r0);
401 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
402 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
404 g_assert ((code - start) <= size);
406 mono_arch_flush_icache (start, size);
410 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
411 start = code = mono_global_codeman_reserve (size);
413 code = mono_ppc_create_pre_code_ftnptr (code);
415 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
417 /* it's a function descriptor */
418 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
420 ppc_mtctr (code, ppc_r0);
421 /* slide down the arguments */
422 for (i = 0; i < param_count; ++i) {
423 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
425 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
427 g_assert ((code - start) <= size);
429 mono_arch_flush_icache (start, size);
433 *code_len = code - start;
439 mono_arch_get_delegate_invoke_impls (void)
446 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
447 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
449 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
450 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
451 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
458 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
460 guint8 *code, *start;
462 /* FIXME: Support more cases */
463 if (MONO_TYPE_ISSTRUCT (sig->ret))
467 static guint8* cached = NULL;
473 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
475 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
477 mono_memory_barrier ();
481 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
484 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
486 for (i = 0; i < sig->param_count; ++i)
487 if (!mono_is_regsize_var (sig->params [i]))
491 code = cache [sig->param_count];
496 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
497 start = mono_aot_get_trampoline (name);
500 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
503 mono_memory_barrier ();
505 cache [sig->param_count] = start;
511 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
513 mgreg_t *r = (mgreg_t*)regs;
515 return (gpointer)(gsize)r [ppc_r3];
523 #ifdef USE_ENVIRON_HACK
525 linux_find_auxv (int *count)
529 char **result = __environ;
530 /* Scan over the env vector looking for the ending NULL */
531 for (; *result != NULL; ++result) {
533 /* Bump the pointer one more step, which should be the auxv. */
535 vec = (AuxVec *)result;
536 if (vec->type != 22 /*AT_IGNOREPPC*/) {
540 while (vec->type != 0 /*AT_NULL*/) {
545 return (AuxVec *)result;
549 #define MAX_AUX_ENTRIES 128
551 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
552 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
554 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
556 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
557 #define ISA_64 0x40000000
559 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
560 #define ISA_MOVE_FPR_GPR 0x00000200
562 * Initialize the cpu to execute managed code.
565 mono_arch_cpu_init (void)
571 mib [1] = HW_CACHELINE;
572 len = sizeof (cachelinesize);
573 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
577 cachelineinc = cachelinesize;
579 #elif defined(__linux__)
580 AuxVec vec [MAX_AUX_ENTRIES];
581 int i, vec_entries = 0;
582 /* sadly this will work only with 2.6 kernels... */
583 FILE* f = fopen ("/proc/self/auxv", "rb");
585 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
587 #ifdef USE_ENVIRON_HACK
589 AuxVec *evec = linux_find_auxv (&vec_entries);
591 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
594 for (i = 0; i < vec_entries; i++) {
595 int type = vec [i].type;
596 if (type == 19) { /* AT_DCACHEBSIZE */
597 cachelinesize = vec [i].value;
599 } else if (type == 16) { /* AT_HWCAP */
600 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
601 cpu_hw_caps |= PPC_ICACHE_SNOOP;
602 if (vec [i].value & ISA_2X)
603 cpu_hw_caps |= PPC_ISA_2X;
604 if (vec [i].value & ISA_64)
605 cpu_hw_caps |= PPC_ISA_64;
606 if (vec [i].value & ISA_MOVE_FPR_GPR)
607 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
609 } else if (type == 15) { /* AT_PLATFORM */
610 const char *arch = (char*)vec [i].value;
611 if (strcmp (arch, "ppc970") == 0 ||
612 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
613 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
614 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
618 #elif defined(G_COMPILER_CODEWARRIOR)
621 #elif defined(MONO_CROSS_COMPILE)
623 //#error Need a way to get cache line size
628 cachelineinc = cachelinesize;
630 if (mono_cpu_count () > 1)
631 cpu_hw_caps |= PPC_SMP_CAPABLE;
635 * Initialize architecture specific code.
638 mono_arch_init (void)
640 InitializeCriticalSection (&mini_arch_mutex);
642 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
643 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
644 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
646 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
650 * Cleanup architecture specific code.
653 mono_arch_cleanup (void)
655 DeleteCriticalSection (&mini_arch_mutex);
659 * This function returns the optimizations supported on this cpu.
662 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
666 /* no ppc-specific optimizations yet */
671 #ifdef __mono_ppc64__
672 #define CASE_PPC32(c)
673 #define CASE_PPC64(c) case c:
675 #define CASE_PPC32(c) case c:
676 #define CASE_PPC64(c)
680 is_regsize_var (MonoType *t) {
683 t = mini_type_get_underlying_type (NULL, t);
687 CASE_PPC64 (MONO_TYPE_I8)
688 CASE_PPC64 (MONO_TYPE_U8)
692 case MONO_TYPE_FNPTR:
694 case MONO_TYPE_OBJECT:
695 case MONO_TYPE_STRING:
696 case MONO_TYPE_CLASS:
697 case MONO_TYPE_SZARRAY:
698 case MONO_TYPE_ARRAY:
700 case MONO_TYPE_GENERICINST:
701 if (!mono_type_generic_inst_is_valuetype (t))
704 case MONO_TYPE_VALUETYPE:
712 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
717 for (i = 0; i < cfg->num_varinfo; i++) {
718 MonoInst *ins = cfg->varinfo [i];
719 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
722 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
725 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
728 /* we can only allocate 32 bit values */
729 if (is_regsize_var (ins->inst_vtype)) {
730 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
731 g_assert (i == vmv->idx);
732 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
738 #endif /* ifndef DISABLE_JIT */
741 mono_arch_get_global_int_regs (MonoCompile *cfg)
745 if (cfg->frame_reg != ppc_sp)
747 /* ppc_r13 is used by the system on PPC EABI */
748 for (i = 14; i < top; ++i) {
750 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
751 * since the trampolines can clobber r11.
753 if (!(cfg->compile_aot && i == 29))
754 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
761 * mono_arch_regalloc_cost:
763 * Return the cost, in number of memory references, of the action of
764 * allocating the variable VMV into a register during global register
768 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
775 mono_arch_flush_icache (guint8 *code, gint size)
777 #ifdef MONO_CROSS_COMPILE
780 guint8 *endp, *start;
784 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
785 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
786 #if defined(G_COMPILER_CODEWARRIOR)
787 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
788 for (p = start; p < endp; p += cachelineinc) {
792 for (p = start; p < endp; p += cachelineinc) {
798 for (p = start; p < endp; p += cachelineinc) {
809 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
810 * The sync is required to insure that the store queue is completely empty.
811 * While the icbi performs no cache operations, icbi/isync is required to
812 * kill local prefetch.
814 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
816 asm ("icbi 0,%0;" : : "r"(code) : "memory");
820 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
821 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
822 for (p = start; p < endp; p += cachelineinc) {
823 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
826 for (p = start; p < endp; p += cachelineinc) {
827 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
832 for (p = start; p < endp; p += cachelineinc) {
833 /* for ISA2.0+ implementations we should not need any extra sync between the
834 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
835 * So I am not sure which chip had this problem but its not an issue on
836 * of the ISA V2 chips.
838 if (cpu_hw_caps & PPC_ISA_2X)
839 asm ("icbi 0,%0;" : : "r"(p) : "memory");
841 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
843 if (!(cpu_hw_caps & PPC_ISA_2X))
851 mono_arch_flush_register_windows (void)
856 #define ALWAYS_ON_STACK(s) s
857 #define FP_ALSO_IN_REG(s) s
859 #ifdef __mono_ppc64__
860 #define ALWAYS_ON_STACK(s) s
861 #define FP_ALSO_IN_REG(s) s
863 #define ALWAYS_ON_STACK(s)
864 #define FP_ALSO_IN_REG(s)
866 #define ALIGN_DOUBLES
879 guint32 vtsize; /* in param area */
881 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
882 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
883 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
884 guint8 bytes : 4; /* size in bytes - only valid for
885 RegTypeStructByVal if the struct fits
886 in one word, otherwise it's 0*/
895 gboolean vtype_retaddr;
903 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
905 #ifdef __mono_ppc64__
910 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
911 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
912 ainfo->reg = ppc_sp; /* in the caller */
913 ainfo->regtype = RegTypeBase;
914 *stack_size += sizeof (gpointer);
916 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
920 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
922 //*stack_size += (*stack_size % 8);
924 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
925 ainfo->reg = ppc_sp; /* in the caller */
926 ainfo->regtype = RegTypeBase;
933 ALWAYS_ON_STACK (*stack_size += 8);
941 #if defined(__APPLE__) || defined(__mono_ppc64__)
943 has_only_a_r48_field (MonoClass *klass)
947 gboolean have_field = FALSE;
949 while ((f = mono_class_get_fields (klass, &iter))) {
950 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
953 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
964 calculate_sizes (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
966 guint i, fr, gr, pstart;
967 int n = sig->hasthis + sig->param_count;
968 MonoType *simpletype;
969 guint32 stack_size = 0;
970 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
972 fr = PPC_FIRST_FPARG_REG;
973 gr = PPC_FIRST_ARG_REG;
975 /* FIXME: handle returning a struct */
976 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
977 cinfo->vtype_retaddr = TRUE;
983 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
984 * the first argument, allowing 'this' to be always passed in the first arg reg.
985 * Also do this if the first argument is a reference type, since virtual calls
986 * are sometimes made using calli without sig->hasthis set, like in the delegate
989 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
991 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
994 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
998 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
999 cinfo->struct_ret = cinfo->ret.reg;
1000 cinfo->vret_arg_index = 1;
1004 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1008 if (cinfo->vtype_retaddr) {
1009 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1010 cinfo->struct_ret = cinfo->ret.reg;
1014 DEBUG(printf("params: %d\n", sig->param_count));
1015 for (i = pstart; i < sig->param_count; ++i) {
1016 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1017 /* Prevent implicit arguments and sig_cookie from
1018 being passed in registers */
1019 gr = PPC_LAST_ARG_REG + 1;
1020 /* FIXME: don't we have to set fr, too? */
1021 /* Emit the signature cookie just before the implicit arguments */
1022 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1024 DEBUG(printf("param %d: ", i));
1025 if (sig->params [i]->byref) {
1026 DEBUG(printf("byref\n"));
1027 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1031 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1032 switch (simpletype->type) {
1033 case MONO_TYPE_BOOLEAN:
1036 cinfo->args [n].size = 1;
1037 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1040 case MONO_TYPE_CHAR:
1043 cinfo->args [n].size = 2;
1044 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1049 cinfo->args [n].size = 4;
1050 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1056 case MONO_TYPE_FNPTR:
1057 case MONO_TYPE_CLASS:
1058 case MONO_TYPE_OBJECT:
1059 case MONO_TYPE_STRING:
1060 case MONO_TYPE_SZARRAY:
1061 case MONO_TYPE_ARRAY:
1062 cinfo->args [n].size = sizeof (gpointer);
1063 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1066 case MONO_TYPE_GENERICINST:
1067 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1068 cinfo->args [n].size = sizeof (gpointer);
1069 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1074 case MONO_TYPE_VALUETYPE:
1075 case MONO_TYPE_TYPEDBYREF: {
1079 klass = mono_class_from_mono_type (sig->params [i]);
1080 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1081 size = sizeof (MonoTypedRef);
1082 else if (is_pinvoke)
1083 size = mono_class_native_size (klass, NULL);
1085 size = mono_class_value_size (klass, NULL);
1087 #if defined(__APPLE__) || defined(__mono_ppc64__)
1088 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1089 cinfo->args [n].size = size;
1091 /* It was 7, now it is 8 in LinuxPPC */
1092 if (fr <= PPC_LAST_FPARG_REG) {
1093 cinfo->args [n].regtype = RegTypeFP;
1094 cinfo->args [n].reg = fr;
1096 FP_ALSO_IN_REG (gr ++);
1098 FP_ALSO_IN_REG (gr ++);
1099 ALWAYS_ON_STACK (stack_size += size);
1101 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1102 cinfo->args [n].regtype = RegTypeBase;
1103 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1110 DEBUG(printf ("load %d bytes struct\n",
1111 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1113 #if PPC_PASS_STRUCTS_BY_VALUE
1115 int align_size = size;
1117 int rest = PPC_LAST_ARG_REG - gr + 1;
1120 align_size += (sizeof (gpointer) - 1);
1121 align_size &= ~(sizeof (gpointer) - 1);
1122 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1123 n_in_regs = MIN (rest, nregs);
1127 /* FIXME: check this */
1128 if (size >= 3 && size % 4 != 0)
1131 cinfo->args [n].regtype = RegTypeStructByVal;
1132 cinfo->args [n].vtregs = n_in_regs;
1133 cinfo->args [n].size = n_in_regs;
1134 cinfo->args [n].vtsize = nregs - n_in_regs;
1135 cinfo->args [n].reg = gr;
1137 #ifdef __mono_ppc64__
1138 if (nregs == 1 && is_pinvoke)
1139 cinfo->args [n].bytes = size;
1142 cinfo->args [n].bytes = 0;
1144 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1145 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1146 stack_size += nregs * sizeof (gpointer);
1149 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1150 cinfo->args [n].regtype = RegTypeStructByAddr;
1151 cinfo->args [n].vtsize = size;
1158 cinfo->args [n].size = 8;
1159 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1163 cinfo->args [n].size = 4;
1165 /* It was 7, now it is 8 in LinuxPPC */
1166 if (fr <= PPC_LAST_FPARG_REG) {
1167 cinfo->args [n].regtype = RegTypeFP;
1168 cinfo->args [n].reg = fr;
1170 FP_ALSO_IN_REG (gr ++);
1171 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1173 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1174 cinfo->args [n].regtype = RegTypeBase;
1175 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1176 stack_size += SIZEOF_REGISTER;
1181 cinfo->args [n].size = 8;
1182 /* It was 7, now it is 8 in LinuxPPC */
1183 if (fr <= PPC_LAST_FPARG_REG) {
1184 cinfo->args [n].regtype = RegTypeFP;
1185 cinfo->args [n].reg = fr;
1187 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1188 ALWAYS_ON_STACK (stack_size += 8);
1190 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1191 cinfo->args [n].regtype = RegTypeBase;
1192 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1198 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1202 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1203 /* Prevent implicit arguments and sig_cookie from
1204 being passed in registers */
1205 gr = PPC_LAST_ARG_REG + 1;
1206 /* Emit the signature cookie just before the implicit arguments */
1207 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1211 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1212 switch (simpletype->type) {
1213 case MONO_TYPE_BOOLEAN:
1218 case MONO_TYPE_CHAR:
1224 case MONO_TYPE_FNPTR:
1225 case MONO_TYPE_CLASS:
1226 case MONO_TYPE_OBJECT:
1227 case MONO_TYPE_SZARRAY:
1228 case MONO_TYPE_ARRAY:
1229 case MONO_TYPE_STRING:
1230 cinfo->ret.reg = ppc_r3;
1234 cinfo->ret.reg = ppc_r3;
1238 cinfo->ret.reg = ppc_f1;
1239 cinfo->ret.regtype = RegTypeFP;
1241 case MONO_TYPE_GENERICINST:
1242 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1243 cinfo->ret.reg = ppc_r3;
1247 case MONO_TYPE_VALUETYPE:
1249 case MONO_TYPE_TYPEDBYREF:
1250 case MONO_TYPE_VOID:
1253 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1257 /* align stack size to 16 */
1258 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1259 stack_size = (stack_size + 15) & ~15;
1261 cinfo->stack_usage = stack_size;
1266 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1268 #if !PPC_PASS_STRUCTS_BY_VALUE
1269 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1270 int num_structs = 0;
1273 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1276 for (i = 0; i < sig->param_count; ++i) {
1277 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1278 if (type->type == MONO_TYPE_VALUETYPE)
1283 cfg->tailcall_valuetype_addrs =
1284 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1285 for (i = 0; i < num_structs; ++i) {
1286 cfg->tailcall_valuetype_addrs [i] =
1287 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1288 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1295 * Set var information according to the calling convention. ppc version.
1296 * The locals var stuff should most likely be split in another method.
1299 mono_arch_allocate_vars (MonoCompile *m)
1301 MonoMethodSignature *sig;
1302 MonoMethodHeader *header;
1304 int i, offset, size, align, curinst;
1305 int frame_reg = ppc_sp;
1307 guint32 locals_stack_size, locals_stack_align;
1309 allocate_tailcall_valuetype_addrs (m);
1311 m->flags |= MONO_CFG_HAS_SPILLUP;
1313 /* allow room for the vararg method args: void* and long/double */
1314 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1315 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1316 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1317 * call convs needs to be handled this way.
1319 if (m->flags & MONO_CFG_HAS_VARARGS)
1320 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1321 /* gtk-sharp and other broken code will dllimport vararg functions even with
1322 * non-varargs signatures. Since there is little hope people will get this right
1323 * we assume they won't.
1325 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1326 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1331 * We use the frame register also for any method that has
1332 * exception clauses. This way, when the handlers are called,
1333 * the code will reference local variables using the frame reg instead of
1334 * the stack pointer: if we had to restore the stack pointer, we'd
1335 * corrupt the method frames that are already on the stack (since
1336 * filters get called before stack unwinding happens) when the filter
1337 * code would call any method (this also applies to finally etc.).
1339 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1340 frame_reg = ppc_r31;
1341 m->frame_reg = frame_reg;
1342 if (frame_reg != ppc_sp) {
1343 m->used_int_regs |= 1 << frame_reg;
1346 sig = mono_method_signature (m->method);
1350 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1351 m->ret->opcode = OP_REGVAR;
1352 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1354 /* FIXME: handle long values? */
1355 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1356 case MONO_TYPE_VOID:
1360 m->ret->opcode = OP_REGVAR;
1361 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1364 m->ret->opcode = OP_REGVAR;
1365 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1369 /* local vars are at a positive offset from the stack pointer */
1371 * also note that if the function uses alloca, we use ppc_r31
1372 * to point at the local variables.
1374 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1375 /* align the offset to 16 bytes: not sure this is needed here */
1377 //offset &= ~(16 - 1);
1379 /* add parameter area size for called functions */
1380 offset += m->param_area;
1382 offset &= ~(16 - 1);
1384 /* allow room to save the return value */
1385 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1388 /* the MonoLMF structure is stored just below the stack pointer */
1391 /* this stuff should not be needed on ppc and the new jit,
1392 * because a call on ppc to the handlers doesn't change the
1393 * stack pointer and the jist doesn't manipulate the stack pointer
1394 * for operations involving valuetypes.
1396 /* reserve space to store the esp */
1397 offset += sizeof (gpointer);
1399 /* this is a global constant */
1400 mono_exc_esp_offset = offset;
1403 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1404 offset += sizeof(gpointer) - 1;
1405 offset &= ~(sizeof(gpointer) - 1);
1407 m->vret_addr->opcode = OP_REGOFFSET;
1408 m->vret_addr->inst_basereg = frame_reg;
1409 m->vret_addr->inst_offset = offset;
1411 if (G_UNLIKELY (m->verbose_level > 1)) {
1412 printf ("vret_addr =");
1413 mono_print_ins (m->vret_addr);
1416 offset += sizeof(gpointer);
1419 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1420 if (locals_stack_align) {
1421 offset += (locals_stack_align - 1);
1422 offset &= ~(locals_stack_align - 1);
1424 for (i = m->locals_start; i < m->num_varinfo; i++) {
1425 if (offsets [i] != -1) {
1426 MonoInst *inst = m->varinfo [i];
1427 inst->opcode = OP_REGOFFSET;
1428 inst->inst_basereg = frame_reg;
1429 inst->inst_offset = offset + offsets [i];
1431 g_print ("allocating local %d (%s) to %d\n",
1432 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1436 offset += locals_stack_size;
1440 inst = m->args [curinst];
1441 if (inst->opcode != OP_REGVAR) {
1442 inst->opcode = OP_REGOFFSET;
1443 inst->inst_basereg = frame_reg;
1444 offset += sizeof (gpointer) - 1;
1445 offset &= ~(sizeof (gpointer) - 1);
1446 inst->inst_offset = offset;
1447 offset += sizeof (gpointer);
1452 for (i = 0; i < sig->param_count; ++i) {
1453 inst = m->args [curinst];
1454 if (inst->opcode != OP_REGVAR) {
1455 inst->opcode = OP_REGOFFSET;
1456 inst->inst_basereg = frame_reg;
1458 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1459 inst->backend.is_pinvoke = 1;
1461 size = mono_type_size (sig->params [i], &align);
1463 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1464 size = align = sizeof (gpointer);
1466 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1467 * they are saved using std in the prolog.
1469 align = sizeof (gpointer);
1470 offset += align - 1;
1471 offset &= ~(align - 1);
1472 inst->inst_offset = offset;
1478 /* some storage for fp conversions */
1481 m->arch.fp_conv_var_offset = offset;
1484 /* align the offset to 16 bytes */
1486 offset &= ~(16 - 1);
1489 m->stack_offset = offset;
1491 if (sig->call_convention == MONO_CALL_VARARG) {
1492 CallInfo *cinfo = calculate_sizes (m->generic_sharing_context, m->method->signature, m->method->signature->pinvoke);
1494 m->sig_cookie = cinfo->sig_cookie.offset;
1501 mono_arch_create_vars (MonoCompile *cfg)
1503 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1505 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1506 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1510 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1511 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1515 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1517 int sig_reg = mono_alloc_ireg (cfg);
1519 /* FIXME: Add support for signature tokens to AOT */
1520 cfg->disable_aot = TRUE;
1522 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1523 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1524 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1528 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1531 MonoMethodSignature *sig;
1535 sig = call->signature;
1536 n = sig->param_count + sig->hasthis;
1538 cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
1540 for (i = 0; i < n; ++i) {
1541 ArgInfo *ainfo = cinfo->args + i;
1544 if (i >= sig->hasthis)
1545 t = sig->params [i - sig->hasthis];
1547 t = &mono_defaults.int_class->byval_arg;
1548 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1550 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1551 emit_sig_cookie (cfg, call, cinfo);
1553 in = call->args [i];
1555 if (ainfo->regtype == RegTypeGeneral) {
1556 #ifndef __mono_ppc64__
1557 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1558 MONO_INST_NEW (cfg, ins, OP_MOVE);
1559 ins->dreg = mono_alloc_ireg (cfg);
1560 ins->sreg1 = in->dreg + 1;
1561 MONO_ADD_INS (cfg->cbb, ins);
1562 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1564 MONO_INST_NEW (cfg, ins, OP_MOVE);
1565 ins->dreg = mono_alloc_ireg (cfg);
1566 ins->sreg1 = in->dreg + 2;
1567 MONO_ADD_INS (cfg->cbb, ins);
1568 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1572 MONO_INST_NEW (cfg, ins, OP_MOVE);
1573 ins->dreg = mono_alloc_ireg (cfg);
1574 ins->sreg1 = in->dreg;
1575 MONO_ADD_INS (cfg->cbb, ins);
1577 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1579 } else if (ainfo->regtype == RegTypeStructByAddr) {
1580 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1581 ins->opcode = OP_OUTARG_VT;
1582 ins->sreg1 = in->dreg;
1583 ins->klass = in->klass;
1584 ins->inst_p0 = call;
1585 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1586 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1587 MONO_ADD_INS (cfg->cbb, ins);
1588 } else if (ainfo->regtype == RegTypeStructByVal) {
1589 /* this is further handled in mono_arch_emit_outarg_vt () */
1590 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1591 ins->opcode = OP_OUTARG_VT;
1592 ins->sreg1 = in->dreg;
1593 ins->klass = in->klass;
1594 ins->inst_p0 = call;
1595 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1596 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1597 MONO_ADD_INS (cfg->cbb, ins);
1598 } else if (ainfo->regtype == RegTypeBase) {
1599 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1600 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1601 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1602 if (t->type == MONO_TYPE_R8)
1603 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1605 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1607 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1609 } else if (ainfo->regtype == RegTypeFP) {
1610 if (t->type == MONO_TYPE_VALUETYPE) {
1611 /* this is further handled in mono_arch_emit_outarg_vt () */
1612 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1613 ins->opcode = OP_OUTARG_VT;
1614 ins->sreg1 = in->dreg;
1615 ins->klass = in->klass;
1616 ins->inst_p0 = call;
1617 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1618 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1619 MONO_ADD_INS (cfg->cbb, ins);
1621 cfg->flags |= MONO_CFG_HAS_FPOUT;
1623 int dreg = mono_alloc_freg (cfg);
1625 if (ainfo->size == 4) {
1626 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1628 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1630 ins->sreg1 = in->dreg;
1631 MONO_ADD_INS (cfg->cbb, ins);
1634 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1635 cfg->flags |= MONO_CFG_HAS_FPOUT;
1638 g_assert_not_reached ();
1642 /* Emit the signature cookie in the case that there is no
1643 additional argument */
1644 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1645 emit_sig_cookie (cfg, call, cinfo);
1647 if (cinfo->struct_ret) {
1650 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1651 vtarg->sreg1 = call->vret_var->dreg;
1652 vtarg->dreg = mono_alloc_preg (cfg);
1653 MONO_ADD_INS (cfg->cbb, vtarg);
1655 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1658 call->stack_usage = cinfo->stack_usage;
1659 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1660 cfg->flags |= MONO_CFG_HAS_CALLS;
1668 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1670 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1671 ArgInfo *ainfo = ins->inst_p1;
1672 int ovf_size = ainfo->vtsize;
1673 int doffset = ainfo->offset;
1674 int i, soffset, dreg;
1676 if (ainfo->regtype == RegTypeStructByVal) {
1683 * Darwin pinvokes needs some special handling for 1
1684 * and 2 byte arguments
1686 g_assert (ins->klass);
1687 if (call->signature->pinvoke)
1688 size = mono_class_native_size (ins->klass, NULL);
1689 if (size == 2 || size == 1) {
1690 int tmpr = mono_alloc_ireg (cfg);
1692 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1694 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1695 dreg = mono_alloc_ireg (cfg);
1696 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1697 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1700 for (i = 0; i < ainfo->vtregs; ++i) {
1701 int antipadding = 0;
1704 antipadding = sizeof (gpointer) - ainfo->bytes;
1706 dreg = mono_alloc_ireg (cfg);
1707 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1709 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1710 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1711 soffset += sizeof (gpointer);
1714 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1715 } else if (ainfo->regtype == RegTypeFP) {
1716 int tmpr = mono_alloc_freg (cfg);
1717 if (ainfo->size == 4)
1718 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1720 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1721 dreg = mono_alloc_freg (cfg);
1722 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1723 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1725 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1729 /* FIXME: alignment? */
1730 if (call->signature->pinvoke) {
1731 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1732 vtcopy->backend.is_pinvoke = 1;
1734 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1737 g_assert (ovf_size > 0);
1739 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1740 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1743 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1745 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1750 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1752 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1753 mono_method_signature (method)->ret);
1756 #ifndef __mono_ppc64__
1757 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1760 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1761 ins->sreg1 = val->dreg + 1;
1762 ins->sreg2 = val->dreg + 2;
1763 MONO_ADD_INS (cfg->cbb, ins);
1767 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1768 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1772 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1775 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1777 mono_arch_is_inst_imm (gint64 imm)
1782 #endif /* DISABLE_JIT */
1785 * Allow tracing to work with this interface (with an optional argument)
1789 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1793 ppc_load_ptr (code, ppc_r3, cfg->method);
1794 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1795 ppc_load_func (code, ppc_r0, func);
1796 ppc_mtlr (code, ppc_r0);
1810 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1813 int save_mode = SAVE_NONE;
1815 MonoMethod *method = cfg->method;
1816 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1817 mono_method_signature (method)->ret)->type;
1818 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1822 offset = code - cfg->native_code;
1823 /* we need about 16 instructions */
1824 if (offset > (cfg->code_size - 16 * 4)) {
1825 cfg->code_size *= 2;
1826 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1827 code = cfg->native_code + offset;
1831 case MONO_TYPE_VOID:
1832 /* special case string .ctor icall */
1833 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1834 save_mode = SAVE_ONE;
1836 save_mode = SAVE_NONE;
1838 #ifndef __mono_ppc64__
1841 save_mode = SAVE_TWO;
1846 save_mode = SAVE_FP;
1848 case MONO_TYPE_VALUETYPE:
1849 save_mode = SAVE_STRUCT;
1852 save_mode = SAVE_ONE;
1856 switch (save_mode) {
1858 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1859 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1860 if (enable_arguments) {
1861 ppc_mr (code, ppc_r5, ppc_r4);
1862 ppc_mr (code, ppc_r4, ppc_r3);
1866 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1867 if (enable_arguments) {
1868 ppc_mr (code, ppc_r4, ppc_r3);
1872 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1873 if (enable_arguments) {
1874 /* FIXME: what reg? */
1875 ppc_fmr (code, ppc_f3, ppc_f1);
1876 /* FIXME: use 8 byte load on PPC64 */
1877 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1878 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1882 if (enable_arguments) {
1883 /* FIXME: get the actual address */
1884 ppc_mr (code, ppc_r4, ppc_r3);
1892 ppc_load_ptr (code, ppc_r3, cfg->method);
1893 ppc_load_func (code, ppc_r0, func);
1894 ppc_mtlr (code, ppc_r0);
1897 switch (save_mode) {
1899 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1900 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1903 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1906 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1916 * Conditional branches have a small offset, so if it is likely overflowed,
1917 * we do a branch to the end of the method (uncond branches have much larger
1918 * offsets) where we perform the conditional and jump back unconditionally.
1919 * It's slightly slower, since we add two uncond branches, but it's very simple
1920 * with the current patch implementation and such large methods are likely not
1921 * going to be perf critical anyway.
1926 const char *exception;
1933 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1934 if (0 && ins->inst_true_bb->native_offset) { \
1935 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1937 int br_disp = ins->inst_true_bb->max_offset - offset; \
1938 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1939 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1940 ovfj->data.bb = ins->inst_true_bb; \
1941 ovfj->ip_offset = 0; \
1942 ovfj->b0_cond = (b0); \
1943 ovfj->b1_cond = (b1); \
1944 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1947 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1948 ppc_bc (code, (b0), (b1), 0); \
1952 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1954 /* emit an exception if condition is fail
1956 * We assign the extra code used to throw the implicit exceptions
1957 * to cfg->bb_exit as far as the big branch handling is concerned
1959 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1961 int br_disp = cfg->bb_exit->max_offset - offset; \
1962 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1963 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1964 ovfj->data.exception = (exc_name); \
1965 ovfj->ip_offset = code - cfg->native_code; \
1966 ovfj->b0_cond = (b0); \
1967 ovfj->b1_cond = (b1); \
1968 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1970 cfg->bb_exit->max_offset += 24; \
1972 mono_add_patch_info (cfg, code - cfg->native_code, \
1973 MONO_PATCH_INFO_EXC, exc_name); \
1974 ppc_bcl (code, (b0), (b1), 0); \
1978 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1981 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1986 normalize_opcode (int opcode)
1989 #ifndef __mono_ilp32__
1990 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1991 return OP_LOAD_MEMBASE;
1992 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1993 return OP_LOAD_MEMINDEX;
1994 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1995 return OP_STORE_MEMBASE_REG;
1996 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1997 return OP_STORE_MEMBASE_IMM;
1998 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1999 return OP_STORE_MEMINDEX;
2001 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2003 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2004 return OP_SHR_UN_IMM;
2011 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2013 MonoInst *ins, *n, *last_ins = NULL;
2015 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2016 switch (normalize_opcode (ins->opcode)) {
2018 /* remove unnecessary multiplication with 1 */
2019 if (ins->inst_imm == 1) {
2020 if (ins->dreg != ins->sreg1) {
2021 ins->opcode = OP_MOVE;
2023 MONO_DELETE_INS (bb, ins);
2027 int power2 = mono_is_power_of_two (ins->inst_imm);
2029 ins->opcode = OP_SHL_IMM;
2030 ins->inst_imm = power2;
2034 case OP_LOAD_MEMBASE:
2036 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2037 * OP_LOAD_MEMBASE offset(basereg), reg
2039 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2040 ins->inst_basereg == last_ins->inst_destbasereg &&
2041 ins->inst_offset == last_ins->inst_offset) {
2042 if (ins->dreg == last_ins->sreg1) {
2043 MONO_DELETE_INS (bb, ins);
2046 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2047 ins->opcode = OP_MOVE;
2048 ins->sreg1 = last_ins->sreg1;
2052 * Note: reg1 must be different from the basereg in the second load
2053 * OP_LOAD_MEMBASE offset(basereg), reg1
2054 * OP_LOAD_MEMBASE offset(basereg), reg2
2056 * OP_LOAD_MEMBASE offset(basereg), reg1
2057 * OP_MOVE reg1, reg2
2059 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2060 ins->inst_basereg != last_ins->dreg &&
2061 ins->inst_basereg == last_ins->inst_basereg &&
2062 ins->inst_offset == last_ins->inst_offset) {
2064 if (ins->dreg == last_ins->dreg) {
2065 MONO_DELETE_INS (bb, ins);
2068 ins->opcode = OP_MOVE;
2069 ins->sreg1 = last_ins->dreg;
2072 //g_assert_not_reached ();
2076 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2077 * OP_LOAD_MEMBASE offset(basereg), reg
2079 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2080 * OP_ICONST reg, imm
2082 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2083 ins->inst_basereg == last_ins->inst_destbasereg &&
2084 ins->inst_offset == last_ins->inst_offset) {
2085 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2086 ins->opcode = OP_ICONST;
2087 ins->inst_c0 = last_ins->inst_imm;
2088 g_assert_not_reached (); // check this rule
2092 case OP_LOADU1_MEMBASE:
2093 case OP_LOADI1_MEMBASE:
2094 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2095 ins->inst_basereg == last_ins->inst_destbasereg &&
2096 ins->inst_offset == last_ins->inst_offset) {
2097 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2098 ins->sreg1 = last_ins->sreg1;
2101 case OP_LOADU2_MEMBASE:
2102 case OP_LOADI2_MEMBASE:
2103 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2104 ins->inst_basereg == last_ins->inst_destbasereg &&
2105 ins->inst_offset == last_ins->inst_offset) {
2106 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2107 ins->sreg1 = last_ins->sreg1;
2110 #ifdef __mono_ppc64__
2111 case OP_LOADU4_MEMBASE:
2112 case OP_LOADI4_MEMBASE:
2113 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2114 ins->inst_basereg == last_ins->inst_destbasereg &&
2115 ins->inst_offset == last_ins->inst_offset) {
2116 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2117 ins->sreg1 = last_ins->sreg1;
2122 ins->opcode = OP_MOVE;
2126 if (ins->dreg == ins->sreg1) {
2127 MONO_DELETE_INS (bb, ins);
2131 * OP_MOVE sreg, dreg
2132 * OP_MOVE dreg, sreg
2134 if (last_ins && last_ins->opcode == OP_MOVE &&
2135 ins->sreg1 == last_ins->dreg &&
2136 ins->dreg == last_ins->sreg1) {
2137 MONO_DELETE_INS (bb, ins);
2145 bb->last_ins = last_ins;
2149 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2151 switch (ins->opcode) {
2152 case OP_ICONV_TO_R_UN: {
2153 #if G_BYTE_ORDER == G_BIG_ENDIAN
2154 static const guint64 adjust_val = 0x4330000000000000ULL;
2156 static const guint64 adjust_val = 0x0000000000003043ULL;
2158 int msw_reg = mono_alloc_ireg (cfg);
2159 int adj_reg = mono_alloc_freg (cfg);
2160 int tmp_reg = mono_alloc_freg (cfg);
2161 int basereg = ppc_sp;
2163 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2164 if (!ppc_is_imm16 (offset + 4)) {
2165 basereg = mono_alloc_ireg (cfg);
2166 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2168 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2169 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2170 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2171 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2173 ins->opcode = OP_NOP;
2176 #ifndef __mono_ppc64__
2177 case OP_ICONV_TO_R4:
2178 case OP_ICONV_TO_R8: {
2179 /* If we have a PPC_FEATURE_64 machine we can avoid
2180 this and use the fcfid instruction. Otherwise
2181 on an old 32-bit chip and we have to do this the
2183 if (!(cpu_hw_caps & PPC_ISA_64)) {
2184 /* FIXME: change precision for CEE_CONV_R4 */
2185 static const guint64 adjust_val = 0x4330000080000000ULL;
2186 int msw_reg = mono_alloc_ireg (cfg);
2187 int xored = mono_alloc_ireg (cfg);
2188 int adj_reg = mono_alloc_freg (cfg);
2189 int tmp_reg = mono_alloc_freg (cfg);
2190 int basereg = ppc_sp;
2192 if (!ppc_is_imm16 (offset + 4)) {
2193 basereg = mono_alloc_ireg (cfg);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2196 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2197 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2199 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2200 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2201 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2203 if (ins->opcode == OP_ICONV_TO_R4)
2204 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2205 ins->opcode = OP_NOP;
2211 int msw_reg = mono_alloc_ireg (cfg);
2212 int basereg = ppc_sp;
2214 if (!ppc_is_imm16 (offset + 4)) {
2215 basereg = mono_alloc_ireg (cfg);
2216 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2218 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2219 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2220 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2221 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2222 ins->opcode = OP_NOP;
2225 #ifdef __mono_ppc64__
2227 case OP_IADD_OVF_UN:
2229 int shifted1_reg = mono_alloc_ireg (cfg);
2230 int shifted2_reg = mono_alloc_ireg (cfg);
2231 int result_shifted_reg = mono_alloc_ireg (cfg);
2233 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2234 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2235 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2236 if (ins->opcode == OP_IADD_OVF_UN)
2237 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2240 ins->opcode = OP_NOP;
2247 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2249 switch (ins->opcode) {
2251 /* ADC sets the condition code */
2252 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2253 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2256 case OP_LADD_OVF_UN:
2257 /* ADC sets the condition code */
2258 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2263 /* SBB sets the condition code */
2264 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2268 case OP_LSUB_OVF_UN:
2269 /* SBB sets the condition code */
2270 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2275 /* From gcc generated code */
2276 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2277 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2286 * the branch_b0_table should maintain the order of these
2300 branch_b0_table [] = {
2315 branch_b1_table [] = {
2329 #define NEW_INS(cfg,dest,op) do { \
2330 MONO_INST_NEW((cfg), (dest), (op)); \
2331 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2335 map_to_reg_reg_op (int op)
2344 case OP_COMPARE_IMM:
2346 case OP_ICOMPARE_IMM:
2348 case OP_LCOMPARE_IMM:
2364 case OP_LOAD_MEMBASE:
2365 return OP_LOAD_MEMINDEX;
2366 case OP_LOADI4_MEMBASE:
2367 return OP_LOADI4_MEMINDEX;
2368 case OP_LOADU4_MEMBASE:
2369 return OP_LOADU4_MEMINDEX;
2370 case OP_LOADI8_MEMBASE:
2371 return OP_LOADI8_MEMINDEX;
2372 case OP_LOADU1_MEMBASE:
2373 return OP_LOADU1_MEMINDEX;
2374 case OP_LOADI2_MEMBASE:
2375 return OP_LOADI2_MEMINDEX;
2376 case OP_LOADU2_MEMBASE:
2377 return OP_LOADU2_MEMINDEX;
2378 case OP_LOADI1_MEMBASE:
2379 return OP_LOADI1_MEMINDEX;
2380 case OP_LOADR4_MEMBASE:
2381 return OP_LOADR4_MEMINDEX;
2382 case OP_LOADR8_MEMBASE:
2383 return OP_LOADR8_MEMINDEX;
2384 case OP_STOREI1_MEMBASE_REG:
2385 return OP_STOREI1_MEMINDEX;
2386 case OP_STOREI2_MEMBASE_REG:
2387 return OP_STOREI2_MEMINDEX;
2388 case OP_STOREI4_MEMBASE_REG:
2389 return OP_STOREI4_MEMINDEX;
2390 case OP_STOREI8_MEMBASE_REG:
2391 return OP_STOREI8_MEMINDEX;
2392 case OP_STORE_MEMBASE_REG:
2393 return OP_STORE_MEMINDEX;
2394 case OP_STORER4_MEMBASE_REG:
2395 return OP_STORER4_MEMINDEX;
2396 case OP_STORER8_MEMBASE_REG:
2397 return OP_STORER8_MEMINDEX;
2398 case OP_STORE_MEMBASE_IMM:
2399 return OP_STORE_MEMBASE_REG;
2400 case OP_STOREI1_MEMBASE_IMM:
2401 return OP_STOREI1_MEMBASE_REG;
2402 case OP_STOREI2_MEMBASE_IMM:
2403 return OP_STOREI2_MEMBASE_REG;
2404 case OP_STOREI4_MEMBASE_IMM:
2405 return OP_STOREI4_MEMBASE_REG;
2406 case OP_STOREI8_MEMBASE_IMM:
2407 return OP_STOREI8_MEMBASE_REG;
2409 return mono_op_imm_to_op (op);
2412 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2414 #define compare_opcode_is_unsigned(opcode) \
2415 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2416 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2417 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2418 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2419 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2420 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2421 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2422 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2425 * Remove from the instruction list the instructions that can't be
2426 * represented with very simple instructions with no register
2430 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2432 MonoInst *ins, *next, *temp, *last_ins = NULL;
2435 MONO_BB_FOR_EACH_INS (bb, ins) {
2437 switch (ins->opcode) {
2438 case OP_IDIV_UN_IMM:
2441 case OP_IREM_UN_IMM:
2442 NEW_INS (cfg, temp, OP_ICONST);
2443 temp->inst_c0 = ins->inst_imm;
2444 temp->dreg = mono_alloc_ireg (cfg);
2445 ins->sreg2 = temp->dreg;
2446 if (ins->opcode == OP_IDIV_IMM)
2447 ins->opcode = OP_IDIV;
2448 else if (ins->opcode == OP_IREM_IMM)
2449 ins->opcode = OP_IREM;
2450 else if (ins->opcode == OP_IDIV_UN_IMM)
2451 ins->opcode = OP_IDIV_UN;
2452 else if (ins->opcode == OP_IREM_UN_IMM)
2453 ins->opcode = OP_IREM_UN;
2455 /* handle rem separately */
2459 CASE_PPC64 (OP_LREM)
2460 CASE_PPC64 (OP_LREM_UN) {
2462 /* we change a rem dest, src1, src2 to
2463 * div temp1, src1, src2
2464 * mul temp2, temp1, src2
2465 * sub dest, src1, temp2
2467 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2468 NEW_INS (cfg, mul, OP_IMUL);
2469 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2470 ins->opcode = OP_ISUB;
2472 NEW_INS (cfg, mul, OP_LMUL);
2473 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2474 ins->opcode = OP_LSUB;
2476 temp->sreg1 = ins->sreg1;
2477 temp->sreg2 = ins->sreg2;
2478 temp->dreg = mono_alloc_ireg (cfg);
2479 mul->sreg1 = temp->dreg;
2480 mul->sreg2 = ins->sreg2;
2481 mul->dreg = mono_alloc_ireg (cfg);
2482 ins->sreg2 = mul->dreg;
2486 CASE_PPC64 (OP_LADD_IMM)
2489 if (!ppc_is_imm16 (ins->inst_imm)) {
2490 NEW_INS (cfg, temp, OP_ICONST);
2491 temp->inst_c0 = ins->inst_imm;
2492 temp->dreg = mono_alloc_ireg (cfg);
2493 ins->sreg2 = temp->dreg;
2494 ins->opcode = map_to_reg_reg_op (ins->opcode);
2498 CASE_PPC64 (OP_LSUB_IMM)
2500 if (!ppc_is_imm16 (-ins->inst_imm)) {
2501 NEW_INS (cfg, temp, OP_ICONST);
2502 temp->inst_c0 = ins->inst_imm;
2503 temp->dreg = mono_alloc_ireg (cfg);
2504 ins->sreg2 = temp->dreg;
2505 ins->opcode = map_to_reg_reg_op (ins->opcode);
2517 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2518 #ifdef __mono_ppc64__
2519 if (ins->inst_imm & 0xffffffff00000000ULL)
2523 NEW_INS (cfg, temp, OP_ICONST);
2524 temp->inst_c0 = ins->inst_imm;
2525 temp->dreg = mono_alloc_ireg (cfg);
2526 ins->sreg2 = temp->dreg;
2527 ins->opcode = map_to_reg_reg_op (ins->opcode);
2536 NEW_INS (cfg, temp, OP_ICONST);
2537 temp->inst_c0 = ins->inst_imm;
2538 temp->dreg = mono_alloc_ireg (cfg);
2539 ins->sreg2 = temp->dreg;
2540 ins->opcode = map_to_reg_reg_op (ins->opcode);
2542 case OP_COMPARE_IMM:
2543 case OP_ICOMPARE_IMM:
2544 CASE_PPC64 (OP_LCOMPARE_IMM)
2546 /* Branch opts can eliminate the branch */
2547 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2548 ins->opcode = OP_NOP;
2552 if (compare_opcode_is_unsigned (next->opcode)) {
2553 if (!ppc_is_uimm16 (ins->inst_imm)) {
2554 NEW_INS (cfg, temp, OP_ICONST);
2555 temp->inst_c0 = ins->inst_imm;
2556 temp->dreg = mono_alloc_ireg (cfg);
2557 ins->sreg2 = temp->dreg;
2558 ins->opcode = map_to_reg_reg_op (ins->opcode);
2561 if (!ppc_is_imm16 (ins->inst_imm)) {
2562 NEW_INS (cfg, temp, OP_ICONST);
2563 temp->inst_c0 = ins->inst_imm;
2564 temp->dreg = mono_alloc_ireg (cfg);
2565 ins->sreg2 = temp->dreg;
2566 ins->opcode = map_to_reg_reg_op (ins->opcode);
2572 if (ins->inst_imm == 1) {
2573 ins->opcode = OP_MOVE;
2576 if (ins->inst_imm == 0) {
2577 ins->opcode = OP_ICONST;
2581 imm = mono_is_power_of_two (ins->inst_imm);
2583 ins->opcode = OP_SHL_IMM;
2584 ins->inst_imm = imm;
2587 if (!ppc_is_imm16 (ins->inst_imm)) {
2588 NEW_INS (cfg, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2592 ins->opcode = map_to_reg_reg_op (ins->opcode);
2595 case OP_LOCALLOC_IMM:
2596 NEW_INS (cfg, temp, OP_ICONST);
2597 temp->inst_c0 = ins->inst_imm;
2598 temp->dreg = mono_alloc_ireg (cfg);
2599 ins->sreg1 = temp->dreg;
2600 ins->opcode = OP_LOCALLOC;
2602 case OP_LOAD_MEMBASE:
2603 case OP_LOADI4_MEMBASE:
2604 CASE_PPC64 (OP_LOADI8_MEMBASE)
2605 case OP_LOADU4_MEMBASE:
2606 case OP_LOADI2_MEMBASE:
2607 case OP_LOADU2_MEMBASE:
2608 case OP_LOADI1_MEMBASE:
2609 case OP_LOADU1_MEMBASE:
2610 case OP_LOADR4_MEMBASE:
2611 case OP_LOADR8_MEMBASE:
2612 case OP_STORE_MEMBASE_REG:
2613 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2614 case OP_STOREI4_MEMBASE_REG:
2615 case OP_STOREI2_MEMBASE_REG:
2616 case OP_STOREI1_MEMBASE_REG:
2617 case OP_STORER4_MEMBASE_REG:
2618 case OP_STORER8_MEMBASE_REG:
2619 /* we can do two things: load the immed in a register
2620 * and use an indexed load, or see if the immed can be
2621 * represented as an ad_imm + a load with a smaller offset
2622 * that fits. We just do the first for now, optimize later.
2624 if (ppc_is_imm16 (ins->inst_offset))
2626 NEW_INS (cfg, temp, OP_ICONST);
2627 temp->inst_c0 = ins->inst_offset;
2628 temp->dreg = mono_alloc_ireg (cfg);
2629 ins->sreg2 = temp->dreg;
2630 ins->opcode = map_to_reg_reg_op (ins->opcode);
2632 case OP_STORE_MEMBASE_IMM:
2633 case OP_STOREI1_MEMBASE_IMM:
2634 case OP_STOREI2_MEMBASE_IMM:
2635 case OP_STOREI4_MEMBASE_IMM:
2636 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2637 NEW_INS (cfg, temp, OP_ICONST);
2638 temp->inst_c0 = ins->inst_imm;
2639 temp->dreg = mono_alloc_ireg (cfg);
2640 ins->sreg1 = temp->dreg;
2641 ins->opcode = map_to_reg_reg_op (ins->opcode);
2643 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2646 if (cfg->compile_aot) {
2647 /* Keep these in the aot case */
2650 NEW_INS (cfg, temp, OP_ICONST);
2651 temp->inst_c0 = (gulong)ins->inst_p0;
2652 temp->dreg = mono_alloc_ireg (cfg);
2653 ins->inst_basereg = temp->dreg;
2654 ins->inst_offset = 0;
2655 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2657 /* make it handle the possibly big ins->inst_offset
2658 * later optimize to use lis + load_membase
2664 bb->last_ins = last_ins;
2665 bb->max_vreg = cfg->next_vreg;
2669 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2671 long offset = cfg->arch.fp_conv_var_offset;
2673 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2674 #ifdef __mono_ppc64__
2676 ppc_fctidz (code, ppc_f0, sreg);
2681 ppc_fctiwz (code, ppc_f0, sreg);
2684 if (ppc_is_imm16 (offset + sub_offset)) {
2685 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2687 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2689 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2691 ppc_load (code, dreg, offset);
2692 ppc_add (code, dreg, dreg, cfg->frame_reg);
2693 ppc_stfd (code, ppc_f0, 0, dreg);
2695 ppc_ldr (code, dreg, sub_offset, dreg);
2697 ppc_lwz (code, dreg, sub_offset, dreg);
2701 ppc_andid (code, dreg, dreg, 0xff);
2703 ppc_andid (code, dreg, dreg, 0xffff);
2704 #ifdef __mono_ppc64__
2706 ppc_clrldi (code, dreg, dreg, 32);
2710 ppc_extsb (code, dreg, dreg);
2712 ppc_extsh (code, dreg, dreg);
2713 #ifdef __mono_ppc64__
2715 ppc_extsw (code, dreg, dreg);
2723 const guchar *target;
2728 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2731 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2732 #ifdef __mono_ppc64__
2733 g_assert_not_reached ();
2735 PatchData *pdata = (PatchData*)user_data;
2736 guchar *code = data;
2737 guint32 *thunks = data;
2738 guint32 *endthunks = (guint32*)(code + bsize);
2742 int difflow, diffhigh;
2744 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2745 difflow = (char*)pdata->code - (char*)thunks;
2746 diffhigh = (char*)pdata->code - (char*)endthunks;
2747 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2750 templ = (guchar*)load;
2751 ppc_load_sequence (templ, ppc_r0, pdata->target);
2753 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2754 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2755 while (thunks < endthunks) {
2756 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2757 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2758 ppc_patch (pdata->code, (guchar*)thunks);
2761 static int num_thunks = 0;
2763 if ((num_thunks % 20) == 0)
2764 g_print ("num_thunks lookup: %d\n", num_thunks);
2767 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2768 /* found a free slot instead: emit thunk */
2769 code = (guchar*)thunks;
2770 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2771 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2772 ppc_mtctr (code, ppc_r0);
2773 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2774 mono_arch_flush_icache ((guchar*)thunks, 16);
2776 ppc_patch (pdata->code, (guchar*)thunks);
2779 static int num_thunks = 0;
2781 if ((num_thunks % 20) == 0)
2782 g_print ("num_thunks: %d\n", num_thunks);
2786 /* skip 16 bytes, the size of the thunk */
2790 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2797 handle_thunk (int absolute, guchar *code, const guchar *target) {
2798 MonoDomain *domain = mono_domain_get ();
2802 pdata.target = target;
2803 pdata.absolute = absolute;
2806 mono_domain_lock (domain);
2807 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2810 /* this uses the first available slot */
2812 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2814 mono_domain_unlock (domain);
2816 if (pdata.found != 1)
2817 g_print ("thunk failed for %p from %p\n", target, code);
2818 g_assert (pdata.found == 1);
2822 patch_ins (guint8 *code, guint32 ins)
2824 *(guint32*)code = GUINT32_TO_BE (ins);
2825 mono_arch_flush_icache (code, 4);
2829 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2831 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2832 guint32 prim = ins >> 26;
2835 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2837 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2838 gint diff = target - code;
2841 if (diff <= 33554431){
2842 ins = (18 << 26) | (diff) | (ins & 1);
2843 patch_ins (code, ins);
2847 /* diff between 0 and -33554432 */
2848 if (diff >= -33554432){
2849 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2850 patch_ins (code, ins);
2855 if ((glong)target >= 0){
2856 if ((glong)target <= 33554431){
2857 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2858 patch_ins (code, ins);
2862 if ((glong)target >= -33554432){
2863 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2864 patch_ins (code, ins);
2869 handle_thunk (TRUE, code, target);
2872 g_assert_not_reached ();
2880 guint32 li = (gulong)target;
2881 ins = (ins & 0xffff0000) | (ins & 3);
2882 ovf = li & 0xffff0000;
2883 if (ovf != 0 && ovf != 0xffff0000)
2884 g_assert_not_reached ();
2887 // FIXME: assert the top bits of li are 0
2889 gint diff = target - code;
2890 ins = (ins & 0xffff0000) | (ins & 3);
2891 ovf = diff & 0xffff0000;
2892 if (ovf != 0 && ovf != 0xffff0000)
2893 g_assert_not_reached ();
2897 patch_ins (code, ins);
2901 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2902 #ifdef __mono_ppc64__
2903 guint32 *seq = (guint32*)code;
2904 guint32 *branch_ins;
2906 /* the trampoline code will try to patch the blrl, blr, bcctr */
2907 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2909 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2914 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2915 branch_ins = seq + 8;
2917 branch_ins = seq + 6;
2920 seq = (guint32*)code;
2921 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2922 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2924 if (ppc_is_load_op (seq [5])) {
2925 g_assert (ppc_is_load_op (seq [6]));
2928 guint8 *buf = (guint8*)&seq [5];
2929 ppc_mr (buf, ppc_r0, ppc_r11);
2934 target = mono_get_addr_from_ftnptr ((gpointer)target);
2937 /* FIXME: make this thread safe */
2938 /* FIXME: we're assuming we're using r11 here */
2939 ppc_load_ptr_sequence (code, ppc_r11, target);
2940 mono_arch_flush_icache ((guint8*)seq, 28);
2943 /* the trampoline code will try to patch the blrl, blr, bcctr */
2944 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2947 /* this is the lis/ori/mtlr/blrl sequence */
2948 seq = (guint32*)code;
2949 g_assert ((seq [0] >> 26) == 15);
2950 g_assert ((seq [1] >> 26) == 24);
2951 g_assert ((seq [2] >> 26) == 31);
2952 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2953 /* FIXME: make this thread safe */
2954 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2955 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2956 mono_arch_flush_icache (code - 8, 8);
2959 g_assert_not_reached ();
2961 // g_print ("patched with 0x%08x\n", ins);
2965 ppc_patch (guchar *code, const guchar *target)
2967 ppc_patch_full (code, target, FALSE);
2971 mono_ppc_patch (guchar *code, const guchar *target)
2973 ppc_patch (code, target);
2977 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2979 switch (ins->opcode) {
2982 case OP_FCALL_MEMBASE:
2983 if (ins->dreg != ppc_f1)
2984 ppc_fmr (code, ins->dreg, ppc_f1);
2992 * emit_load_volatile_arguments:
2994 * Load volatile arguments from the stack to the original input registers.
2995 * Required before a tail call.
2998 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3000 MonoMethod *method = cfg->method;
3001 MonoMethodSignature *sig;
3005 int struct_index = 0;
3007 sig = mono_method_signature (method);
3009 /* This is the opposite of the code in emit_prolog */
3013 cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
3015 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3016 ArgInfo *ainfo = &cinfo->ret;
3017 inst = cfg->vret_addr;
3018 g_assert (ppc_is_imm16 (inst->inst_offset));
3019 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3021 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3022 ArgInfo *ainfo = cinfo->args + i;
3023 inst = cfg->args [pos];
3025 g_assert (inst->opcode != OP_REGVAR);
3026 g_assert (ppc_is_imm16 (inst->inst_offset));
3028 switch (ainfo->regtype) {
3029 case RegTypeGeneral:
3030 switch (ainfo->size) {
3032 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3035 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3037 #ifdef __mono_ppc64__
3039 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3043 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3049 switch (ainfo->size) {
3051 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3054 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3057 g_assert_not_reached ();
3062 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3063 &inst->klass->byval_arg);
3065 #ifndef __mono_ppc64__
3066 if (type->type == MONO_TYPE_I8)
3070 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3071 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3072 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3073 } else if (type->type == MONO_TYPE_I4) {
3074 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3075 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3083 case RegTypeStructByVal: {
3094 * Darwin pinvokes needs some special handling
3095 * for 1 and 2 byte arguments
3097 if (method->signature->pinvoke)
3098 size = mono_class_native_size (inst->klass, NULL);
3099 if (size == 1 || size == 2) {
3104 for (j = 0; j < ainfo->vtregs; ++j) {
3105 ppc_ldptr (code, ainfo->reg + j,
3106 inst->inst_offset + j * sizeof (gpointer),
3107 inst->inst_basereg);
3108 /* FIXME: shift to the right */
3115 case RegTypeStructByAddr: {
3116 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3118 g_assert (ppc_is_imm16 (addr->inst_offset));
3119 g_assert (!ainfo->offset);
3120 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3127 g_assert_not_reached ();
3138 /* This must be kept in sync with emit_load_volatile_arguments(). */
3140 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3142 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3143 MonoMethodSignature *sig;
3148 if (ins->opcode != OP_JMP)
3151 call = (MonoCallInst*)ins;
3152 sig = mono_method_signature (cfg->method);
3153 cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
3155 if (MONO_TYPE_ISSTRUCT (sig->ret))
3157 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3158 ArgInfo *ainfo = cinfo->args + i;
3160 switch (ainfo->regtype) {
3161 case RegTypeGeneral:
3170 case RegTypeStructByVal:
3171 len += 4 * ainfo->size;
3174 case RegTypeStructByAddr:
3179 g_assert_not_reached ();
3189 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3191 long size = cfg->param_area;
3193 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3194 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3199 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3200 if (ppc_is_imm16 (-size)) {
3201 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3203 ppc_load (code, ppc_r11, -size);
3204 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3211 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3213 long size = cfg->param_area;
3215 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3216 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3221 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3222 if (ppc_is_imm16 (size)) {
3223 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3225 ppc_load (code, ppc_r11, size);
3226 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3232 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3236 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3238 MonoInst *ins, *next;
3241 guint8 *code = cfg->native_code + cfg->code_len;
3242 MonoInst *last_ins = NULL;
3243 guint last_offset = 0;
3247 /* we don't align basic blocks of loops on ppc */
3249 if (cfg->verbose_level > 2)
3250 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3252 cpos = bb->max_offset;
3254 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3255 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3256 //g_assert (!mono_compile_aot);
3259 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3260 /* this is not thread save, but good enough */
3261 /* fixme: howto handle overflows? */
3262 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3265 MONO_BB_FOR_EACH_INS (bb, ins) {
3266 offset = code - cfg->native_code;
3268 max_len = ins_native_length (cfg, ins);
3270 if (offset > (cfg->code_size - max_len - 16)) {
3271 cfg->code_size *= 2;
3272 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3273 code = cfg->native_code + offset;
3275 // if (ins->cil_code)
3276 // g_print ("cil code\n");
3277 mono_debug_record_line_number (cfg, ins, offset);
3279 switch (normalize_opcode (ins->opcode)) {
3280 case OP_RELAXED_NOP:
3283 case OP_DUMMY_STORE:
3284 case OP_NOT_REACHED:
3287 case OP_SEQ_POINT: {
3290 if (cfg->compile_aot)
3294 * Read from the single stepping trigger page. This will cause a
3295 * SIGSEGV when single stepping is enabled.
3296 * We do this _before_ the breakpoint, so single stepping after
3297 * a breakpoint is hit will step to the next IL offset.
3299 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3300 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3301 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3304 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3307 * A placeholder for a possible breakpoint inserted by
3308 * mono_arch_set_breakpoint ().
3310 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3315 emit_tls_access (code, ins->dreg, ins->inst_offset);
3318 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3319 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3320 ppc_mr (code, ppc_r4, ppc_r0);
3323 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3324 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3325 ppc_mr (code, ppc_r4, ppc_r0);
3327 case OP_MEMORY_BARRIER:
3330 case OP_STOREI1_MEMBASE_REG:
3331 if (ppc_is_imm16 (ins->inst_offset)) {
3332 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3334 if (ppc_is_imm32 (ins->inst_offset)) {
3335 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3336 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3338 ppc_load (code, ppc_r0, ins->inst_offset);
3339 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3343 case OP_STOREI2_MEMBASE_REG:
3344 if (ppc_is_imm16 (ins->inst_offset)) {
3345 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3347 if (ppc_is_imm32 (ins->inst_offset)) {
3348 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3349 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3351 ppc_load (code, ppc_r0, ins->inst_offset);
3352 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3356 case OP_STORE_MEMBASE_REG:
3357 if (ppc_is_imm16 (ins->inst_offset)) {
3358 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3360 if (ppc_is_imm32 (ins->inst_offset)) {
3361 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3362 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3364 ppc_load (code, ppc_r0, ins->inst_offset);
3365 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3369 #ifdef __mono_ilp32__
3370 case OP_STOREI8_MEMBASE_REG:
3371 if (ppc_is_imm16 (ins->inst_offset)) {
3372 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3374 ppc_load (code, ppc_r0, ins->inst_offset);
3375 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3379 case OP_STOREI1_MEMINDEX:
3380 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3382 case OP_STOREI2_MEMINDEX:
3383 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3385 case OP_STORE_MEMINDEX:
3386 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3389 g_assert_not_reached ();
3391 case OP_LOAD_MEMBASE:
3392 if (ppc_is_imm16 (ins->inst_offset)) {
3393 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3395 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3396 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3397 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3399 ppc_load (code, ppc_r0, ins->inst_offset);
3400 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3404 case OP_LOADI4_MEMBASE:
3405 #ifdef __mono_ppc64__
3406 if (ppc_is_imm16 (ins->inst_offset)) {
3407 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3409 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3410 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3411 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3413 ppc_load (code, ppc_r0, ins->inst_offset);
3414 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3419 case OP_LOADU4_MEMBASE:
3420 if (ppc_is_imm16 (ins->inst_offset)) {
3421 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3423 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3424 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3425 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3427 ppc_load (code, ppc_r0, ins->inst_offset);
3428 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3432 case OP_LOADI1_MEMBASE:
3433 case OP_LOADU1_MEMBASE:
3434 if (ppc_is_imm16 (ins->inst_offset)) {
3435 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3437 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3438 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3439 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3441 ppc_load (code, ppc_r0, ins->inst_offset);
3442 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3445 if (ins->opcode == OP_LOADI1_MEMBASE)
3446 ppc_extsb (code, ins->dreg, ins->dreg);
3448 case OP_LOADU2_MEMBASE:
3449 if (ppc_is_imm16 (ins->inst_offset)) {
3450 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3452 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3453 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3454 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3456 ppc_load (code, ppc_r0, ins->inst_offset);
3457 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3461 case OP_LOADI2_MEMBASE:
3462 if (ppc_is_imm16 (ins->inst_offset)) {
3463 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3465 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3466 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3467 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3469 ppc_load (code, ppc_r0, ins->inst_offset);
3470 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3474 #ifdef __mono_ilp32__
3475 case OP_LOADI8_MEMBASE:
3476 if (ppc_is_imm16 (ins->inst_offset)) {
3477 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3479 ppc_load (code, ppc_r0, ins->inst_offset);
3480 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3484 case OP_LOAD_MEMINDEX:
3485 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3487 case OP_LOADI4_MEMINDEX:
3488 #ifdef __mono_ppc64__
3489 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3492 case OP_LOADU4_MEMINDEX:
3493 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3495 case OP_LOADU2_MEMINDEX:
3496 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3498 case OP_LOADI2_MEMINDEX:
3499 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3501 case OP_LOADU1_MEMINDEX:
3502 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3504 case OP_LOADI1_MEMINDEX:
3505 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3506 ppc_extsb (code, ins->dreg, ins->dreg);
3508 case OP_ICONV_TO_I1:
3509 CASE_PPC64 (OP_LCONV_TO_I1)
3510 ppc_extsb (code, ins->dreg, ins->sreg1);
3512 case OP_ICONV_TO_I2:
3513 CASE_PPC64 (OP_LCONV_TO_I2)
3514 ppc_extsh (code, ins->dreg, ins->sreg1);
3516 case OP_ICONV_TO_U1:
3517 CASE_PPC64 (OP_LCONV_TO_U1)
3518 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3520 case OP_ICONV_TO_U2:
3521 CASE_PPC64 (OP_LCONV_TO_U2)
3522 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3526 CASE_PPC64 (OP_LCOMPARE)
3527 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3529 if (next && compare_opcode_is_unsigned (next->opcode))
3530 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3532 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3534 case OP_COMPARE_IMM:
3535 case OP_ICOMPARE_IMM:
3536 CASE_PPC64 (OP_LCOMPARE_IMM)
3537 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3539 if (next && compare_opcode_is_unsigned (next->opcode)) {
3540 if (ppc_is_uimm16 (ins->inst_imm)) {
3541 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3543 g_assert_not_reached ();
3546 if (ppc_is_imm16 (ins->inst_imm)) {
3547 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3549 g_assert_not_reached ();
3555 * gdb does not like encountering a trap in the debugged code. So
3556 * instead of emitting a trap, we emit a call a C function and place a
3560 ppc_mr (code, ppc_r3, ins->sreg1);
3561 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3562 (gpointer)"mono_break");
3563 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3564 ppc_load_func (code, ppc_r0, 0);
3565 ppc_mtlr (code, ppc_r0);
3573 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3576 CASE_PPC64 (OP_LADD)
3577 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3581 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 if (ppc_is_imm16 (ins->inst_imm)) {
3585 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3587 g_assert_not_reached ();
3592 CASE_PPC64 (OP_LADD_IMM)
3593 if (ppc_is_imm16 (ins->inst_imm)) {
3594 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3596 g_assert_not_reached ();
3600 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3602 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3603 ppc_mfspr (code, ppc_r0, ppc_xer);
3604 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3605 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3607 case OP_IADD_OVF_UN:
3608 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3610 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3611 ppc_mfspr (code, ppc_r0, ppc_xer);
3612 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3613 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3616 CASE_PPC64 (OP_LSUB_OVF)
3617 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3619 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3620 ppc_mfspr (code, ppc_r0, ppc_xer);
3621 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3622 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3624 case OP_ISUB_OVF_UN:
3625 CASE_PPC64 (OP_LSUB_OVF_UN)
3626 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3628 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3629 ppc_mfspr (code, ppc_r0, ppc_xer);
3630 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3631 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3633 case OP_ADD_OVF_CARRY:
3634 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3636 ppc_addeo (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, "OverflowException");
3641 case OP_ADD_OVF_UN_CARRY:
3642 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3644 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3645 ppc_mfspr (code, ppc_r0, ppc_xer);
3646 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3647 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3649 case OP_SUB_OVF_CARRY:
3650 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3652 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3653 ppc_mfspr (code, ppc_r0, ppc_xer);
3654 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3655 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3657 case OP_SUB_OVF_UN_CARRY:
3658 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3660 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3661 ppc_mfspr (code, ppc_r0, ppc_xer);
3662 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3663 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3667 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3670 CASE_PPC64 (OP_LSUB)
3671 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3675 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3679 CASE_PPC64 (OP_LSUB_IMM)
3680 // we add the negated value
3681 if (ppc_is_imm16 (-ins->inst_imm))
3682 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3684 g_assert_not_reached ();
3688 g_assert (ppc_is_imm16 (ins->inst_imm));
3689 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3692 ppc_subfze (code, ins->dreg, ins->sreg1);
3695 CASE_PPC64 (OP_LAND)
3696 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3697 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3701 CASE_PPC64 (OP_LAND_IMM)
3702 if (!(ins->inst_imm & 0xffff0000)) {
3703 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3704 } else if (!(ins->inst_imm & 0xffff)) {
3705 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3707 g_assert_not_reached ();
3711 CASE_PPC64 (OP_LDIV) {
3712 guint8 *divisor_is_m1;
3713 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3715 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3716 divisor_is_m1 = code;
3717 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3718 ppc_lis (code, ppc_r0, 0x8000);
3719 #ifdef __mono_ppc64__
3720 if (ins->opcode == OP_LDIV)
3721 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3723 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3724 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3725 ppc_patch (divisor_is_m1, code);
3726 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3728 if (ins->opcode == OP_IDIV)
3729 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3730 #ifdef __mono_ppc64__
3732 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3734 ppc_mfspr (code, ppc_r0, ppc_xer);
3735 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3736 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3740 CASE_PPC64 (OP_LDIV_UN)
3741 if (ins->opcode == OP_IDIV_UN)
3742 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3743 #ifdef __mono_ppc64__
3745 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3747 ppc_mfspr (code, ppc_r0, ppc_xer);
3748 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3749 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3755 g_assert_not_reached ();
3758 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3762 CASE_PPC64 (OP_LOR_IMM)
3763 if (!(ins->inst_imm & 0xffff0000)) {
3764 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3765 } else if (!(ins->inst_imm & 0xffff)) {
3766 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3768 g_assert_not_reached ();
3772 CASE_PPC64 (OP_LXOR)
3773 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3777 CASE_PPC64 (OP_LXOR_IMM)
3778 if (!(ins->inst_imm & 0xffff0000)) {
3779 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3780 } else if (!(ins->inst_imm & 0xffff)) {
3781 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3783 g_assert_not_reached ();
3787 CASE_PPC64 (OP_LSHL)
3788 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3792 CASE_PPC64 (OP_LSHL_IMM)
3793 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3796 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3799 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3802 if (MASK_SHIFT_IMM (ins->inst_imm))
3803 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3805 ppc_mr (code, ins->dreg, ins->sreg1);
3808 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3811 CASE_PPC64 (OP_LNOT)
3812 ppc_not (code, ins->dreg, ins->sreg1);
3815 CASE_PPC64 (OP_LNEG)
3816 ppc_neg (code, ins->dreg, ins->sreg1);
3819 CASE_PPC64 (OP_LMUL)
3820 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3824 CASE_PPC64 (OP_LMUL_IMM)
3825 if (ppc_is_imm16 (ins->inst_imm)) {
3826 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3828 g_assert_not_reached ();
3832 CASE_PPC64 (OP_LMUL_OVF)
3833 /* we annot use mcrxr, since it's not implemented on some processors
3834 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3836 if (ins->opcode == OP_IMUL_OVF)
3837 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3838 #ifdef __mono_ppc64__
3840 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3842 ppc_mfspr (code, ppc_r0, ppc_xer);
3843 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3844 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3846 case OP_IMUL_OVF_UN:
3847 CASE_PPC64 (OP_LMUL_OVF_UN)
3848 /* we first multiply to get the high word and compare to 0
3849 * to set the flags, then the result is discarded and then
3850 * we multiply to get the lower * bits result
3852 if (ins->opcode == OP_IMUL_OVF_UN)
3853 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3854 #ifdef __mono_ppc64__
3856 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3858 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3859 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3860 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3863 ppc_load (code, ins->dreg, ins->inst_c0);
3866 ppc_load (code, ins->dreg, ins->inst_l);
3869 case OP_LOAD_GOTADDR:
3870 /* The PLT implementation depends on this */
3871 g_assert (ins->dreg == ppc_r30);
3873 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3876 // FIXME: Fix max instruction length
3877 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3878 /* arch_emit_got_access () patches this */
3879 ppc_load32 (code, ppc_r0, 0);
3880 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3883 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3884 ppc_load_sequence (code, ins->dreg, 0);
3886 CASE_PPC32 (OP_ICONV_TO_I4)
3887 CASE_PPC32 (OP_ICONV_TO_U4)
3889 ppc_mr (code, ins->dreg, ins->sreg1);
3892 int saved = ins->sreg1;
3893 if (ins->sreg1 == ppc_r3) {
3894 ppc_mr (code, ppc_r0, ins->sreg1);
3897 if (ins->sreg2 != ppc_r3)
3898 ppc_mr (code, ppc_r3, ins->sreg2);
3899 if (saved != ppc_r4)
3900 ppc_mr (code, ppc_r4, saved);
3904 ppc_fmr (code, ins->dreg, ins->sreg1);
3906 case OP_FCONV_TO_R4:
3907 ppc_frsp (code, ins->dreg, ins->sreg1);
3913 * Keep in sync with mono_arch_emit_epilog
3915 g_assert (!cfg->method->save_lmf);
3917 * Note: we can use ppc_r11 here because it is dead anyway:
3918 * we're leaving the method.
3920 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3921 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3922 if (ppc_is_imm16 (ret_offset)) {
3923 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3925 ppc_load (code, ppc_r11, ret_offset);
3926 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3928 ppc_mtlr (code, ppc_r0);
3931 code = emit_load_volatile_arguments (cfg, code);
3933 if (ppc_is_imm16 (cfg->stack_usage)) {
3934 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3936 /* cfg->stack_usage is an int, so we can use
3937 * an addis/addi sequence here even in 64-bit. */
3938 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3939 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3941 if (!cfg->method->save_lmf) {
3942 /*for (i = 31; i >= 14; --i) {
3943 if (cfg->used_float_regs & (1 << i)) {
3944 pos += sizeof (double);
3945 ppc_lfd (code, i, -pos, cfg->frame_reg);
3949 for (i = 31; i >= 13; --i) {
3950 if (cfg->used_int_regs & (1 << i)) {
3951 pos += sizeof (gpointer);
3952 ppc_ldptr (code, i, -pos, ppc_r11);
3956 /* FIXME restore from MonoLMF: though this can't happen yet */
3958 ppc_mr (code, ppc_sp, ppc_r11);
3959 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3960 if (cfg->compile_aot) {
3961 /* arch_emit_got_access () patches this */
3962 ppc_load32 (code, ppc_r0, 0);
3963 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3964 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3965 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3967 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3969 ppc_mtctr (code, ppc_r0);
3970 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3977 /* ensure ins->sreg1 is not NULL */
3978 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3981 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3982 if (ppc_is_imm16 (cookie_offset)) {
3983 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3985 ppc_load (code, ppc_r0, cookie_offset);
3986 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3988 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3997 call = (MonoCallInst*)ins;
3998 if (ins->flags & MONO_INST_HAS_METHOD)
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4001 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4002 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4003 ppc_load_func (code, ppc_r0, 0);
4004 ppc_mtlr (code, ppc_r0);
4009 /* FIXME: this should be handled somewhere else in the new jit */
4010 code = emit_move_return_value (cfg, ins, code);
4016 case OP_VOIDCALL_REG:
4018 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4019 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4020 /* FIXME: if we know that this is a method, we
4021 can omit this load */
4022 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4023 ppc_mtlr (code, ppc_r0);
4025 ppc_mtlr (code, ins->sreg1);
4028 /* FIXME: this should be handled somewhere else in the new jit */
4029 code = emit_move_return_value (cfg, ins, code);
4031 case OP_FCALL_MEMBASE:
4032 case OP_LCALL_MEMBASE:
4033 case OP_VCALL_MEMBASE:
4034 case OP_VCALL2_MEMBASE:
4035 case OP_VOIDCALL_MEMBASE:
4036 case OP_CALL_MEMBASE:
4037 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
4038 /* The trampolines clobber this */
4039 ppc_mr (code, ppc_r29, ins->sreg1);
4040 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4042 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4044 ppc_mtlr (code, ppc_r0);
4046 /* FIXME: this should be handled somewhere else in the new jit */
4047 code = emit_move_return_value (cfg, ins, code);
4050 guint8 * zero_loop_jump, * zero_loop_start;
4051 /* keep alignment */
4052 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4053 int area_offset = alloca_waste;
4055 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
4056 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4057 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
4058 /* use ctr to store the number of words to 0 if needed */
4059 if (ins->flags & MONO_INST_INIT) {
4060 /* we zero 4 bytes at a time:
4061 * we add 7 instead of 3 so that we set the counter to
4062 * at least 1, otherwise the bdnz instruction will make
4063 * it negative and iterate billions of times.
4065 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4066 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4067 ppc_mtctr (code, ppc_r0);
4069 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4070 ppc_neg (code, ppc_r11, ppc_r11);
4071 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4073 /* FIXME: make this loop work in 8 byte
4074 increments on PPC64 */
4075 if (ins->flags & MONO_INST_INIT) {
4076 /* adjust the dest reg by -4 so we can use stwu */
4077 /* we actually adjust -8 because we let the loop
4080 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4081 ppc_li (code, ppc_r11, 0);
4082 zero_loop_start = code;
4083 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4084 zero_loop_jump = code;
4085 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4086 ppc_patch (zero_loop_jump, zero_loop_start);
4088 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4093 ppc_mr (code, ppc_r3, ins->sreg1);
4094 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4095 (gpointer)"mono_arch_throw_exception");
4096 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4097 ppc_load_func (code, ppc_r0, 0);
4098 ppc_mtlr (code, ppc_r0);
4107 ppc_mr (code, ppc_r3, ins->sreg1);
4108 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4109 (gpointer)"mono_arch_rethrow_exception");
4110 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4111 ppc_load_func (code, ppc_r0, 0);
4112 ppc_mtlr (code, ppc_r0);
4119 case OP_START_HANDLER: {
4120 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4121 g_assert (spvar->inst_basereg != ppc_sp);
4122 code = emit_reserve_param_area (cfg, code);
4123 ppc_mflr (code, ppc_r0);
4124 if (ppc_is_imm16 (spvar->inst_offset)) {
4125 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4127 ppc_load (code, ppc_r11, spvar->inst_offset);
4128 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4132 case OP_ENDFILTER: {
4133 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4134 g_assert (spvar->inst_basereg != ppc_sp);
4135 code = emit_unreserve_param_area (cfg, code);
4136 if (ins->sreg1 != ppc_r3)
4137 ppc_mr (code, ppc_r3, ins->sreg1);
4138 if (ppc_is_imm16 (spvar->inst_offset)) {
4139 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4141 ppc_load (code, ppc_r11, spvar->inst_offset);
4142 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4144 ppc_mtlr (code, ppc_r0);
4148 case OP_ENDFINALLY: {
4149 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4150 g_assert (spvar->inst_basereg != ppc_sp);
4151 code = emit_unreserve_param_area (cfg, code);
4152 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4153 ppc_mtlr (code, ppc_r0);
4157 case OP_CALL_HANDLER:
4158 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4160 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4163 ins->inst_c0 = code - cfg->native_code;
4166 /*if (ins->inst_target_bb->native_offset) {
4168 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4170 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4175 ppc_mtctr (code, ins->sreg1);
4176 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4180 CASE_PPC64 (OP_LCEQ)
4181 ppc_li (code, ins->dreg, 0);
4182 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4183 ppc_li (code, ins->dreg, 1);
4189 CASE_PPC64 (OP_LCLT)
4190 CASE_PPC64 (OP_LCLT_UN)
4191 ppc_li (code, ins->dreg, 1);
4192 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4193 ppc_li (code, ins->dreg, 0);
4199 CASE_PPC64 (OP_LCGT)
4200 CASE_PPC64 (OP_LCGT_UN)
4201 ppc_li (code, ins->dreg, 1);
4202 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4203 ppc_li (code, ins->dreg, 0);
4205 case OP_COND_EXC_EQ:
4206 case OP_COND_EXC_NE_UN:
4207 case OP_COND_EXC_LT:
4208 case OP_COND_EXC_LT_UN:
4209 case OP_COND_EXC_GT:
4210 case OP_COND_EXC_GT_UN:
4211 case OP_COND_EXC_GE:
4212 case OP_COND_EXC_GE_UN:
4213 case OP_COND_EXC_LE:
4214 case OP_COND_EXC_LE_UN:
4215 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4217 case OP_COND_EXC_IEQ:
4218 case OP_COND_EXC_INE_UN:
4219 case OP_COND_EXC_ILT:
4220 case OP_COND_EXC_ILT_UN:
4221 case OP_COND_EXC_IGT:
4222 case OP_COND_EXC_IGT_UN:
4223 case OP_COND_EXC_IGE:
4224 case OP_COND_EXC_IGE_UN:
4225 case OP_COND_EXC_ILE:
4226 case OP_COND_EXC_ILE_UN:
4227 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4239 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4242 /* floating point opcodes */
4244 g_assert (cfg->compile_aot);
4246 /* FIXME: Optimize this */
4248 ppc_mflr (code, ppc_r11);
4250 *(double*)code = *(double*)ins->inst_p0;
4252 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4255 g_assert_not_reached ();
4257 case OP_STORER8_MEMBASE_REG:
4258 if (ppc_is_imm16 (ins->inst_offset)) {
4259 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4261 if (ppc_is_imm32 (ins->inst_offset)) {
4262 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4263 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4265 ppc_load (code, ppc_r0, ins->inst_offset);
4266 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4270 case OP_LOADR8_MEMBASE:
4271 if (ppc_is_imm16 (ins->inst_offset)) {
4272 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4274 if (ppc_is_imm32 (ins->inst_offset)) {
4275 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4276 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4278 ppc_load (code, ppc_r0, ins->inst_offset);
4279 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4283 case OP_STORER4_MEMBASE_REG:
4284 ppc_frsp (code, ins->sreg1, ins->sreg1);
4285 if (ppc_is_imm16 (ins->inst_offset)) {
4286 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4288 if (ppc_is_imm32 (ins->inst_offset)) {
4289 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4290 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4292 ppc_load (code, ppc_r0, ins->inst_offset);
4293 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4297 case OP_LOADR4_MEMBASE:
4298 if (ppc_is_imm16 (ins->inst_offset)) {
4299 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4301 if (ppc_is_imm32 (ins->inst_offset)) {
4302 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4303 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4305 ppc_load (code, ppc_r0, ins->inst_offset);
4306 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4310 case OP_LOADR4_MEMINDEX:
4311 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4313 case OP_LOADR8_MEMINDEX:
4314 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4316 case OP_STORER4_MEMINDEX:
4317 ppc_frsp (code, ins->sreg1, ins->sreg1);
4318 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4320 case OP_STORER8_MEMINDEX:
4321 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4324 case CEE_CONV_R4: /* FIXME: change precision */
4326 g_assert_not_reached ();
4327 case OP_FCONV_TO_I1:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4330 case OP_FCONV_TO_U1:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4333 case OP_FCONV_TO_I2:
4334 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4336 case OP_FCONV_TO_U2:
4337 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4339 case OP_FCONV_TO_I4:
4341 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4343 case OP_FCONV_TO_U4:
4345 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4347 case OP_LCONV_TO_R_UN:
4348 g_assert_not_reached ();
4349 /* Implemented as helper calls */
4351 case OP_LCONV_TO_OVF_I4_2:
4352 case OP_LCONV_TO_OVF_I: {
4353 #ifdef __mono_ppc64__
4356 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4357 // Check if its negative
4358 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4359 negative_branch = code;
4360 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4361 // Its positive msword == 0
4362 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4363 msword_positive_branch = code;
4364 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4366 ovf_ex_target = code;
4367 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4369 ppc_patch (negative_branch, code);
4370 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4371 msword_negative_branch = code;
4372 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4373 ppc_patch (msword_negative_branch, ovf_ex_target);
4375 ppc_patch (msword_positive_branch, code);
4376 if (ins->dreg != ins->sreg1)
4377 ppc_mr (code, ins->dreg, ins->sreg1);
4382 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4385 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4388 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4391 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4394 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4397 ppc_fneg (code, ins->dreg, ins->sreg1);
4401 g_assert_not_reached ();
4404 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4407 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4408 ppc_li (code, ins->dreg, 0);
4409 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4410 ppc_li (code, ins->dreg, 1);
4413 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4414 ppc_li (code, ins->dreg, 1);
4415 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4416 ppc_li (code, ins->dreg, 0);
4419 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4420 ppc_li (code, ins->dreg, 1);
4421 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4422 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4423 ppc_li (code, ins->dreg, 0);
4426 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 1);
4428 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4429 ppc_li (code, ins->dreg, 0);
4432 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4433 ppc_li (code, ins->dreg, 1);
4434 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4435 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4436 ppc_li (code, ins->dreg, 0);
4439 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4442 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4445 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4446 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4449 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4450 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4453 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4454 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4457 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4458 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4461 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4462 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4465 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4468 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4469 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4472 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4475 g_assert_not_reached ();
4476 case OP_CHECK_FINITE: {
4477 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4478 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4479 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4480 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4483 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4484 #ifdef __mono_ppc64__
4485 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4487 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4492 #ifdef __mono_ppc64__
4493 case OP_ICONV_TO_I4:
4495 ppc_extsw (code, ins->dreg, ins->sreg1);
4497 case OP_ICONV_TO_U4:
4499 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4501 case OP_ICONV_TO_R4:
4502 case OP_ICONV_TO_R8:
4503 case OP_LCONV_TO_R4:
4504 case OP_LCONV_TO_R8: {
4506 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4507 ppc_extsw (code, ppc_r0, ins->sreg1);
4512 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4513 ppc_mffgpr (code, ins->dreg, tmp);
4515 ppc_str (code, tmp, -8, ppc_r1);
4516 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4518 ppc_fcfid (code, ins->dreg, ins->dreg);
4519 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4520 ppc_frsp (code, ins->dreg, ins->dreg);
4524 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4527 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4530 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4532 ppc_mfspr (code, ppc_r0, ppc_xer);
4533 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4534 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4536 case OP_COND_EXC_OV:
4537 ppc_mfspr (code, ppc_r0, ppc_xer);
4538 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4539 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4551 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4553 case OP_FCONV_TO_I8:
4554 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4556 case OP_FCONV_TO_U8:
4557 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4559 case OP_STOREI4_MEMBASE_REG:
4560 if (ppc_is_imm16 (ins->inst_offset)) {
4561 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4563 ppc_load (code, ppc_r0, ins->inst_offset);
4564 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4567 case OP_STOREI4_MEMINDEX:
4568 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4571 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4573 case OP_ISHR_UN_IMM:
4574 if (ins->inst_imm & 0x1f)
4575 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4577 ppc_mr (code, ins->dreg, ins->sreg1);
4579 case OP_ATOMIC_ADD_NEW_I4:
4580 case OP_ATOMIC_ADD_NEW_I8: {
4581 guint8 *loop = code, *branch;
4582 g_assert (ins->inst_offset == 0);
4583 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4584 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4586 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4587 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4588 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4589 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4591 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4593 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4594 ppc_patch (branch, loop);
4595 ppc_mr (code, ins->dreg, ppc_r0);
4599 case OP_ICONV_TO_R4:
4600 case OP_ICONV_TO_R8: {
4601 if (cpu_hw_caps & PPC_ISA_64) {
4602 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4603 ppc_stw (code, ppc_r0, -8, ppc_r1);
4604 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4605 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4606 ppc_fcfid (code, ins->dreg, ins->dreg);
4607 if (ins->opcode == OP_ICONV_TO_R4)
4608 ppc_frsp (code, ins->dreg, ins->dreg);
4613 case OP_ATOMIC_CAS_I4:
4614 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4615 int location = ins->sreg1;
4616 int value = ins->sreg2;
4617 int comparand = ins->sreg3;
4618 guint8 *start, *not_equal, *lost_reservation;
4621 if (ins->opcode == OP_ATOMIC_CAS_I4)
4622 ppc_lwarx (code, ppc_r0, 0, location);
4623 #ifdef __mono_ppc64__
4625 ppc_ldarx (code, ppc_r0, 0, location);
4627 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4630 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4631 if (ins->opcode == OP_ATOMIC_CAS_I4)
4632 ppc_stwcxd (code, value, 0, location);
4633 #ifdef __mono_ppc64__
4635 ppc_stdcxd (code, value, 0, location);
4638 lost_reservation = code;
4639 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4640 ppc_patch (lost_reservation, start);
4642 ppc_patch (not_equal, code);
4643 ppc_mr (code, ins->dreg, ppc_r0);
4648 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4649 g_assert_not_reached ();
4652 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4653 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4654 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4655 g_assert_not_reached ();
4661 last_offset = offset;
4664 cfg->code_len = code - cfg->native_code;
4666 #endif /* !DISABLE_JIT */
4669 mono_arch_register_lowlevel_calls (void)
4671 /* The signature doesn't matter */
4672 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4675 #ifdef __mono_ppc64__
4676 #define patch_load_sequence(ip,val) do {\
4677 guint16 *__load = (guint16*)(ip); \
4678 g_assert (sizeof (val) == sizeof (gsize)); \
4679 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4680 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4681 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4682 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4685 #define patch_load_sequence(ip,val) do {\
4686 guint16 *__lis_ori = (guint16*)(ip); \
4687 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4688 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4694 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4696 MonoJumpInfo *patch_info;
4697 gboolean compile_aot = !run_cctors;
4699 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4700 unsigned char *ip = patch_info->ip.i + code;
4701 unsigned char *target;
4702 gboolean is_fd = FALSE;
4704 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4707 switch (patch_info->type) {
4708 case MONO_PATCH_INFO_BB:
4709 case MONO_PATCH_INFO_LABEL:
4712 /* No need to patch these */
4717 switch (patch_info->type) {
4718 case MONO_PATCH_INFO_IP:
4719 patch_load_sequence (ip, ip);
4721 case MONO_PATCH_INFO_METHOD_REL:
4722 g_assert_not_reached ();
4723 *((gpointer *)(ip)) = code + patch_info->data.offset;
4725 case MONO_PATCH_INFO_SWITCH: {
4726 gpointer *table = (gpointer *)patch_info->data.table->table;
4729 patch_load_sequence (ip, table);
4731 for (i = 0; i < patch_info->data.table->table_size; i++) {
4732 table [i] = (glong)patch_info->data.table->table [i] + code;
4734 /* we put into the table the absolute address, no need for ppc_patch in this case */
4737 case MONO_PATCH_INFO_METHODCONST:
4738 case MONO_PATCH_INFO_CLASS:
4739 case MONO_PATCH_INFO_IMAGE:
4740 case MONO_PATCH_INFO_FIELD:
4741 case MONO_PATCH_INFO_VTABLE:
4742 case MONO_PATCH_INFO_IID:
4743 case MONO_PATCH_INFO_SFLDA:
4744 case MONO_PATCH_INFO_LDSTR:
4745 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4746 case MONO_PATCH_INFO_LDTOKEN:
4747 /* from OP_AOTCONST : lis + ori */
4748 patch_load_sequence (ip, target);
4750 case MONO_PATCH_INFO_R4:
4751 case MONO_PATCH_INFO_R8:
4752 g_assert_not_reached ();
4753 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4755 case MONO_PATCH_INFO_EXC_NAME:
4756 g_assert_not_reached ();
4757 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4759 case MONO_PATCH_INFO_NONE:
4760 case MONO_PATCH_INFO_BB_OVF:
4761 case MONO_PATCH_INFO_EXC_OVF:
4762 /* everything is dealt with at epilog output time */
4764 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4765 case MONO_PATCH_INFO_INTERNAL_METHOD:
4766 case MONO_PATCH_INFO_ABS:
4767 case MONO_PATCH_INFO_CLASS_INIT:
4768 case MONO_PATCH_INFO_RGCTX_FETCH:
4775 ppc_patch_full (ip, target, is_fd);
4780 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4781 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4782 * the instruction offset immediate for all the registers.
4785 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4789 for (i = 13; i <= 31; i++) {
4790 if (used_int_regs & (1 << i)) {
4791 ppc_str (code, i, pos, base_reg);
4792 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4793 pos += sizeof (mgreg_t);
4797 /* pos is the start of the MonoLMF structure */
4798 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4799 for (i = 13; i <= 31; i++) {
4800 ppc_str (code, i, offset, base_reg);
4801 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4802 offset += sizeof (mgreg_t);
4804 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4805 for (i = 14; i < 32; i++) {
4806 ppc_stfd (code, i, offset, base_reg);
4807 offset += sizeof (gdouble);
4814 * Stack frame layout:
4816 * ------------------- sp
4817 * MonoLMF structure or saved registers
4818 * -------------------
4820 * -------------------
4822 * -------------------
4823 * optional 8 bytes for tracing
4824 * -------------------
4825 * param area size is cfg->param_area
4826 * -------------------
4827 * linkage area size is PPC_STACK_PARAM_OFFSET
4828 * ------------------- sp
4832 mono_arch_emit_prolog (MonoCompile *cfg)
4834 MonoMethod *method = cfg->method;
4836 MonoMethodSignature *sig;
4838 long alloc_size, pos, max_offset, cfa_offset;
4844 int tailcall_struct_index;
4846 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4849 sig = mono_method_signature (method);
4850 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4851 code = cfg->native_code = g_malloc (cfg->code_size);
4855 /* We currently emit unwind info for aot, but don't use it */
4856 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4858 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4859 ppc_mflr (code, ppc_r0);
4860 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4861 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4864 alloc_size = cfg->stack_offset;
4867 if (!method->save_lmf) {
4868 for (i = 31; i >= 13; --i) {
4869 if (cfg->used_int_regs & (1 << i)) {
4870 pos += sizeof (mgreg_t);
4874 pos += sizeof (MonoLMF);
4878 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4879 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4880 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4881 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4884 cfg->stack_usage = alloc_size;
4885 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4887 if (ppc_is_imm16 (-alloc_size)) {
4888 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4889 cfa_offset = alloc_size;
4890 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4891 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4894 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4895 ppc_load (code, ppc_r0, -alloc_size);
4896 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4897 cfa_offset = alloc_size;
4898 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4899 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4902 if (cfg->frame_reg != ppc_sp) {
4903 ppc_mr (code, cfg->frame_reg, ppc_sp);
4904 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4907 /* store runtime generic context */
4908 if (cfg->rgctx_var) {
4909 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4910 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4912 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4915 /* compute max_offset in order to use short forward jumps
4916 * we always do it on ppc because the immediate displacement
4917 * for jumps is too small
4920 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4922 bb->max_offset = max_offset;
4924 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4927 MONO_BB_FOR_EACH_INS (bb, ins)
4928 max_offset += ins_native_length (cfg, ins);
4931 /* load arguments allocated to register from the stack */
4934 cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
4936 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4937 ArgInfo *ainfo = &cinfo->ret;
4939 inst = cfg->vret_addr;
4942 if (ppc_is_imm16 (inst->inst_offset)) {
4943 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4945 ppc_load (code, ppc_r11, inst->inst_offset);
4946 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4950 tailcall_struct_index = 0;
4951 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4952 ArgInfo *ainfo = cinfo->args + i;
4953 inst = cfg->args [pos];
4955 if (cfg->verbose_level > 2)
4956 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4957 if (inst->opcode == OP_REGVAR) {
4958 if (ainfo->regtype == RegTypeGeneral)
4959 ppc_mr (code, inst->dreg, ainfo->reg);
4960 else if (ainfo->regtype == RegTypeFP)
4961 ppc_fmr (code, inst->dreg, ainfo->reg);
4962 else if (ainfo->regtype == RegTypeBase) {
4963 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4964 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4966 g_assert_not_reached ();
4968 if (cfg->verbose_level > 2)
4969 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4971 /* the argument should be put on the stack: FIXME handle size != word */
4972 if (ainfo->regtype == RegTypeGeneral) {
4973 switch (ainfo->size) {
4975 if (ppc_is_imm16 (inst->inst_offset)) {
4976 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4978 if (ppc_is_imm32 (inst->inst_offset)) {
4979 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4980 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4982 ppc_load (code, ppc_r11, inst->inst_offset);
4983 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4988 if (ppc_is_imm16 (inst->inst_offset)) {
4989 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4991 if (ppc_is_imm32 (inst->inst_offset)) {
4992 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4993 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4995 ppc_load (code, ppc_r11, inst->inst_offset);
4996 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5000 #ifdef __mono_ppc64__
5002 if (ppc_is_imm16 (inst->inst_offset)) {
5003 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5005 if (ppc_is_imm32 (inst->inst_offset)) {
5006 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5007 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
5009 ppc_load (code, ppc_r11, inst->inst_offset);
5010 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5015 if (ppc_is_imm16 (inst->inst_offset)) {
5016 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5018 ppc_load (code, ppc_r11, inst->inst_offset);
5019 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
5024 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5025 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5026 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5028 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5029 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5030 ppc_stw (code, ainfo->reg, 0, ppc_r11);
5031 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
5036 if (ppc_is_imm16 (inst->inst_offset)) {
5037 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5039 if (ppc_is_imm32 (inst->inst_offset)) {
5040 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5041 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
5043 ppc_load (code, ppc_r11, inst->inst_offset);
5044 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5049 } else if (ainfo->regtype == RegTypeBase) {
5050 g_assert (ppc_is_imm16 (ainfo->offset));
5051 /* load the previous stack pointer in r11 */
5052 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5053 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
5054 switch (ainfo->size) {
5056 if (ppc_is_imm16 (inst->inst_offset)) {
5057 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5059 if (ppc_is_imm32 (inst->inst_offset)) {
5060 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5061 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
5063 ppc_load (code, ppc_r11, inst->inst_offset);
5064 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5069 if (ppc_is_imm16 (inst->inst_offset)) {
5070 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5072 if (ppc_is_imm32 (inst->inst_offset)) {
5073 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5074 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
5076 ppc_load (code, ppc_r11, inst->inst_offset);
5077 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5081 #ifdef __mono_ppc64__
5083 if (ppc_is_imm16 (inst->inst_offset)) {
5084 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5086 if (ppc_is_imm32 (inst->inst_offset)) {
5087 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5088 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
5090 ppc_load (code, ppc_r11, inst->inst_offset);
5091 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5096 if (ppc_is_imm16 (inst->inst_offset)) {
5097 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5099 ppc_load (code, ppc_r11, inst->inst_offset);
5100 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
5105 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5106 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5107 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5108 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5109 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5111 /* use r12 to load the 2nd half of the long before we clobber r11. */
5112 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5113 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5114 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5115 ppc_stw (code, ppc_r0, 0, ppc_r11);
5116 ppc_stw (code, ppc_r12, 4, ppc_r11);
5121 if (ppc_is_imm16 (inst->inst_offset)) {
5122 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5124 if (ppc_is_imm32 (inst->inst_offset)) {
5125 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5126 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
5128 ppc_load (code, ppc_r11, inst->inst_offset);
5129 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5134 } else if (ainfo->regtype == RegTypeFP) {
5135 g_assert (ppc_is_imm16 (inst->inst_offset));
5136 if (ainfo->size == 8)
5137 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5138 else if (ainfo->size == 4)
5139 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5141 g_assert_not_reached ();
5142 } else if (ainfo->regtype == RegTypeStructByVal) {
5143 int doffset = inst->inst_offset;
5147 g_assert (ppc_is_imm16 (inst->inst_offset));
5148 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5149 /* FIXME: what if there is no class? */
5150 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5151 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5152 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5155 * Darwin handles 1 and 2 byte
5156 * structs specially by
5157 * loading h/b into the arg
5158 * register. Only done for
5162 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5164 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5168 #ifdef __mono_ppc64__
5170 g_assert (cur_reg == 0);
5171 ppc_sldi (code, ppc_r0, ainfo->reg,
5172 (sizeof (gpointer) - ainfo->bytes) * 8);
5173 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5177 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5178 inst->inst_basereg);
5181 soffset += sizeof (gpointer);
5182 doffset += sizeof (gpointer);
5184 if (ainfo->vtsize) {
5185 /* FIXME: we need to do the shifting here, too */
5188 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5189 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5190 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5191 code = emit_memcpy (code, size - soffset,
5192 inst->inst_basereg, doffset,
5193 ppc_r11, ainfo->offset + soffset);
5195 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5196 inst->inst_basereg, doffset,
5197 ppc_r11, ainfo->offset + soffset);
5200 } else if (ainfo->regtype == RegTypeStructByAddr) {
5201 /* if it was originally a RegTypeBase */
5202 if (ainfo->offset) {
5203 /* load the previous stack pointer in r11 */
5204 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5205 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5207 ppc_mr (code, ppc_r11, ainfo->reg);
5210 if (cfg->tailcall_valuetype_addrs) {
5211 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5213 g_assert (ppc_is_imm16 (addr->inst_offset));
5214 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5216 tailcall_struct_index++;
5219 g_assert (ppc_is_imm16 (inst->inst_offset));
5220 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5221 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5223 g_assert_not_reached ();
5228 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5229 if (cfg->compile_aot)
5230 /* AOT code is only used in the root domain */
5231 ppc_load_ptr (code, ppc_r3, 0);
5233 ppc_load_ptr (code, ppc_r3, cfg->domain);
5234 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5235 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5236 ppc_load_func (code, ppc_r0, 0);
5237 ppc_mtlr (code, ppc_r0);
5244 if (method->save_lmf) {
5245 if (lmf_pthread_key != -1) {
5246 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5247 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5248 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5250 if (cfg->compile_aot) {
5251 /* Compute the got address which is needed by the PLT entry */
5252 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5254 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5255 (gpointer)"mono_get_lmf_addr");
5256 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5257 ppc_load_func (code, ppc_r0, 0);
5258 ppc_mtlr (code, ppc_r0);
5264 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5265 /* lmf_offset is the offset from the previous stack pointer,
5266 * alloc_size is the total stack space allocated, so the offset
5267 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5268 * The pointer to the struct is put in ppc_r11 (new_lmf).
5269 * The callee-saved registers are already in the MonoLMF structure
5271 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5272 /* ppc_r3 is the result from mono_get_lmf_addr () */
5273 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5274 /* new_lmf->previous_lmf = *lmf_addr */
5275 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5276 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5277 /* *(lmf_addr) = r11 */
5278 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5279 /* save method info */
5280 if (cfg->compile_aot)
5282 ppc_load (code, ppc_r0, 0);
5284 ppc_load_ptr (code, ppc_r0, method);
5285 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5286 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5287 /* save the current IP */
5288 if (cfg->compile_aot) {
5290 ppc_mflr (code, ppc_r0);
5292 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5293 #ifdef __mono_ppc64__
5294 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5296 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5299 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5303 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5305 cfg->code_len = code - cfg->native_code;
5306 g_assert (cfg->code_len <= cfg->code_size);
5313 mono_arch_emit_epilog (MonoCompile *cfg)
5315 MonoMethod *method = cfg->method;
5317 int max_epilog_size = 16 + 20*4;
5320 if (cfg->method->save_lmf)
5321 max_epilog_size += 128;
5323 if (mono_jit_trace_calls != NULL)
5324 max_epilog_size += 50;
5326 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5327 max_epilog_size += 50;
5329 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5330 cfg->code_size *= 2;
5331 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5332 mono_jit_stats.code_reallocs++;
5336 * Keep in sync with OP_JMP
5338 code = cfg->native_code + cfg->code_len;
5340 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5341 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5345 if (method->save_lmf) {
5347 pos += sizeof (MonoLMF);
5349 /* save the frame reg in r8 */
5350 ppc_mr (code, ppc_r8, cfg->frame_reg);
5351 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5352 /* r5 = previous_lmf */
5353 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5355 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5356 /* *(lmf_addr) = previous_lmf */
5357 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5358 /* FIXME: speedup: there is no actual need to restore the registers if
5359 * we didn't actually change them (idea from Zoltan).
5362 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5364 /*for (i = 14; i < 32; i++) {
5365 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5367 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5368 /* use the saved copy of the frame reg in r8 */
5369 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5370 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5371 ppc_mtlr (code, ppc_r0);
5373 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5375 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5376 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5377 if (ppc_is_imm16 (return_offset)) {
5378 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5380 ppc_load (code, ppc_r11, return_offset);
5381 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5383 ppc_mtlr (code, ppc_r0);
5385 if (ppc_is_imm16 (cfg->stack_usage)) {
5386 int offset = cfg->stack_usage;
5387 for (i = 13; i <= 31; i++) {
5388 if (cfg->used_int_regs & (1 << i))
5389 offset -= sizeof (mgreg_t);
5391 if (cfg->frame_reg != ppc_sp)
5392 ppc_mr (code, ppc_r11, cfg->frame_reg);
5393 /* note r31 (possibly the frame register) is restored last */
5394 for (i = 13; i <= 31; i++) {
5395 if (cfg->used_int_regs & (1 << i)) {
5396 ppc_ldr (code, i, offset, cfg->frame_reg);
5397 offset += sizeof (mgreg_t);
5400 if (cfg->frame_reg != ppc_sp)
5401 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5403 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5405 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5406 if (cfg->used_int_regs) {
5407 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5408 for (i = 31; i >= 13; --i) {
5409 if (cfg->used_int_regs & (1 << i)) {
5410 pos += sizeof (mgreg_t);
5411 ppc_ldr (code, i, -pos, ppc_r11);
5414 ppc_mr (code, ppc_sp, ppc_r11);
5416 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5423 cfg->code_len = code - cfg->native_code;
5425 g_assert (cfg->code_len < cfg->code_size);
5428 #endif /* ifndef DISABLE_JIT */
5430 /* remove once throw_exception_by_name is eliminated */
5432 exception_id_by_name (const char *name)
5434 if (strcmp (name, "IndexOutOfRangeException") == 0)
5435 return MONO_EXC_INDEX_OUT_OF_RANGE;
5436 if (strcmp (name, "OverflowException") == 0)
5437 return MONO_EXC_OVERFLOW;
5438 if (strcmp (name, "ArithmeticException") == 0)
5439 return MONO_EXC_ARITHMETIC;
5440 if (strcmp (name, "DivideByZeroException") == 0)
5441 return MONO_EXC_DIVIDE_BY_ZERO;
5442 if (strcmp (name, "InvalidCastException") == 0)
5443 return MONO_EXC_INVALID_CAST;
5444 if (strcmp (name, "NullReferenceException") == 0)
5445 return MONO_EXC_NULL_REF;
5446 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5447 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5448 g_error ("Unknown intrinsic exception %s\n", name);
5454 mono_arch_emit_exceptions (MonoCompile *cfg)
5456 MonoJumpInfo *patch_info;
5459 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5460 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5461 int max_epilog_size = 50;
5463 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5464 exc_throw_pos [i] = NULL;
5465 exc_throw_found [i] = 0;
5468 /* count the number of exception infos */
5471 * make sure we have enough space for exceptions
5473 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5474 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5475 i = exception_id_by_name (patch_info->data.target);
5476 if (!exc_throw_found [i]) {
5477 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5478 exc_throw_found [i] = TRUE;
5480 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5481 max_epilog_size += 12;
5482 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5483 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5484 i = exception_id_by_name (ovfj->data.exception);
5485 if (!exc_throw_found [i]) {
5486 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5487 exc_throw_found [i] = TRUE;
5489 max_epilog_size += 8;
5493 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5494 cfg->code_size *= 2;
5495 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5496 mono_jit_stats.code_reallocs++;
5499 code = cfg->native_code + cfg->code_len;
5501 /* add code to raise exceptions */
5502 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5503 switch (patch_info->type) {
5504 case MONO_PATCH_INFO_BB_OVF: {
5505 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5506 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5507 /* patch the initial jump */
5508 ppc_patch (ip, code);
5509 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5511 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5512 /* jump back to the true target */
5514 ip = ovfj->data.bb->native_offset + cfg->native_code;
5515 ppc_patch (code - 4, ip);
5516 patch_info->type = MONO_PATCH_INFO_NONE;
5519 case MONO_PATCH_INFO_EXC_OVF: {
5520 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5521 MonoJumpInfo *newji;
5522 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5523 unsigned char *bcl = code;
5524 /* patch the initial jump: we arrived here with a call */
5525 ppc_patch (ip, code);
5526 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5528 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5529 /* patch the conditional jump to the right handler */
5530 /* make it processed next */
5531 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5532 newji->type = MONO_PATCH_INFO_EXC;
5533 newji->ip.i = bcl - cfg->native_code;
5534 newji->data.target = ovfj->data.exception;
5535 newji->next = patch_info->next;
5536 patch_info->next = newji;
5537 patch_info->type = MONO_PATCH_INFO_NONE;
5540 case MONO_PATCH_INFO_EXC: {
5541 MonoClass *exc_class;
5543 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5544 i = exception_id_by_name (patch_info->data.target);
5545 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5546 ppc_patch (ip, exc_throw_pos [i]);
5547 patch_info->type = MONO_PATCH_INFO_NONE;
5550 exc_throw_pos [i] = code;
5553 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5554 g_assert (exc_class);
5556 ppc_patch (ip, code);
5557 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5558 ppc_load (code, ppc_r3, exc_class->type_token);
5559 /* we got here from a conditional call, so the calling ip is set in lr */
5560 ppc_mflr (code, ppc_r4);
5561 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5562 patch_info->data.name = "mono_arch_throw_corlib_exception";
5563 patch_info->ip.i = code - cfg->native_code;
5564 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5565 ppc_load_func (code, ppc_r0, 0);
5566 ppc_mtctr (code, ppc_r0);
5567 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5579 cfg->code_len = code - cfg->native_code;
5581 g_assert (cfg->code_len <= cfg->code_size);
5587 try_offset_access (void *value, guint32 idx)
5589 register void* me __asm__ ("r2");
5590 void ***p = (void***)((char*)me + 284);
5591 int idx1 = idx / 32;
5592 int idx2 = idx % 32;
5595 if (value != p[idx1][idx2])
5602 setup_tls_access (void)
5606 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5607 size_t conf_size = 0;
5610 /* FIXME for darwin */
5611 guint32 *ins, *code;
5612 guint32 cmplwi_1023, li_0x48, blr_ins;
5616 tls_mode = TLS_MODE_FAILED;
5619 if (tls_mode == TLS_MODE_FAILED)
5621 if (g_getenv ("MONO_NO_TLS")) {
5622 tls_mode = TLS_MODE_FAILED;
5626 if (tls_mode == TLS_MODE_DETECT) {
5627 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5628 tls_mode = TLS_MODE_DARWIN_G4;
5629 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5630 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5631 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5632 tls_mode = TLS_MODE_NPTL;
5633 #elif !defined(TARGET_PS3)
5634 ins = (guint32*)pthread_getspecific;
5635 /* uncond branch to the real method */
5636 if ((*ins >> 26) == 18) {
5638 val = (*ins & ~3) << 6;
5642 ins = (guint32*)(long)val;
5644 ins = (guint32*) ((char*)ins + val);
5647 code = &cmplwi_1023;
5648 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5650 ppc_li (code, ppc_r4, 0x48);
5653 if (*ins == cmplwi_1023) {
5654 int found_lwz_284 = 0;
5655 for (ptk = 0; ptk < 20; ++ptk) {
5657 if (!*ins || *ins == blr_ins)
5659 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5664 if (!found_lwz_284) {
5665 tls_mode = TLS_MODE_FAILED;
5668 tls_mode = TLS_MODE_LTHREADS;
5669 } else if (*ins == li_0x48) {
5671 /* uncond branch to the real method */
5672 if ((*ins >> 26) == 18) {
5674 val = (*ins & ~3) << 6;
5678 ins = (guint32*)(long)val;
5680 ins = (guint32*) ((char*)ins + val);
5682 code = (guint32*)&val;
5683 ppc_li (code, ppc_r0, 0x7FF2);
5684 if (ins [1] == val) {
5685 /* Darwin on G4, implement */
5686 tls_mode = TLS_MODE_FAILED;
5689 code = (guint32*)&val;
5690 ppc_mfspr (code, ppc_r3, 104);
5691 if (ins [1] != val) {
5692 tls_mode = TLS_MODE_FAILED;
5695 tls_mode = TLS_MODE_DARWIN_G5;
5698 tls_mode = TLS_MODE_FAILED;
5702 tls_mode = TLS_MODE_FAILED;
5708 if (tls_mode == TLS_MODE_DETECT)
5709 tls_mode = TLS_MODE_FAILED;
5710 if (tls_mode == TLS_MODE_FAILED)
5712 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5713 monodomain_key = mono_domain_get_tls_offset();
5715 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5716 mono_domain_get_tls_offset returning -1) then use keyed access. */
5717 if (monodomain_key == -1) {
5718 ptk = mono_domain_get_tls_key ();
5720 ptk = mono_pthread_key_for_tls (ptk);
5722 monodomain_key = ptk;
5727 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5728 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5730 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5731 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5732 if (lmf_pthread_key == -1) {
5733 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5735 /*g_print ("MonoLMF at: %d\n", ptk);*/
5736 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5737 init_tls_failed = 1;
5740 lmf_pthread_key = ptk;
5747 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5749 setup_tls_access ();
5753 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5757 #ifdef MONO_ARCH_HAVE_IMT
5759 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5761 #define LOADSTORE_SIZE 4
5762 #define JUMP_IMM_SIZE 12
5763 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5764 #define ENABLE_WRONG_METHOD_CHECK 0
5767 * LOCKING: called with the domain lock held
5770 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5771 gpointer fail_tramp)
5775 guint8 *code, *start;
5777 for (i = 0; i < count; ++i) {
5778 MonoIMTCheckItem *item = imt_entries [i];
5779 if (item->is_equals) {
5780 if (item->check_target_idx) {
5781 if (!item->compare_done)
5782 item->chunk_size += CMP_SIZE;
5783 if (item->has_target_code)
5784 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5786 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5789 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5790 if (!item->has_target_code)
5791 item->chunk_size += LOADSTORE_SIZE;
5793 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5794 #if ENABLE_WRONG_METHOD_CHECK
5795 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5800 item->chunk_size += CMP_SIZE + BR_SIZE;
5801 imt_entries [item->check_target_idx]->compare_done = TRUE;
5803 size += item->chunk_size;
5805 /* the initial load of the vtable address */
5806 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5808 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5810 code = mono_domain_code_reserve (domain, size);
5815 * We need to save and restore r11 because it might be
5816 * used by the caller as the vtable register, so
5817 * clobbering it will trip up the magic trampoline.
5819 * FIXME: Get rid of this by making sure that r11 is
5820 * not used as the vtable register in interface calls.
5822 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5823 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5825 for (i = 0; i < count; ++i) {
5826 MonoIMTCheckItem *item = imt_entries [i];
5827 item->code_target = code;
5828 if (item->is_equals) {
5829 if (item->check_target_idx) {
5830 if (!item->compare_done) {
5831 ppc_load (code, ppc_r0, (gsize)item->key);
5832 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5834 item->jmp_code = code;
5835 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5836 if (item->has_target_code) {
5837 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5839 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5840 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5842 ppc_mtctr (code, ppc_r0);
5843 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5846 ppc_load (code, ppc_r0, (gulong)item->key);
5847 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5848 item->jmp_code = code;
5849 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5850 if (item->has_target_code) {
5851 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5854 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5855 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5857 ppc_mtctr (code, ppc_r0);
5858 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5859 ppc_patch (item->jmp_code, code);
5860 ppc_load_ptr (code, ppc_r0, fail_tramp);
5861 ppc_mtctr (code, ppc_r0);
5862 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5863 item->jmp_code = NULL;
5865 /* enable the commented code to assert on wrong method */
5866 #if ENABLE_WRONG_METHOD_CHECK
5867 ppc_load (code, ppc_r0, (guint32)item->key);
5868 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5869 item->jmp_code = code;
5870 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5872 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5873 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5874 ppc_mtctr (code, ppc_r0);
5875 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5876 #if ENABLE_WRONG_METHOD_CHECK
5877 ppc_patch (item->jmp_code, code);
5879 item->jmp_code = NULL;
5884 ppc_load (code, ppc_r0, (gulong)item->key);
5885 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5886 item->jmp_code = code;
5887 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5890 /* patch the branches to get to the target items */
5891 for (i = 0; i < count; ++i) {
5892 MonoIMTCheckItem *item = imt_entries [i];
5893 if (item->jmp_code) {
5894 if (item->check_target_idx) {
5895 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5901 mono_stats.imt_thunks_size += code - start;
5902 g_assert (code - start <= size);
5903 mono_arch_flush_icache (start, size);
5908 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5910 mgreg_t *r = (mgreg_t*)regs;
5912 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5917 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5919 mgreg_t *r = (mgreg_t*)regs;
5921 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5925 mono_arch_get_cie_program (void)
5929 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5935 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5942 mono_arch_print_tree (MonoInst *tree, int arity)
5947 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5951 setup_tls_access ();
5952 if (monodomain_key == -1)
5955 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5956 ins->inst_offset = monodomain_key;
5961 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5964 return MONO_CONTEXT_GET_SP (ctx);
5966 g_assert (reg >= ppc_r13);
5968 return (gpointer)(gsize)ctx->regs [reg - ppc_r13];
5972 mono_arch_get_patch_offset (guint8 *code)
5978 * mono_aot_emit_load_got_addr:
5980 * Emit code to load the got address.
5981 * On PPC, the result is placed into r30.
5984 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5987 ppc_mflr (code, ppc_r30);
5989 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5991 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5992 /* arch_emit_got_address () patches this */
5993 #if defined(TARGET_POWERPC64)
5999 ppc_load32 (code, ppc_r0, 0);
6000 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6007 * mono_ppc_emit_load_aotconst:
6009 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6010 * TARGET from the mscorlib GOT in full-aot code.
6011 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6015 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6017 /* Load the mscorlib got address */
6018 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
6019 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6020 /* arch_emit_got_access () patches this */
6021 ppc_load32 (code, ppc_r0, 0);
6022 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
6027 /* Soft Debug support */
6028 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6035 * mono_arch_set_breakpoint:
6037 * See mini-amd64.c for docs.
6040 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6043 guint8 *orig_code = code;
6045 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
6046 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
6048 g_assert (code - orig_code == BREAKPOINT_SIZE);
6050 mono_arch_flush_icache (orig_code, code - orig_code);
6054 * mono_arch_clear_breakpoint:
6056 * See mini-amd64.c for docs.
6059 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6064 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6067 mono_arch_flush_icache (ip, code - ip);
6071 * mono_arch_is_breakpoint_event:
6073 * See mini-amd64.c for docs.
6076 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6078 siginfo_t* sinfo = (siginfo_t*) info;
6079 /* Sometimes the address is off by 4 */
6080 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6087 * mono_arch_get_ip_for_breakpoint:
6089 * See mini-amd64.c for docs.
6092 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6094 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6096 /* ip points at the ldptr instruction */
6097 ip -= PPC_LOAD_SEQUENCE_LENGTH;
6103 * mono_arch_skip_breakpoint:
6105 * See mini-amd64.c for docs.
6108 mono_arch_skip_breakpoint (MonoContext *ctx)
6110 /* skip the ldptr */
6111 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6119 * mono_arch_start_single_stepping:
6121 * See mini-amd64.c for docs.
6124 mono_arch_start_single_stepping (void)
6126 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6130 * mono_arch_stop_single_stepping:
6132 * See mini-amd64.c for docs.
6135 mono_arch_stop_single_stepping (void)
6137 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6141 * mono_arch_is_single_step_event:
6143 * See mini-amd64.c for docs.
6146 mono_arch_is_single_step_event (void *info, void *sigctx)
6148 siginfo_t* sinfo = (siginfo_t*) info;
6149 /* Sometimes the address is off by 4 */
6150 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6157 * mono_arch_get_ip_for_single_step:
6159 * See mini-amd64.c for docs.
6162 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6164 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6166 /* ip points after the ldptr instruction */
6171 * mono_arch_skip_single_step:
6173 * See mini-amd64.c for docs.
6176 mono_arch_skip_single_step (MonoContext *ctx)
6178 /* skip the ldptr */
6179 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6183 * mono_arch_create_seq_point_info:
6185 * See mini-amd64.c for docs.
6188 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)