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))
344 /* code must point to the blrl */
346 mono_ppc_is_direct_call_sequence (guint32 *code)
348 #ifdef __mono_ppc64__
349 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
351 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
352 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
353 if (ppc_opcode (code [-2]) == 58 && ppc_opcode (code [-3]) == 58) { /* ld/ld */
354 if (!is_load_sequence (&code [-8]))
356 /* one of the loads must be "ld r2,8(rX)" */
357 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == 8) ||
358 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == 8);
360 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
361 return is_load_sequence (&code [-8]);
363 return is_load_sequence (&code [-6]);
367 g_assert(*code == 0x4e800021);
369 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
370 return ppc_opcode (code [-1]) == 31 &&
371 ppc_opcode (code [-2]) == 24 &&
372 ppc_opcode (code [-3]) == 15;
377 mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
381 guint32* code = (guint32*)code_ptr;
382 mgreg_t *r = (mgreg_t*)regs;
386 /* This is the 'blrl' instruction */
389 /* Sanity check: instruction must be 'blrl' */
390 if (*code != 0x4e800021)
393 if (mono_ppc_is_direct_call_sequence (code))
396 /* FIXME: more sanity checks here */
397 /* OK, we're now at the 'blrl' instruction. Now walk backwards
398 till we get to a 'mtlr rA' */
400 if((*code & 0x7c0803a6) == 0x7c0803a6) {
402 /* Here we are: we reached the 'mtlr rA'.
403 Extract the register from the instruction */
404 reg = (*code & 0x03e00000) >> 21;
406 /* ok, this is a lwz reg, offset (vtreg)
407 * it is emitted with:
408 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
410 soff = (*code & 0xffff);
412 reg = (*code >> 16) & 0x1f;
413 g_assert (reg != ppc_r1);
414 /*g_print ("patching reg is %d\n", reg);*/
415 o = (gpointer)(gsize)r [reg];
419 *displacement = offset;
423 #define MAX_ARCH_DELEGATE_PARAMS 7
426 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
428 guint8 *code, *start;
431 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
433 start = code = mono_global_codeman_reserve (size);
435 code = mono_ppc_create_pre_code_ftnptr (code);
437 /* Replace the this argument with the target */
438 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
439 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
440 /* it's a function descriptor */
441 /* Can't use ldptr as it doesn't work with r0 */
442 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
444 ppc_mtctr (code, ppc_r0);
445 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
446 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
448 g_assert ((code - start) <= size);
450 mono_arch_flush_icache (start, size);
454 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
455 start = code = mono_global_codeman_reserve (size);
457 code = mono_ppc_create_pre_code_ftnptr (code);
459 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
460 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
461 /* it's a function descriptor */
462 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
464 ppc_mtctr (code, ppc_r0);
465 /* slide down the arguments */
466 for (i = 0; i < param_count; ++i) {
467 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
469 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
471 g_assert ((code - start) <= size);
473 mono_arch_flush_icache (start, size);
477 *code_len = code - start;
483 mono_arch_get_delegate_invoke_impls (void)
490 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
491 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len));
493 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
494 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
495 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len));
502 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
504 guint8 *code, *start;
506 /* FIXME: Support more cases */
507 if (MONO_TYPE_ISSTRUCT (sig->ret))
511 static guint8* cached = NULL;
517 start = mono_aot_get_named_code ("delegate_invoke_impl_has_target");
519 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
521 mono_memory_barrier ();
525 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
528 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
530 for (i = 0; i < sig->param_count; ++i)
531 if (!mono_is_regsize_var (sig->params [i]))
535 code = cache [sig->param_count];
540 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
541 start = mono_aot_get_named_code (name);
544 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
547 mono_memory_barrier ();
549 cache [sig->param_count] = start;
555 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
557 mgreg_t *r = (mgreg_t*)regs;
559 /* FIXME: handle returning a struct */
560 if (MONO_TYPE_ISSTRUCT (sig->ret))
561 return (gpointer)(gsize)r [ppc_r4];
562 return (gpointer)(gsize)r [ppc_r3];
570 #ifdef USE_ENVIRON_HACK
572 linux_find_auxv (int *count)
576 char **result = __environ;
577 /* Scan over the env vector looking for the ending NULL */
578 for (; *result != NULL; ++result) {
580 /* Bump the pointer one more step, which should be the auxv. */
582 vec = (AuxVec *)result;
583 if (vec->type != 22 /*AT_IGNOREPPC*/) {
587 while (vec->type != 0 /*AT_NULL*/) {
592 return (AuxVec *)result;
596 #define MAX_AUX_ENTRIES 128
598 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
599 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
601 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
603 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
604 #define ISA_64 0x40000000
606 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
607 #define ISA_MOVE_FPR_GPR 0x00000200
609 * Initialize the cpu to execute managed code.
612 mono_arch_cpu_init (void)
618 mib [1] = HW_CACHELINE;
619 len = sizeof (cachelinesize);
620 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
624 cachelineinc = cachelinesize;
626 #elif defined(__linux__)
627 AuxVec vec [MAX_AUX_ENTRIES];
628 int i, vec_entries = 0;
629 /* sadly this will work only with 2.6 kernels... */
630 FILE* f = fopen ("/proc/self/auxv", "rb");
632 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
634 #ifdef USE_ENVIRON_HACK
636 AuxVec *evec = linux_find_auxv (&vec_entries);
638 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
641 for (i = 0; i < vec_entries; i++) {
642 int type = vec [i].type;
643 if (type == 19) { /* AT_DCACHEBSIZE */
644 cachelinesize = vec [i].value;
646 } else if (type == 16) { /* AT_HWCAP */
647 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
648 cpu_hw_caps |= PPC_ICACHE_SNOOP;
649 if (vec [i].value & ISA_2X)
650 cpu_hw_caps |= PPC_ISA_2X;
651 if (vec [i].value & ISA_64)
652 cpu_hw_caps |= PPC_ISA_64;
653 if (vec [i].value & ISA_MOVE_FPR_GPR)
654 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
656 } else if (type == 15) { /* AT_PLATFORM */
657 const char *arch = (char*)vec [i].value;
658 if (strcmp (arch, "ppc970") == 0 ||
659 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
660 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
661 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
665 #elif defined(G_COMPILER_CODEWARRIOR)
668 #elif defined(MONO_CROSS_COMPILE)
670 //#error Need a way to get cache line size
675 cachelineinc = cachelinesize;
677 if (mono_cpu_count () > 1)
678 cpu_hw_caps |= PPC_SMP_CAPABLE;
682 * Initialize architecture specific code.
685 mono_arch_init (void)
687 InitializeCriticalSection (&mini_arch_mutex);
689 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
690 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
691 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
695 * Cleanup architecture specific code.
698 mono_arch_cleanup (void)
700 DeleteCriticalSection (&mini_arch_mutex);
704 * This function returns the optimizations supported on this cpu.
707 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
711 /* no ppc-specific optimizations yet */
716 #ifdef __mono_ppc64__
717 #define CASE_PPC32(c)
718 #define CASE_PPC64(c) case c:
720 #define CASE_PPC32(c) case c:
721 #define CASE_PPC64(c)
725 is_regsize_var (MonoType *t) {
728 t = mini_type_get_underlying_type (NULL, t);
732 CASE_PPC64 (MONO_TYPE_I8)
733 CASE_PPC64 (MONO_TYPE_U8)
737 case MONO_TYPE_FNPTR:
739 case MONO_TYPE_OBJECT:
740 case MONO_TYPE_STRING:
741 case MONO_TYPE_CLASS:
742 case MONO_TYPE_SZARRAY:
743 case MONO_TYPE_ARRAY:
745 case MONO_TYPE_GENERICINST:
746 if (!mono_type_generic_inst_is_valuetype (t))
749 case MONO_TYPE_VALUETYPE:
756 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
761 for (i = 0; i < cfg->num_varinfo; i++) {
762 MonoInst *ins = cfg->varinfo [i];
763 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
766 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
769 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
772 /* we can only allocate 32 bit values */
773 if (is_regsize_var (ins->inst_vtype)) {
774 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
775 g_assert (i == vmv->idx);
776 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
784 mono_arch_get_global_int_regs (MonoCompile *cfg)
788 if (cfg->frame_reg != ppc_sp)
790 /* ppc_r13 is used by the system on PPC EABI */
791 for (i = 14; i < top; ++i) {
793 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
794 * since the trampolines can clobber r11.
796 if (!(cfg->compile_aot && i == 29))
797 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
804 * mono_arch_regalloc_cost:
806 * Return the cost, in number of memory references, of the action of
807 * allocating the variable VMV into a register during global register
811 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
818 mono_arch_flush_icache (guint8 *code, gint size)
820 #ifdef MONO_CROSS_COMPILE
823 guint8 *endp, *start;
827 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
828 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
829 #if defined(G_COMPILER_CODEWARRIOR)
830 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
831 for (p = start; p < endp; p += cachelineinc) {
835 for (p = start; p < endp; p += cachelineinc) {
841 for (p = start; p < endp; p += cachelineinc) {
852 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
853 * The sync is required to insure that the store queue is completely empty.
854 * While the icbi performs no cache operations, icbi/isync is required to
855 * kill local prefetch.
857 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
859 asm ("icbi 0,%0;" : : "r"(code) : "memory");
863 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
864 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
865 for (p = start; p < endp; p += cachelineinc) {
866 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
869 for (p = start; p < endp; p += cachelineinc) {
870 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
875 for (p = start; p < endp; p += cachelineinc) {
876 /* for ISA2.0+ implementations we should not need any extra sync between the
877 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
878 * So I am not sure which chip had this problem but its not an issue on
879 * of the ISA V2 chips.
881 if (cpu_hw_caps & PPC_ISA_2X)
882 asm ("icbi 0,%0;" : : "r"(p) : "memory");
884 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
886 if (!(cpu_hw_caps & PPC_ISA_2X))
894 mono_arch_flush_register_windows (void)
899 #define ALWAYS_ON_STACK(s) s
900 #define FP_ALSO_IN_REG(s) s
902 #ifdef __mono_ppc64__
903 #define ALWAYS_ON_STACK(s) s
904 #define FP_ALSO_IN_REG(s) s
906 #define ALWAYS_ON_STACK(s)
907 #define FP_ALSO_IN_REG(s)
909 #define ALIGN_DOUBLES
922 guint32 vtsize; /* in param area */
924 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
925 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
926 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
927 guint8 bytes : 4; /* size in bytes - only valid for
928 RegTypeStructByVal if the struct fits
929 in one word, otherwise it's 0*/
944 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
946 #ifdef __mono_ppc64__
951 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
952 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
953 ainfo->reg = ppc_sp; /* in the caller */
954 ainfo->regtype = RegTypeBase;
955 *stack_size += sizeof (gpointer);
957 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
961 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
963 //*stack_size += (*stack_size % 8);
965 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
966 ainfo->reg = ppc_sp; /* in the caller */
967 ainfo->regtype = RegTypeBase;
974 ALWAYS_ON_STACK (*stack_size += 8);
982 #if defined(__APPLE__) || defined(__mono_ppc64__)
984 has_only_a_r48_field (MonoClass *klass)
988 gboolean have_field = FALSE;
990 while ((f = mono_class_get_fields (klass, &iter))) {
991 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
994 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1005 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
1008 int n = sig->hasthis + sig->param_count;
1009 MonoType *simpletype;
1010 guint32 stack_size = 0;
1011 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1013 fr = PPC_FIRST_FPARG_REG;
1014 gr = PPC_FIRST_ARG_REG;
1016 /* FIXME: handle returning a struct */
1017 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1018 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1019 cinfo->struct_ret = PPC_FIRST_ARG_REG;
1024 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1027 DEBUG(printf("params: %d\n", sig->param_count));
1028 for (i = 0; i < sig->param_count; ++i) {
1029 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1030 /* Prevent implicit arguments and sig_cookie from
1031 being passed in registers */
1032 gr = PPC_LAST_ARG_REG + 1;
1033 /* FIXME: don't we have to set fr, too? */
1034 /* Emit the signature cookie just before the implicit arguments */
1035 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1037 DEBUG(printf("param %d: ", i));
1038 if (sig->params [i]->byref) {
1039 DEBUG(printf("byref\n"));
1040 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1044 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1045 switch (simpletype->type) {
1046 case MONO_TYPE_BOOLEAN:
1049 cinfo->args [n].size = 1;
1050 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1053 case MONO_TYPE_CHAR:
1056 cinfo->args [n].size = 2;
1057 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1062 cinfo->args [n].size = 4;
1063 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1069 case MONO_TYPE_FNPTR:
1070 case MONO_TYPE_CLASS:
1071 case MONO_TYPE_OBJECT:
1072 case MONO_TYPE_STRING:
1073 case MONO_TYPE_SZARRAY:
1074 case MONO_TYPE_ARRAY:
1075 cinfo->args [n].size = sizeof (gpointer);
1076 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1079 case MONO_TYPE_GENERICINST:
1080 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1081 cinfo->args [n].size = sizeof (gpointer);
1082 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1087 case MONO_TYPE_VALUETYPE:
1088 case MONO_TYPE_TYPEDBYREF: {
1092 klass = mono_class_from_mono_type (sig->params [i]);
1093 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1094 size = sizeof (MonoTypedRef);
1095 else if (is_pinvoke)
1096 size = mono_class_native_size (klass, NULL);
1098 size = mono_class_value_size (klass, NULL);
1100 #if defined(__APPLE__) || defined(__mono_ppc64__)
1101 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1102 cinfo->args [n].size = size;
1104 /* It was 7, now it is 8 in LinuxPPC */
1105 if (fr <= PPC_LAST_FPARG_REG) {
1106 cinfo->args [n].regtype = RegTypeFP;
1107 cinfo->args [n].reg = fr;
1109 FP_ALSO_IN_REG (gr ++);
1111 FP_ALSO_IN_REG (gr ++);
1112 ALWAYS_ON_STACK (stack_size += size);
1114 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1115 cinfo->args [n].regtype = RegTypeBase;
1116 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1123 DEBUG(printf ("load %d bytes struct\n",
1124 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1126 #if PPC_PASS_STRUCTS_BY_VALUE
1128 int align_size = size;
1130 int rest = PPC_LAST_ARG_REG - gr + 1;
1133 align_size += (sizeof (gpointer) - 1);
1134 align_size &= ~(sizeof (gpointer) - 1);
1135 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1136 n_in_regs = MIN (rest, nregs);
1140 /* FIXME: check this */
1141 if (size >= 3 && size % 4 != 0)
1144 cinfo->args [n].regtype = RegTypeStructByVal;
1145 cinfo->args [n].vtregs = n_in_regs;
1146 cinfo->args [n].size = n_in_regs;
1147 cinfo->args [n].vtsize = nregs - n_in_regs;
1148 cinfo->args [n].reg = gr;
1150 #ifdef __mono_ppc64__
1151 if (nregs == 1 && is_pinvoke)
1152 cinfo->args [n].bytes = size;
1155 cinfo->args [n].bytes = 0;
1157 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1158 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1159 stack_size += nregs * sizeof (gpointer);
1162 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1163 cinfo->args [n].regtype = RegTypeStructByAddr;
1164 cinfo->args [n].vtsize = size;
1171 cinfo->args [n].size = 8;
1172 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1176 cinfo->args [n].size = 4;
1178 /* It was 7, now it is 8 in LinuxPPC */
1179 if (fr <= PPC_LAST_FPARG_REG) {
1180 cinfo->args [n].regtype = RegTypeFP;
1181 cinfo->args [n].reg = fr;
1183 FP_ALSO_IN_REG (gr ++);
1184 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1186 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1187 cinfo->args [n].regtype = RegTypeBase;
1188 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1189 stack_size += SIZEOF_REGISTER;
1194 cinfo->args [n].size = 8;
1195 /* It was 7, now it is 8 in LinuxPPC */
1196 if (fr <= PPC_LAST_FPARG_REG) {
1197 cinfo->args [n].regtype = RegTypeFP;
1198 cinfo->args [n].reg = fr;
1200 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1201 ALWAYS_ON_STACK (stack_size += 8);
1203 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1204 cinfo->args [n].regtype = RegTypeBase;
1205 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1211 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1215 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1216 /* Prevent implicit arguments and sig_cookie from
1217 being passed in registers */
1218 gr = PPC_LAST_ARG_REG + 1;
1219 /* Emit the signature cookie just before the implicit arguments */
1220 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1224 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1225 switch (simpletype->type) {
1226 case MONO_TYPE_BOOLEAN:
1231 case MONO_TYPE_CHAR:
1237 case MONO_TYPE_FNPTR:
1238 case MONO_TYPE_CLASS:
1239 case MONO_TYPE_OBJECT:
1240 case MONO_TYPE_SZARRAY:
1241 case MONO_TYPE_ARRAY:
1242 case MONO_TYPE_STRING:
1243 cinfo->ret.reg = ppc_r3;
1247 cinfo->ret.reg = ppc_r3;
1251 cinfo->ret.reg = ppc_f1;
1252 cinfo->ret.regtype = RegTypeFP;
1254 case MONO_TYPE_GENERICINST:
1255 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1256 cinfo->ret.reg = ppc_r3;
1260 case MONO_TYPE_VALUETYPE:
1262 case MONO_TYPE_TYPEDBYREF:
1263 case MONO_TYPE_VOID:
1266 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1270 /* align stack size to 16 */
1271 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1272 stack_size = (stack_size + 15) & ~15;
1274 cinfo->stack_usage = stack_size;
1279 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1281 #if !PPC_PASS_STRUCTS_BY_VALUE
1282 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1283 int num_structs = 0;
1286 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1289 for (i = 0; i < sig->param_count; ++i) {
1290 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1291 if (type->type == MONO_TYPE_VALUETYPE)
1296 cfg->tailcall_valuetype_addrs =
1297 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1298 for (i = 0; i < num_structs; ++i) {
1299 cfg->tailcall_valuetype_addrs [i] =
1300 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1301 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1308 * Set var information according to the calling convention. ppc version.
1309 * The locals var stuff should most likely be split in another method.
1312 mono_arch_allocate_vars (MonoCompile *m)
1314 MonoMethodSignature *sig;
1315 MonoMethodHeader *header;
1317 int i, offset, size, align, curinst;
1318 int frame_reg = ppc_sp;
1320 guint32 locals_stack_size, locals_stack_align;
1322 allocate_tailcall_valuetype_addrs (m);
1324 m->flags |= MONO_CFG_HAS_SPILLUP;
1326 /* allow room for the vararg method args: void* and long/double */
1327 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1328 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1329 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1330 * call convs needs to be handled this way.
1332 if (m->flags & MONO_CFG_HAS_VARARGS)
1333 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1334 /* gtk-sharp and other broken code will dllimport vararg functions even with
1335 * non-varargs signatures. Since there is little hope people will get this right
1336 * we assume they won't.
1338 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1339 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1344 * We use the frame register also for any method that has
1345 * exception clauses. This way, when the handlers are called,
1346 * the code will reference local variables using the frame reg instead of
1347 * the stack pointer: if we had to restore the stack pointer, we'd
1348 * corrupt the method frames that are already on the stack (since
1349 * filters get called before stack unwinding happens) when the filter
1350 * code would call any method (this also applies to finally etc.).
1352 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1353 frame_reg = ppc_r31;
1354 m->frame_reg = frame_reg;
1355 if (frame_reg != ppc_sp) {
1356 m->used_int_regs |= 1 << frame_reg;
1359 sig = mono_method_signature (m->method);
1363 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1364 m->ret->opcode = OP_REGVAR;
1365 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1367 /* FIXME: handle long values? */
1368 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1369 case MONO_TYPE_VOID:
1373 m->ret->opcode = OP_REGVAR;
1374 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1377 m->ret->opcode = OP_REGVAR;
1378 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1382 /* local vars are at a positive offset from the stack pointer */
1384 * also note that if the function uses alloca, we use ppc_r31
1385 * to point at the local variables.
1387 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1388 /* align the offset to 16 bytes: not sure this is needed here */
1390 //offset &= ~(16 - 1);
1392 /* add parameter area size for called functions */
1393 offset += m->param_area;
1395 offset &= ~(16 - 1);
1397 /* allow room to save the return value */
1398 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1401 /* the MonoLMF structure is stored just below the stack pointer */
1404 /* this stuff should not be needed on ppc and the new jit,
1405 * because a call on ppc to the handlers doesn't change the
1406 * stack pointer and the jist doesn't manipulate the stack pointer
1407 * for operations involving valuetypes.
1409 /* reserve space to store the esp */
1410 offset += sizeof (gpointer);
1412 /* this is a global constant */
1413 mono_exc_esp_offset = offset;
1416 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1417 offset += sizeof(gpointer) - 1;
1418 offset &= ~(sizeof(gpointer) - 1);
1420 m->vret_addr->opcode = OP_REGOFFSET;
1421 m->vret_addr->inst_basereg = frame_reg;
1422 m->vret_addr->inst_offset = offset;
1424 if (G_UNLIKELY (m->verbose_level > 1)) {
1425 printf ("vret_addr =");
1426 mono_print_ins (m->vret_addr);
1429 offset += sizeof(gpointer);
1432 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1433 if (locals_stack_align) {
1434 offset += (locals_stack_align - 1);
1435 offset &= ~(locals_stack_align - 1);
1437 for (i = m->locals_start; i < m->num_varinfo; i++) {
1438 if (offsets [i] != -1) {
1439 MonoInst *inst = m->varinfo [i];
1440 inst->opcode = OP_REGOFFSET;
1441 inst->inst_basereg = frame_reg;
1442 inst->inst_offset = offset + offsets [i];
1444 g_print ("allocating local %d (%s) to %d\n",
1445 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1449 offset += locals_stack_size;
1453 inst = m->args [curinst];
1454 if (inst->opcode != OP_REGVAR) {
1455 inst->opcode = OP_REGOFFSET;
1456 inst->inst_basereg = frame_reg;
1457 offset += sizeof (gpointer) - 1;
1458 offset &= ~(sizeof (gpointer) - 1);
1459 inst->inst_offset = offset;
1460 offset += sizeof (gpointer);
1465 for (i = 0; i < sig->param_count; ++i) {
1466 inst = m->args [curinst];
1467 if (inst->opcode != OP_REGVAR) {
1468 inst->opcode = OP_REGOFFSET;
1469 inst->inst_basereg = frame_reg;
1471 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1472 inst->backend.is_pinvoke = 1;
1474 size = mono_type_size (sig->params [i], &align);
1476 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1477 size = align = sizeof (gpointer);
1478 offset += align - 1;
1479 offset &= ~(align - 1);
1480 inst->inst_offset = offset;
1486 /* some storage for fp conversions */
1489 m->arch.fp_conv_var_offset = offset;
1492 /* align the offset to 16 bytes */
1494 offset &= ~(16 - 1);
1497 m->stack_offset = offset;
1499 if (sig->call_convention == MONO_CALL_VARARG) {
1500 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1502 m->sig_cookie = cinfo->sig_cookie.offset;
1509 mono_arch_create_vars (MonoCompile *cfg)
1511 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1513 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1514 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1518 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1519 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1523 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1525 int sig_reg = mono_alloc_ireg (cfg);
1527 /* FIXME: Add support for signature tokens to AOT */
1528 cfg->disable_aot = TRUE;
1530 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1531 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1532 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1536 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1539 MonoMethodSignature *sig;
1543 sig = call->signature;
1544 n = sig->param_count + sig->hasthis;
1546 cinfo = calculate_sizes (sig, sig->pinvoke);
1548 for (i = 0; i < n; ++i) {
1549 ArgInfo *ainfo = cinfo->args + i;
1552 if (i >= sig->hasthis)
1553 t = sig->params [i - sig->hasthis];
1555 t = &mono_defaults.int_class->byval_arg;
1556 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1558 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1559 emit_sig_cookie (cfg, call, cinfo);
1561 in = call->args [i];
1563 if (ainfo->regtype == RegTypeGeneral) {
1564 #ifndef __mono_ppc64__
1565 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1566 MONO_INST_NEW (cfg, ins, OP_MOVE);
1567 ins->dreg = mono_alloc_ireg (cfg);
1568 ins->sreg1 = in->dreg + 1;
1569 MONO_ADD_INS (cfg->cbb, ins);
1570 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1572 MONO_INST_NEW (cfg, ins, OP_MOVE);
1573 ins->dreg = mono_alloc_ireg (cfg);
1574 ins->sreg1 = in->dreg + 2;
1575 MONO_ADD_INS (cfg->cbb, ins);
1576 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1580 MONO_INST_NEW (cfg, ins, OP_MOVE);
1581 ins->dreg = mono_alloc_ireg (cfg);
1582 ins->sreg1 = in->dreg;
1583 MONO_ADD_INS (cfg->cbb, ins);
1585 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1587 } else if (ainfo->regtype == RegTypeStructByAddr) {
1588 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1589 ins->opcode = OP_OUTARG_VT;
1590 ins->sreg1 = in->dreg;
1591 ins->klass = in->klass;
1592 ins->inst_p0 = call;
1593 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1594 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1595 MONO_ADD_INS (cfg->cbb, ins);
1596 } else if (ainfo->regtype == RegTypeStructByVal) {
1597 /* this is further handled in mono_arch_emit_outarg_vt () */
1598 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1599 ins->opcode = OP_OUTARG_VT;
1600 ins->sreg1 = in->dreg;
1601 ins->klass = in->klass;
1602 ins->inst_p0 = call;
1603 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1604 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1605 MONO_ADD_INS (cfg->cbb, ins);
1606 } else if (ainfo->regtype == RegTypeBase) {
1607 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1608 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1609 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1610 if (t->type == MONO_TYPE_R8)
1611 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1613 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1615 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1617 } else if (ainfo->regtype == RegTypeFP) {
1618 if (t->type == MONO_TYPE_VALUETYPE) {
1619 /* this is further handled in mono_arch_emit_outarg_vt () */
1620 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1621 ins->opcode = OP_OUTARG_VT;
1622 ins->sreg1 = in->dreg;
1623 ins->klass = in->klass;
1624 ins->inst_p0 = call;
1625 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1626 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1627 MONO_ADD_INS (cfg->cbb, ins);
1629 cfg->flags |= MONO_CFG_HAS_FPOUT;
1631 int dreg = mono_alloc_freg (cfg);
1633 if (ainfo->size == 4) {
1634 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1636 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1638 ins->sreg1 = in->dreg;
1639 MONO_ADD_INS (cfg->cbb, ins);
1642 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1643 cfg->flags |= MONO_CFG_HAS_FPOUT;
1646 g_assert_not_reached ();
1650 /* Emit the signature cookie in the case that there is no
1651 additional argument */
1652 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1653 emit_sig_cookie (cfg, call, cinfo);
1655 if (cinfo->struct_ret) {
1658 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1659 vtarg->sreg1 = call->vret_var->dreg;
1660 vtarg->dreg = mono_alloc_preg (cfg);
1661 MONO_ADD_INS (cfg->cbb, vtarg);
1663 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1666 call->stack_usage = cinfo->stack_usage;
1667 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1668 cfg->flags |= MONO_CFG_HAS_CALLS;
1674 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1676 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1677 ArgInfo *ainfo = ins->inst_p1;
1678 int ovf_size = ainfo->vtsize;
1679 int doffset = ainfo->offset;
1680 int i, soffset, dreg;
1682 if (ainfo->regtype == RegTypeStructByVal) {
1689 * Darwin pinvokes needs some special handling for 1
1690 * and 2 byte arguments
1692 g_assert (ins->klass);
1693 if (call->signature->pinvoke)
1694 size = mono_class_native_size (ins->klass, NULL);
1695 if (size == 2 || size == 1) {
1696 int tmpr = mono_alloc_ireg (cfg);
1698 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1700 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1701 dreg = mono_alloc_ireg (cfg);
1702 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1703 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1706 for (i = 0; i < ainfo->vtregs; ++i) {
1707 int antipadding = 0;
1710 antipadding = sizeof (gpointer) - ainfo->bytes;
1712 dreg = mono_alloc_ireg (cfg);
1713 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1716 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1717 soffset += sizeof (gpointer);
1720 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1721 } else if (ainfo->regtype == RegTypeFP) {
1722 int tmpr = mono_alloc_freg (cfg);
1723 if (ainfo->size == 4)
1724 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1726 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1727 dreg = mono_alloc_freg (cfg);
1728 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1729 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1731 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1735 /* FIXME: alignment? */
1736 if (call->signature->pinvoke) {
1737 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1738 vtcopy->backend.is_pinvoke = 1;
1740 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1743 g_assert (ovf_size > 0);
1745 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1746 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1749 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1751 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1756 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1758 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1759 mono_method_signature (method)->ret);
1762 #ifndef __mono_ppc64__
1763 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1766 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1767 ins->sreg1 = val->dreg + 1;
1768 ins->sreg2 = val->dreg + 2;
1769 MONO_ADD_INS (cfg->cbb, ins);
1773 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1774 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1778 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1781 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1783 mono_arch_is_inst_imm (gint64 imm)
1789 * Allow tracing to work with this interface (with an optional argument)
1793 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1797 ppc_load_ptr (code, ppc_r3, cfg->method);
1798 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1799 ppc_load_func (code, ppc_r0, func);
1800 ppc_mtlr (code, ppc_r0);
1814 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1817 int save_mode = SAVE_NONE;
1819 MonoMethod *method = cfg->method;
1820 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1821 mono_method_signature (method)->ret)->type;
1822 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1826 offset = code - cfg->native_code;
1827 /* we need about 16 instructions */
1828 if (offset > (cfg->code_size - 16 * 4)) {
1829 cfg->code_size *= 2;
1830 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1831 code = cfg->native_code + offset;
1835 case MONO_TYPE_VOID:
1836 /* special case string .ctor icall */
1837 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1838 save_mode = SAVE_ONE;
1840 save_mode = SAVE_NONE;
1842 #ifndef __mono_ppc64__
1845 save_mode = SAVE_TWO;
1850 save_mode = SAVE_FP;
1852 case MONO_TYPE_VALUETYPE:
1853 save_mode = SAVE_STRUCT;
1856 save_mode = SAVE_ONE;
1860 switch (save_mode) {
1862 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1863 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1864 if (enable_arguments) {
1865 ppc_mr (code, ppc_r5, ppc_r4);
1866 ppc_mr (code, ppc_r4, ppc_r3);
1870 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1871 if (enable_arguments) {
1872 ppc_mr (code, ppc_r4, ppc_r3);
1876 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1877 if (enable_arguments) {
1878 /* FIXME: what reg? */
1879 ppc_fmr (code, ppc_f3, ppc_f1);
1880 /* FIXME: use 8 byte load on PPC64 */
1881 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1882 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1886 if (enable_arguments) {
1887 /* FIXME: get the actual address */
1888 ppc_mr (code, ppc_r4, ppc_r3);
1896 ppc_load_ptr (code, ppc_r3, cfg->method);
1897 ppc_load_func (code, ppc_r0, func);
1898 ppc_mtlr (code, ppc_r0);
1901 switch (save_mode) {
1903 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1904 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1907 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1910 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1920 * Conditional branches have a small offset, so if it is likely overflowed,
1921 * we do a branch to the end of the method (uncond branches have much larger
1922 * offsets) where we perform the conditional and jump back unconditionally.
1923 * It's slightly slower, since we add two uncond branches, but it's very simple
1924 * with the current patch implementation and such large methods are likely not
1925 * going to be perf critical anyway.
1930 const char *exception;
1937 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1938 if (0 && ins->inst_true_bb->native_offset) { \
1939 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1941 int br_disp = ins->inst_true_bb->max_offset - offset; \
1942 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1943 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1944 ovfj->data.bb = ins->inst_true_bb; \
1945 ovfj->ip_offset = 0; \
1946 ovfj->b0_cond = (b0); \
1947 ovfj->b1_cond = (b1); \
1948 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1951 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1952 ppc_bc (code, (b0), (b1), 0); \
1956 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1958 /* emit an exception if condition is fail
1960 * We assign the extra code used to throw the implicit exceptions
1961 * to cfg->bb_exit as far as the big branch handling is concerned
1963 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1965 int br_disp = cfg->bb_exit->max_offset - offset; \
1966 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1967 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1968 ovfj->data.exception = (exc_name); \
1969 ovfj->ip_offset = code - cfg->native_code; \
1970 ovfj->b0_cond = (b0); \
1971 ovfj->b1_cond = (b1); \
1972 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1974 cfg->bb_exit->max_offset += 24; \
1976 mono_add_patch_info (cfg, code - cfg->native_code, \
1977 MONO_PATCH_INFO_EXC, exc_name); \
1978 ppc_bcl (code, (b0), (b1), 0); \
1982 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1985 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1990 normalize_opcode (int opcode)
1993 #ifndef __mono_ilp32__
1994 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1995 return OP_LOAD_MEMBASE;
1996 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1997 return OP_LOAD_MEMINDEX;
1998 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1999 return OP_STORE_MEMBASE_REG;
2000 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2001 return OP_STORE_MEMBASE_IMM;
2002 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2003 return OP_STORE_MEMINDEX;
2005 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2007 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2008 return OP_SHR_UN_IMM;
2015 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2017 MonoInst *ins, *n, *last_ins = NULL;
2019 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2020 switch (normalize_opcode (ins->opcode)) {
2022 /* remove unnecessary multiplication with 1 */
2023 if (ins->inst_imm == 1) {
2024 if (ins->dreg != ins->sreg1) {
2025 ins->opcode = OP_MOVE;
2027 MONO_DELETE_INS (bb, ins);
2031 int power2 = mono_is_power_of_two (ins->inst_imm);
2033 ins->opcode = OP_SHL_IMM;
2034 ins->inst_imm = power2;
2038 case OP_LOAD_MEMBASE:
2040 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2041 * OP_LOAD_MEMBASE offset(basereg), reg
2043 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2044 ins->inst_basereg == last_ins->inst_destbasereg &&
2045 ins->inst_offset == last_ins->inst_offset) {
2046 if (ins->dreg == last_ins->sreg1) {
2047 MONO_DELETE_INS (bb, ins);
2050 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2051 ins->opcode = OP_MOVE;
2052 ins->sreg1 = last_ins->sreg1;
2056 * Note: reg1 must be different from the basereg in the second load
2057 * OP_LOAD_MEMBASE offset(basereg), reg1
2058 * OP_LOAD_MEMBASE offset(basereg), reg2
2060 * OP_LOAD_MEMBASE offset(basereg), reg1
2061 * OP_MOVE reg1, reg2
2063 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2064 ins->inst_basereg != last_ins->dreg &&
2065 ins->inst_basereg == last_ins->inst_basereg &&
2066 ins->inst_offset == last_ins->inst_offset) {
2068 if (ins->dreg == last_ins->dreg) {
2069 MONO_DELETE_INS (bb, ins);
2072 ins->opcode = OP_MOVE;
2073 ins->sreg1 = last_ins->dreg;
2076 //g_assert_not_reached ();
2080 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2081 * OP_LOAD_MEMBASE offset(basereg), reg
2083 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2084 * OP_ICONST reg, imm
2086 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2087 ins->inst_basereg == last_ins->inst_destbasereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2089 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2090 ins->opcode = OP_ICONST;
2091 ins->inst_c0 = last_ins->inst_imm;
2092 g_assert_not_reached (); // check this rule
2096 case OP_LOADU1_MEMBASE:
2097 case OP_LOADI1_MEMBASE:
2098 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2099 ins->inst_basereg == last_ins->inst_destbasereg &&
2100 ins->inst_offset == last_ins->inst_offset) {
2101 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2102 ins->sreg1 = last_ins->sreg1;
2105 case OP_LOADU2_MEMBASE:
2106 case OP_LOADI2_MEMBASE:
2107 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2108 ins->inst_basereg == last_ins->inst_destbasereg &&
2109 ins->inst_offset == last_ins->inst_offset) {
2110 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2111 ins->sreg1 = last_ins->sreg1;
2114 #ifdef __mono_ppc64__
2115 case OP_LOADU4_MEMBASE:
2116 case OP_LOADI4_MEMBASE:
2117 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2118 ins->inst_basereg == last_ins->inst_destbasereg &&
2119 ins->inst_offset == last_ins->inst_offset) {
2120 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2121 ins->sreg1 = last_ins->sreg1;
2126 ins->opcode = OP_MOVE;
2130 if (ins->dreg == ins->sreg1) {
2131 MONO_DELETE_INS (bb, ins);
2135 * OP_MOVE sreg, dreg
2136 * OP_MOVE dreg, sreg
2138 if (last_ins && last_ins->opcode == OP_MOVE &&
2139 ins->sreg1 == last_ins->dreg &&
2140 ins->dreg == last_ins->sreg1) {
2141 MONO_DELETE_INS (bb, ins);
2149 bb->last_ins = last_ins;
2153 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2155 switch (ins->opcode) {
2156 case OP_ICONV_TO_R_UN: {
2157 #if G_BYTE_ORDER == G_BIG_ENDIAN
2158 static const guint64 adjust_val = 0x4330000000000000ULL;
2160 static const guint64 adjust_val = 0x0000000000003043ULL;
2162 int msw_reg = mono_alloc_ireg (cfg);
2163 int adj_reg = mono_alloc_freg (cfg);
2164 int tmp_reg = mono_alloc_freg (cfg);
2165 int basereg = ppc_sp;
2167 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2168 if (!ppc_is_imm16 (offset + 4)) {
2169 basereg = mono_alloc_ireg (cfg);
2170 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2172 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2173 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2174 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2175 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2177 ins->opcode = OP_NOP;
2180 #ifndef __mono_ppc64__
2181 case OP_ICONV_TO_R4:
2182 case OP_ICONV_TO_R8: {
2183 /* If we have a PPC_FEATURE_64 machine we can avoid
2184 this and use the fcfid instruction. Otherwise
2185 on an old 32-bit chip and we have to do this the
2187 if (!(cpu_hw_caps & PPC_ISA_64)) {
2188 /* FIXME: change precision for CEE_CONV_R4 */
2189 static const guint64 adjust_val = 0x4330000080000000ULL;
2190 int msw_reg = mono_alloc_ireg (cfg);
2191 int xored = mono_alloc_ireg (cfg);
2192 int adj_reg = mono_alloc_freg (cfg);
2193 int tmp_reg = mono_alloc_freg (cfg);
2194 int basereg = ppc_sp;
2196 if (!ppc_is_imm16 (offset + 4)) {
2197 basereg = mono_alloc_ireg (cfg);
2198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2200 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2201 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2202 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2204 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2205 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2207 if (ins->opcode == OP_ICONV_TO_R4)
2208 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2209 ins->opcode = OP_NOP;
2215 int msw_reg = mono_alloc_ireg (cfg);
2216 int basereg = ppc_sp;
2218 if (!ppc_is_imm16 (offset + 4)) {
2219 basereg = mono_alloc_ireg (cfg);
2220 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2222 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2223 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2224 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2225 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2226 ins->opcode = OP_NOP;
2229 #ifdef __mono_ppc64__
2231 case OP_IADD_OVF_UN:
2233 int shifted1_reg = mono_alloc_ireg (cfg);
2234 int shifted2_reg = mono_alloc_ireg (cfg);
2235 int result_shifted_reg = mono_alloc_ireg (cfg);
2237 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2238 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2239 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2240 if (ins->opcode == OP_IADD_OVF_UN)
2241 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2243 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2244 ins->opcode = OP_NOP;
2251 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2253 switch (ins->opcode) {
2255 /* ADC sets the condition code */
2256 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2257 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2260 case OP_LADD_OVF_UN:
2261 /* ADC sets the condition code */
2262 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2267 /* SBB sets the condition code */
2268 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2272 case OP_LSUB_OVF_UN:
2273 /* SBB sets the condition code */
2274 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2279 /* This is the old version from inssel-long32.brg */
2280 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 1, ins->sreg1 + 1);
2281 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 2, ins->sreg1 + 2);
2282 /* ADC sets the condition codes */
2283 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 1, ins->dreg + 1, 1);
2284 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->dreg + 2, 0);
2293 * the branch_b0_table should maintain the order of these
2307 branch_b0_table [] = {
2322 branch_b1_table [] = {
2336 #define NEW_INS(cfg,dest,op) do { \
2337 MONO_INST_NEW((cfg), (dest), (op)); \
2338 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2342 map_to_reg_reg_op (int op)
2351 case OP_COMPARE_IMM:
2353 case OP_ICOMPARE_IMM:
2355 case OP_LCOMPARE_IMM:
2371 case OP_LOAD_MEMBASE:
2372 return OP_LOAD_MEMINDEX;
2373 case OP_LOADI4_MEMBASE:
2374 return OP_LOADI4_MEMINDEX;
2375 case OP_LOADU4_MEMBASE:
2376 return OP_LOADU4_MEMINDEX;
2377 case OP_LOADI8_MEMBASE:
2378 return OP_LOADI8_MEMINDEX;
2379 case OP_LOADU1_MEMBASE:
2380 return OP_LOADU1_MEMINDEX;
2381 case OP_LOADI2_MEMBASE:
2382 return OP_LOADI2_MEMINDEX;
2383 case OP_LOADU2_MEMBASE:
2384 return OP_LOADU2_MEMINDEX;
2385 case OP_LOADI1_MEMBASE:
2386 return OP_LOADI1_MEMINDEX;
2387 case OP_LOADR4_MEMBASE:
2388 return OP_LOADR4_MEMINDEX;
2389 case OP_LOADR8_MEMBASE:
2390 return OP_LOADR8_MEMINDEX;
2391 case OP_STOREI1_MEMBASE_REG:
2392 return OP_STOREI1_MEMINDEX;
2393 case OP_STOREI2_MEMBASE_REG:
2394 return OP_STOREI2_MEMINDEX;
2395 case OP_STOREI4_MEMBASE_REG:
2396 return OP_STOREI4_MEMINDEX;
2397 case OP_STOREI8_MEMBASE_REG:
2398 return OP_STOREI8_MEMINDEX;
2399 case OP_STORE_MEMBASE_REG:
2400 return OP_STORE_MEMINDEX;
2401 case OP_STORER4_MEMBASE_REG:
2402 return OP_STORER4_MEMINDEX;
2403 case OP_STORER8_MEMBASE_REG:
2404 return OP_STORER8_MEMINDEX;
2405 case OP_STORE_MEMBASE_IMM:
2406 return OP_STORE_MEMBASE_REG;
2407 case OP_STOREI1_MEMBASE_IMM:
2408 return OP_STOREI1_MEMBASE_REG;
2409 case OP_STOREI2_MEMBASE_IMM:
2410 return OP_STOREI2_MEMBASE_REG;
2411 case OP_STOREI4_MEMBASE_IMM:
2412 return OP_STOREI4_MEMBASE_REG;
2413 case OP_STOREI8_MEMBASE_IMM:
2414 return OP_STOREI8_MEMBASE_REG;
2416 return mono_op_imm_to_op (op);
2419 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2421 #define compare_opcode_is_unsigned(opcode) \
2422 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2423 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2424 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2425 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2426 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2427 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2428 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2429 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2432 * Remove from the instruction list the instructions that can't be
2433 * represented with very simple instructions with no register
2437 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2439 MonoInst *ins, *next, *temp, *last_ins = NULL;
2442 MONO_BB_FOR_EACH_INS (bb, ins) {
2444 switch (ins->opcode) {
2445 case OP_IDIV_UN_IMM:
2448 case OP_IREM_UN_IMM:
2449 NEW_INS (cfg, temp, OP_ICONST);
2450 temp->inst_c0 = ins->inst_imm;
2451 temp->dreg = mono_alloc_ireg (cfg);
2452 ins->sreg2 = temp->dreg;
2453 if (ins->opcode == OP_IDIV_IMM)
2454 ins->opcode = OP_IDIV;
2455 else if (ins->opcode == OP_IREM_IMM)
2456 ins->opcode = OP_IREM;
2457 else if (ins->opcode == OP_IDIV_UN_IMM)
2458 ins->opcode = OP_IDIV_UN;
2459 else if (ins->opcode == OP_IREM_UN_IMM)
2460 ins->opcode = OP_IREM_UN;
2462 /* handle rem separately */
2466 CASE_PPC64 (OP_LREM)
2467 CASE_PPC64 (OP_LREM_UN) {
2469 /* we change a rem dest, src1, src2 to
2470 * div temp1, src1, src2
2471 * mul temp2, temp1, src2
2472 * sub dest, src1, temp2
2474 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2475 NEW_INS (cfg, mul, OP_IMUL);
2476 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2477 ins->opcode = OP_ISUB;
2479 NEW_INS (cfg, mul, OP_LMUL);
2480 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2481 ins->opcode = OP_LSUB;
2483 temp->sreg1 = ins->sreg1;
2484 temp->sreg2 = ins->sreg2;
2485 temp->dreg = mono_alloc_ireg (cfg);
2486 mul->sreg1 = temp->dreg;
2487 mul->sreg2 = ins->sreg2;
2488 mul->dreg = mono_alloc_ireg (cfg);
2489 ins->sreg2 = mul->dreg;
2493 CASE_PPC64 (OP_LADD_IMM)
2496 if (!ppc_is_imm16 (ins->inst_imm)) {
2497 NEW_INS (cfg, temp, OP_ICONST);
2498 temp->inst_c0 = ins->inst_imm;
2499 temp->dreg = mono_alloc_ireg (cfg);
2500 ins->sreg2 = temp->dreg;
2501 ins->opcode = map_to_reg_reg_op (ins->opcode);
2505 CASE_PPC64 (OP_LSUB_IMM)
2507 if (!ppc_is_imm16 (-ins->inst_imm)) {
2508 NEW_INS (cfg, temp, OP_ICONST);
2509 temp->inst_c0 = ins->inst_imm;
2510 temp->dreg = mono_alloc_ireg (cfg);
2511 ins->sreg2 = temp->dreg;
2512 ins->opcode = map_to_reg_reg_op (ins->opcode);
2524 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2525 #ifdef __mono_ppc64__
2526 if (ins->inst_imm & 0xffffffff00000000ULL)
2530 NEW_INS (cfg, temp, OP_ICONST);
2531 temp->inst_c0 = ins->inst_imm;
2532 temp->dreg = mono_alloc_ireg (cfg);
2533 ins->sreg2 = temp->dreg;
2534 ins->opcode = map_to_reg_reg_op (ins->opcode);
2543 NEW_INS (cfg, temp, OP_ICONST);
2544 temp->inst_c0 = ins->inst_imm;
2545 temp->dreg = mono_alloc_ireg (cfg);
2546 ins->sreg2 = temp->dreg;
2547 ins->opcode = map_to_reg_reg_op (ins->opcode);
2549 case OP_COMPARE_IMM:
2550 case OP_ICOMPARE_IMM:
2551 CASE_PPC64 (OP_LCOMPARE_IMM)
2553 /* Branch opts can eliminate the branch */
2554 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2555 ins->opcode = OP_NOP;
2559 if (compare_opcode_is_unsigned (next->opcode)) {
2560 if (!ppc_is_uimm16 (ins->inst_imm)) {
2561 NEW_INS (cfg, temp, OP_ICONST);
2562 temp->inst_c0 = ins->inst_imm;
2563 temp->dreg = mono_alloc_ireg (cfg);
2564 ins->sreg2 = temp->dreg;
2565 ins->opcode = map_to_reg_reg_op (ins->opcode);
2568 if (!ppc_is_imm16 (ins->inst_imm)) {
2569 NEW_INS (cfg, temp, OP_ICONST);
2570 temp->inst_c0 = ins->inst_imm;
2571 temp->dreg = mono_alloc_ireg (cfg);
2572 ins->sreg2 = temp->dreg;
2573 ins->opcode = map_to_reg_reg_op (ins->opcode);
2579 if (ins->inst_imm == 1) {
2580 ins->opcode = OP_MOVE;
2583 if (ins->inst_imm == 0) {
2584 ins->opcode = OP_ICONST;
2588 imm = mono_is_power_of_two (ins->inst_imm);
2590 ins->opcode = OP_SHL_IMM;
2591 ins->inst_imm = imm;
2594 if (!ppc_is_imm16 (ins->inst_imm)) {
2595 NEW_INS (cfg, temp, OP_ICONST);
2596 temp->inst_c0 = ins->inst_imm;
2597 temp->dreg = mono_alloc_ireg (cfg);
2598 ins->sreg2 = temp->dreg;
2599 ins->opcode = map_to_reg_reg_op (ins->opcode);
2602 case OP_LOCALLOC_IMM:
2603 NEW_INS (cfg, temp, OP_ICONST);
2604 temp->inst_c0 = ins->inst_imm;
2605 temp->dreg = mono_alloc_ireg (cfg);
2606 ins->sreg1 = temp->dreg;
2607 ins->opcode = OP_LOCALLOC;
2609 case OP_LOAD_MEMBASE:
2610 case OP_LOADI4_MEMBASE:
2611 CASE_PPC64 (OP_LOADI8_MEMBASE)
2612 case OP_LOADU4_MEMBASE:
2613 case OP_LOADI2_MEMBASE:
2614 case OP_LOADU2_MEMBASE:
2615 case OP_LOADI1_MEMBASE:
2616 case OP_LOADU1_MEMBASE:
2617 case OP_LOADR4_MEMBASE:
2618 case OP_LOADR8_MEMBASE:
2619 case OP_STORE_MEMBASE_REG:
2620 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2621 case OP_STOREI4_MEMBASE_REG:
2622 case OP_STOREI2_MEMBASE_REG:
2623 case OP_STOREI1_MEMBASE_REG:
2624 case OP_STORER4_MEMBASE_REG:
2625 case OP_STORER8_MEMBASE_REG:
2626 /* we can do two things: load the immed in a register
2627 * and use an indexed load, or see if the immed can be
2628 * represented as an ad_imm + a load with a smaller offset
2629 * that fits. We just do the first for now, optimize later.
2631 if (ppc_is_imm16 (ins->inst_offset))
2633 NEW_INS (cfg, temp, OP_ICONST);
2634 temp->inst_c0 = ins->inst_offset;
2635 temp->dreg = mono_alloc_ireg (cfg);
2636 ins->sreg2 = temp->dreg;
2637 ins->opcode = map_to_reg_reg_op (ins->opcode);
2639 case OP_STORE_MEMBASE_IMM:
2640 case OP_STOREI1_MEMBASE_IMM:
2641 case OP_STOREI2_MEMBASE_IMM:
2642 case OP_STOREI4_MEMBASE_IMM:
2643 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2644 NEW_INS (cfg, temp, OP_ICONST);
2645 temp->inst_c0 = ins->inst_imm;
2646 temp->dreg = mono_alloc_ireg (cfg);
2647 ins->sreg1 = temp->dreg;
2648 ins->opcode = map_to_reg_reg_op (ins->opcode);
2650 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2653 if (cfg->compile_aot) {
2654 /* Keep these in the aot case */
2657 NEW_INS (cfg, temp, OP_ICONST);
2658 temp->inst_c0 = (gulong)ins->inst_p0;
2659 temp->dreg = mono_alloc_ireg (cfg);
2660 ins->inst_basereg = temp->dreg;
2661 ins->inst_offset = 0;
2662 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2664 /* make it handle the possibly big ins->inst_offset
2665 * later optimize to use lis + load_membase
2671 bb->last_ins = last_ins;
2672 bb->max_vreg = cfg->next_vreg;
2676 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2678 long offset = cfg->arch.fp_conv_var_offset;
2680 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2681 #ifdef __mono_ppc64__
2683 ppc_fctidz (code, ppc_f0, sreg);
2688 ppc_fctiwz (code, ppc_f0, sreg);
2691 if (ppc_is_imm16 (offset + sub_offset)) {
2692 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2694 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2696 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2698 ppc_load (code, dreg, offset);
2699 ppc_add (code, dreg, dreg, cfg->frame_reg);
2700 ppc_stfd (code, ppc_f0, 0, dreg);
2702 ppc_ldr (code, dreg, sub_offset, dreg);
2704 ppc_lwz (code, dreg, sub_offset, dreg);
2708 ppc_andid (code, dreg, dreg, 0xff);
2710 ppc_andid (code, dreg, dreg, 0xffff);
2711 #ifdef __mono_ppc64__
2713 ppc_clrldi (code, dreg, dreg, 32);
2717 ppc_extsb (code, dreg, dreg);
2719 ppc_extsh (code, dreg, dreg);
2720 #ifdef __mono_ppc64__
2722 ppc_extsw (code, dreg, dreg);
2730 const guchar *target;
2735 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2738 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2739 #ifdef __mono_ppc64__
2740 g_assert_not_reached ();
2742 PatchData *pdata = (PatchData*)user_data;
2743 guchar *code = data;
2744 guint32 *thunks = data;
2745 guint32 *endthunks = (guint32*)(code + bsize);
2749 int difflow, diffhigh;
2751 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2752 difflow = (char*)pdata->code - (char*)thunks;
2753 diffhigh = (char*)pdata->code - (char*)endthunks;
2754 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2757 templ = (guchar*)load;
2758 ppc_load_sequence (templ, ppc_r0, pdata->target);
2760 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2761 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2762 while (thunks < endthunks) {
2763 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2764 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2765 ppc_patch (pdata->code, (guchar*)thunks);
2768 static int num_thunks = 0;
2770 if ((num_thunks % 20) == 0)
2771 g_print ("num_thunks lookup: %d\n", num_thunks);
2774 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2775 /* found a free slot instead: emit thunk */
2776 code = (guchar*)thunks;
2777 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2778 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2779 ppc_mtctr (code, ppc_r0);
2780 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2781 mono_arch_flush_icache ((guchar*)thunks, 16);
2783 ppc_patch (pdata->code, (guchar*)thunks);
2786 static int num_thunks = 0;
2788 if ((num_thunks % 20) == 0)
2789 g_print ("num_thunks: %d\n", num_thunks);
2793 /* skip 16 bytes, the size of the thunk */
2797 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2804 handle_thunk (int absolute, guchar *code, const guchar *target) {
2805 MonoDomain *domain = mono_domain_get ();
2809 pdata.target = target;
2810 pdata.absolute = absolute;
2813 mono_domain_lock (domain);
2814 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2817 /* this uses the first available slot */
2819 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2821 mono_domain_unlock (domain);
2823 if (pdata.found != 1)
2824 g_print ("thunk failed for %p from %p\n", target, code);
2825 g_assert (pdata.found == 1);
2829 patch_ins (guint8 *code, guint32 ins)
2831 *(guint32*)code = GUINT32_TO_BE (ins);
2832 mono_arch_flush_icache (code, 4);
2836 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2838 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2839 guint32 prim = ins >> 26;
2842 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2844 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2845 gint diff = target - code;
2848 if (diff <= 33554431){
2849 ins = (18 << 26) | (diff) | (ins & 1);
2850 patch_ins (code, ins);
2854 /* diff between 0 and -33554432 */
2855 if (diff >= -33554432){
2856 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2857 patch_ins (code, ins);
2862 if ((glong)target >= 0){
2863 if ((glong)target <= 33554431){
2864 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2865 patch_ins (code, ins);
2869 if ((glong)target >= -33554432){
2870 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2871 patch_ins (code, ins);
2876 handle_thunk (TRUE, code, target);
2879 g_assert_not_reached ();
2887 guint32 li = (gulong)target;
2888 ins = (ins & 0xffff0000) | (ins & 3);
2889 ovf = li & 0xffff0000;
2890 if (ovf != 0 && ovf != 0xffff0000)
2891 g_assert_not_reached ();
2894 // FIXME: assert the top bits of li are 0
2896 gint diff = target - code;
2897 ins = (ins & 0xffff0000) | (ins & 3);
2898 ovf = diff & 0xffff0000;
2899 if (ovf != 0 && ovf != 0xffff0000)
2900 g_assert_not_reached ();
2904 patch_ins (code, ins);
2908 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2909 #ifdef __mono_ppc64__
2910 guint32 *seq = (guint32*)code;
2911 guint32 *branch_ins;
2913 /* the trampoline code will try to patch the blrl, blr, bcctr */
2914 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2916 if (ppc_opcode (seq [-3]) == 58 || ppc_opcode (seq [-3]) == 31) /* ld || mr */
2921 if (ppc_opcode (seq [5]) == 58 || ppc_opcode (seq [5]) == 31) /* ld || mr */
2922 branch_ins = seq + 8;
2924 branch_ins = seq + 6;
2927 seq = (guint32*)code;
2928 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2929 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2931 if (ppc_opcode (seq [5]) == 58) { /* ld */
2932 g_assert (ppc_opcode (seq [6]) == 58); /* ld */
2935 guint8 *buf = (guint8*)&seq [5];
2936 ppc_mr (buf, ppc_r0, ppc_r11);
2941 target = mono_get_addr_from_ftnptr ((gpointer)target);
2944 /* FIXME: make this thread safe */
2945 /* FIXME: we're assuming we're using r11 here */
2946 ppc_load_ptr_sequence (code, ppc_r11, target);
2947 mono_arch_flush_icache ((guint8*)seq, 28);
2950 /* the trampoline code will try to patch the blrl, blr, bcctr */
2951 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2954 /* this is the lis/ori/mtlr/blrl sequence */
2955 seq = (guint32*)code;
2956 g_assert ((seq [0] >> 26) == 15);
2957 g_assert ((seq [1] >> 26) == 24);
2958 g_assert ((seq [2] >> 26) == 31);
2959 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2960 /* FIXME: make this thread safe */
2961 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2962 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2963 mono_arch_flush_icache (code - 8, 8);
2966 g_assert_not_reached ();
2968 // g_print ("patched with 0x%08x\n", ins);
2972 ppc_patch (guchar *code, const guchar *target)
2974 ppc_patch_full (code, target, FALSE);
2978 mono_ppc_patch (guchar *code, const guchar *target)
2980 ppc_patch (code, target);
2984 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2986 switch (ins->opcode) {
2989 case OP_FCALL_MEMBASE:
2990 if (ins->dreg != ppc_f1)
2991 ppc_fmr (code, ins->dreg, ppc_f1);
2999 * emit_load_volatile_arguments:
3001 * Load volatile arguments from the stack to the original input registers.
3002 * Required before a tail call.
3005 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3007 MonoMethod *method = cfg->method;
3008 MonoMethodSignature *sig;
3012 int struct_index = 0;
3014 sig = mono_method_signature (method);
3016 /* This is the opposite of the code in emit_prolog */
3020 cinfo = calculate_sizes (sig, sig->pinvoke);
3022 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3023 ArgInfo *ainfo = &cinfo->ret;
3024 inst = cfg->vret_addr;
3025 g_assert (ppc_is_imm16 (inst->inst_offset));
3026 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3028 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3029 ArgInfo *ainfo = cinfo->args + i;
3030 inst = cfg->args [pos];
3032 g_assert (inst->opcode != OP_REGVAR);
3033 g_assert (ppc_is_imm16 (inst->inst_offset));
3035 switch (ainfo->regtype) {
3036 case RegTypeGeneral:
3037 switch (ainfo->size) {
3039 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3042 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3044 #ifdef __mono_ppc64__
3046 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3050 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3056 switch (ainfo->size) {
3058 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3061 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3064 g_assert_not_reached ();
3069 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3070 &inst->klass->byval_arg);
3072 #ifndef __mono_ppc64__
3073 if (type->type == MONO_TYPE_I8)
3077 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3078 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3079 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3080 } else if (type->type == MONO_TYPE_I4) {
3081 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3082 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3090 case RegTypeStructByVal: {
3101 * Darwin pinvokes needs some special handling
3102 * for 1 and 2 byte arguments
3104 if (method->signature->pinvoke)
3105 size = mono_class_native_size (inst->klass, NULL);
3106 if (size == 1 || size == 2) {
3111 for (j = 0; j < ainfo->vtregs; ++j) {
3112 ppc_ldptr (code, ainfo->reg + j,
3113 inst->inst_offset + j * sizeof (gpointer),
3114 inst->inst_basereg);
3115 /* FIXME: shift to the right */
3122 case RegTypeStructByAddr: {
3123 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3125 g_assert (ppc_is_imm16 (addr->inst_offset));
3126 g_assert (!ainfo->offset);
3127 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3134 g_assert_not_reached ();
3145 /* This must be kept in sync with emit_load_volatile_arguments(). */
3147 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3149 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3150 MonoMethodSignature *sig;
3155 if (ins->opcode != OP_JMP)
3158 call = (MonoCallInst*)ins;
3159 sig = mono_method_signature (cfg->method);
3160 cinfo = calculate_sizes (sig, sig->pinvoke);
3162 if (MONO_TYPE_ISSTRUCT (sig->ret))
3164 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3165 ArgInfo *ainfo = cinfo->args + i;
3167 switch (ainfo->regtype) {
3168 case RegTypeGeneral:
3177 case RegTypeStructByVal:
3178 len += 4 * ainfo->size;
3181 case RegTypeStructByAddr:
3186 g_assert_not_reached ();
3196 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3198 long size = cfg->param_area;
3200 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3201 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3206 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3207 if (ppc_is_imm16 (-size)) {
3208 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3210 ppc_load (code, ppc_r11, -size);
3211 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3218 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3220 long size = cfg->param_area;
3222 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3223 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3228 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3229 if (ppc_is_imm16 (size)) {
3230 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3232 ppc_load (code, ppc_r11, size);
3233 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3239 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3242 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3244 MonoInst *ins, *next;
3247 guint8 *code = cfg->native_code + cfg->code_len;
3248 MonoInst *last_ins = NULL;
3249 guint last_offset = 0;
3253 /* we don't align basic blocks of loops on ppc */
3255 if (cfg->verbose_level > 2)
3256 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3258 cpos = bb->max_offset;
3260 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3261 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3262 //g_assert (!mono_compile_aot);
3265 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3266 /* this is not thread save, but good enough */
3267 /* fixme: howto handle overflows? */
3268 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3271 MONO_BB_FOR_EACH_INS (bb, ins) {
3272 offset = code - cfg->native_code;
3274 max_len = ins_native_length (cfg, ins);
3276 if (offset > (cfg->code_size - max_len - 16)) {
3277 cfg->code_size *= 2;
3278 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3279 code = cfg->native_code + offset;
3281 // if (ins->cil_code)
3282 // g_print ("cil code\n");
3283 mono_debug_record_line_number (cfg, ins, offset);
3285 switch (normalize_opcode (ins->opcode)) {
3286 case OP_RELAXED_NOP:
3289 case OP_DUMMY_STORE:
3290 case OP_NOT_REACHED:
3293 case OP_SEQ_POINT: {
3296 if (cfg->compile_aot)
3300 * Read from the single stepping trigger page. This will cause a
3301 * SIGSEGV when single stepping is enabled.
3302 * We do this _before_ the breakpoint, so single stepping after
3303 * a breakpoint is hit will step to the next IL offset.
3305 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3306 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3307 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3310 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3313 * A placeholder for a possible breakpoint inserted by
3314 * mono_arch_set_breakpoint ().
3316 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3321 emit_tls_access (code, ins->dreg, ins->inst_offset);
3324 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3325 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3326 ppc_mr (code, ppc_r4, ppc_r0);
3329 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3330 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3331 ppc_mr (code, ppc_r4, ppc_r0);
3333 case OP_MEMORY_BARRIER:
3336 case OP_STOREI1_MEMBASE_REG:
3337 if (ppc_is_imm16 (ins->inst_offset)) {
3338 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3340 if (ppc_is_imm32 (ins->inst_offset)) {
3341 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3342 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3344 ppc_load (code, ppc_r0, ins->inst_offset);
3345 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3349 case OP_STOREI2_MEMBASE_REG:
3350 if (ppc_is_imm16 (ins->inst_offset)) {
3351 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3353 if (ppc_is_imm32 (ins->inst_offset)) {
3354 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3355 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3357 ppc_load (code, ppc_r0, ins->inst_offset);
3358 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3362 case OP_STORE_MEMBASE_REG:
3363 if (ppc_is_imm16 (ins->inst_offset)) {
3364 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3366 if (ppc_is_imm32 (ins->inst_offset)) {
3367 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3368 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3370 ppc_load (code, ppc_r0, ins->inst_offset);
3371 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3375 #ifdef __mono_ilp32__
3376 case OP_STOREI8_MEMBASE_REG:
3377 if (ppc_is_imm16 (ins->inst_offset)) {
3378 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3380 ppc_load (code, ppc_r0, ins->inst_offset);
3381 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3385 case OP_STOREI1_MEMINDEX:
3386 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3388 case OP_STOREI2_MEMINDEX:
3389 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3391 case OP_STORE_MEMINDEX:
3392 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3395 g_assert_not_reached ();
3397 case OP_LOAD_MEMBASE:
3398 if (ppc_is_imm16 (ins->inst_offset)) {
3399 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3401 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3402 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3403 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3405 ppc_load (code, ppc_r0, ins->inst_offset);
3406 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3410 case OP_LOADI4_MEMBASE:
3411 #ifdef __mono_ppc64__
3412 if (ppc_is_imm16 (ins->inst_offset)) {
3413 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3415 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3416 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3417 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3419 ppc_load (code, ppc_r0, ins->inst_offset);
3420 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3425 case OP_LOADU4_MEMBASE:
3426 if (ppc_is_imm16 (ins->inst_offset)) {
3427 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3429 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3430 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3431 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3433 ppc_load (code, ppc_r0, ins->inst_offset);
3434 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3438 case OP_LOADI1_MEMBASE:
3439 case OP_LOADU1_MEMBASE:
3440 if (ppc_is_imm16 (ins->inst_offset)) {
3441 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3443 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3444 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3445 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3447 ppc_load (code, ppc_r0, ins->inst_offset);
3448 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3451 if (ins->opcode == OP_LOADI1_MEMBASE)
3452 ppc_extsb (code, ins->dreg, ins->dreg);
3454 case OP_LOADU2_MEMBASE:
3455 if (ppc_is_imm16 (ins->inst_offset)) {
3456 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3458 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3459 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3460 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3462 ppc_load (code, ppc_r0, ins->inst_offset);
3463 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3467 case OP_LOADI2_MEMBASE:
3468 if (ppc_is_imm16 (ins->inst_offset)) {
3469 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3471 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3472 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3473 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3475 ppc_load (code, ppc_r0, ins->inst_offset);
3476 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3480 #ifdef __mono_ilp32__
3481 case OP_LOADI8_MEMBASE:
3482 if (ppc_is_imm16 (ins->inst_offset)) {
3483 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3485 ppc_load (code, ppc_r0, ins->inst_offset);
3486 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3490 case OP_LOAD_MEMINDEX:
3491 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3493 case OP_LOADI4_MEMINDEX:
3494 #ifdef __mono_ppc64__
3495 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3498 case OP_LOADU4_MEMINDEX:
3499 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3501 case OP_LOADU2_MEMINDEX:
3502 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3504 case OP_LOADI2_MEMINDEX:
3505 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3507 case OP_LOADU1_MEMINDEX:
3508 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3510 case OP_LOADI1_MEMINDEX:
3511 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3512 ppc_extsb (code, ins->dreg, ins->dreg);
3514 case OP_ICONV_TO_I1:
3515 CASE_PPC64 (OP_LCONV_TO_I1)
3516 ppc_extsb (code, ins->dreg, ins->sreg1);
3518 case OP_ICONV_TO_I2:
3519 CASE_PPC64 (OP_LCONV_TO_I2)
3520 ppc_extsh (code, ins->dreg, ins->sreg1);
3522 case OP_ICONV_TO_U1:
3523 CASE_PPC64 (OP_LCONV_TO_U1)
3524 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3526 case OP_ICONV_TO_U2:
3527 CASE_PPC64 (OP_LCONV_TO_U2)
3528 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3532 CASE_PPC64 (OP_LCOMPARE)
3533 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3535 if (next && compare_opcode_is_unsigned (next->opcode))
3536 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3538 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3540 case OP_COMPARE_IMM:
3541 case OP_ICOMPARE_IMM:
3542 CASE_PPC64 (OP_LCOMPARE_IMM)
3543 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3545 if (next && compare_opcode_is_unsigned (next->opcode)) {
3546 if (ppc_is_uimm16 (ins->inst_imm)) {
3547 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3549 g_assert_not_reached ();
3552 if (ppc_is_imm16 (ins->inst_imm)) {
3553 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3555 g_assert_not_reached ();
3564 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3567 CASE_PPC64 (OP_LADD)
3568 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3572 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3575 if (ppc_is_imm16 (ins->inst_imm)) {
3576 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3578 g_assert_not_reached ();
3583 CASE_PPC64 (OP_LADD_IMM)
3584 if (ppc_is_imm16 (ins->inst_imm)) {
3585 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3587 g_assert_not_reached ();
3591 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3593 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 ppc_mfspr (code, ppc_r0, ppc_xer);
3595 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3596 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3598 case OP_IADD_OVF_UN:
3599 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3601 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3602 ppc_mfspr (code, ppc_r0, ppc_xer);
3603 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3604 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3607 CASE_PPC64 (OP_LSUB_OVF)
3608 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3610 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3611 ppc_mfspr (code, ppc_r0, ppc_xer);
3612 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3613 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3615 case OP_ISUB_OVF_UN:
3616 CASE_PPC64 (OP_LSUB_OVF_UN)
3617 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3619 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3620 ppc_mfspr (code, ppc_r0, ppc_xer);
3621 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3622 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3624 case OP_ADD_OVF_CARRY:
3625 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3627 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3628 ppc_mfspr (code, ppc_r0, ppc_xer);
3629 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3630 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3632 case OP_ADD_OVF_UN_CARRY:
3633 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3635 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3636 ppc_mfspr (code, ppc_r0, ppc_xer);
3637 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3638 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3640 case OP_SUB_OVF_CARRY:
3641 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3643 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3644 ppc_mfspr (code, ppc_r0, ppc_xer);
3645 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3646 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3648 case OP_SUB_OVF_UN_CARRY:
3649 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3651 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3652 ppc_mfspr (code, ppc_r0, ppc_xer);
3653 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3654 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3658 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3661 CASE_PPC64 (OP_LSUB)
3662 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3666 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3670 CASE_PPC64 (OP_LSUB_IMM)
3671 // we add the negated value
3672 if (ppc_is_imm16 (-ins->inst_imm))
3673 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3675 g_assert_not_reached ();
3679 g_assert (ppc_is_imm16 (ins->inst_imm));
3680 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3683 ppc_subfze (code, ins->dreg, ins->sreg1);
3686 CASE_PPC64 (OP_LAND)
3687 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3688 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3692 CASE_PPC64 (OP_LAND_IMM)
3693 if (!(ins->inst_imm & 0xffff0000)) {
3694 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3695 } else if (!(ins->inst_imm & 0xffff)) {
3696 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3698 g_assert_not_reached ();
3702 CASE_PPC64 (OP_LDIV) {
3703 guint8 *divisor_is_m1;
3704 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3706 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3707 divisor_is_m1 = code;
3708 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3709 ppc_lis (code, ppc_r0, 0x8000);
3710 #ifdef __mono_ppc64__
3711 if (ins->opcode == OP_LDIV)
3712 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3714 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3715 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3716 ppc_patch (divisor_is_m1, code);
3717 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3719 if (ins->opcode == OP_IDIV)
3720 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3721 #ifdef __mono_ppc64__
3723 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3725 ppc_mfspr (code, ppc_r0, ppc_xer);
3726 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3727 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3731 CASE_PPC64 (OP_LDIV_UN)
3732 if (ins->opcode == OP_IDIV_UN)
3733 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3734 #ifdef __mono_ppc64__
3736 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3738 ppc_mfspr (code, ppc_r0, ppc_xer);
3739 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3740 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3746 g_assert_not_reached ();
3749 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3753 CASE_PPC64 (OP_LOR_IMM)
3754 if (!(ins->inst_imm & 0xffff0000)) {
3755 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3756 } else if (!(ins->inst_imm & 0xffff)) {
3757 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3759 g_assert_not_reached ();
3763 CASE_PPC64 (OP_LXOR)
3764 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3768 CASE_PPC64 (OP_LXOR_IMM)
3769 if (!(ins->inst_imm & 0xffff0000)) {
3770 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3771 } else if (!(ins->inst_imm & 0xffff)) {
3772 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3774 g_assert_not_reached ();
3778 CASE_PPC64 (OP_LSHL)
3779 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3783 CASE_PPC64 (OP_LSHL_IMM)
3784 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3787 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3790 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3793 if (MASK_SHIFT_IMM (ins->inst_imm))
3794 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3796 ppc_mr (code, ins->dreg, ins->sreg1);
3799 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3802 CASE_PPC64 (OP_LNOT)
3803 ppc_not (code, ins->dreg, ins->sreg1);
3806 CASE_PPC64 (OP_LNEG)
3807 ppc_neg (code, ins->dreg, ins->sreg1);
3810 CASE_PPC64 (OP_LMUL)
3811 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3815 CASE_PPC64 (OP_LMUL_IMM)
3816 if (ppc_is_imm16 (ins->inst_imm)) {
3817 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3819 g_assert_not_reached ();
3823 CASE_PPC64 (OP_LMUL_OVF)
3824 /* we annot use mcrxr, since it's not implemented on some processors
3825 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3827 if (ins->opcode == OP_IMUL_OVF)
3828 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3829 #ifdef __mono_ppc64__
3831 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3833 ppc_mfspr (code, ppc_r0, ppc_xer);
3834 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3835 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3837 case OP_IMUL_OVF_UN:
3838 CASE_PPC64 (OP_LMUL_OVF_UN)
3839 /* we first multiply to get the high word and compare to 0
3840 * to set the flags, then the result is discarded and then
3841 * we multiply to get the lower * bits result
3843 if (ins->opcode == OP_IMUL_OVF_UN)
3844 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3845 #ifdef __mono_ppc64__
3847 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3849 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3850 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3851 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3854 ppc_load (code, ins->dreg, ins->inst_c0);
3857 ppc_load (code, ins->dreg, ins->inst_l);
3860 case OP_LOAD_GOTADDR:
3861 /* The PLT implementation depends on this */
3862 g_assert (ins->dreg == ppc_r30);
3864 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3867 // FIXME: Fix max instruction length
3868 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3869 /* arch_emit_got_access () patches this */
3870 ppc_load32 (code, ppc_r0, 0);
3871 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3874 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3875 ppc_load_sequence (code, ins->dreg, 0);
3877 CASE_PPC32 (OP_ICONV_TO_I4)
3878 CASE_PPC32 (OP_ICONV_TO_U4)
3880 ppc_mr (code, ins->dreg, ins->sreg1);
3883 int saved = ins->sreg1;
3884 if (ins->sreg1 == ppc_r3) {
3885 ppc_mr (code, ppc_r0, ins->sreg1);
3888 if (ins->sreg2 != ppc_r3)
3889 ppc_mr (code, ppc_r3, ins->sreg2);
3890 if (saved != ppc_r4)
3891 ppc_mr (code, ppc_r4, saved);
3895 ppc_fmr (code, ins->dreg, ins->sreg1);
3897 case OP_FCONV_TO_R4:
3898 ppc_frsp (code, ins->dreg, ins->sreg1);
3904 * Keep in sync with mono_arch_emit_epilog
3906 g_assert (!cfg->method->save_lmf);
3908 * Note: we can use ppc_r11 here because it is dead anyway:
3909 * we're leaving the method.
3911 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3912 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3913 if (ppc_is_imm16 (ret_offset)) {
3914 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3916 ppc_load (code, ppc_r11, ret_offset);
3917 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3919 ppc_mtlr (code, ppc_r0);
3922 code = emit_load_volatile_arguments (cfg, code);
3924 if (ppc_is_imm16 (cfg->stack_usage)) {
3925 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3927 /* cfg->stack_usage is an int, so we can use
3928 * an addis/addi sequence here even in 64-bit. */
3929 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3930 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3932 if (!cfg->method->save_lmf) {
3933 /*for (i = 31; i >= 14; --i) {
3934 if (cfg->used_float_regs & (1 << i)) {
3935 pos += sizeof (double);
3936 ppc_lfd (code, i, -pos, cfg->frame_reg);
3940 for (i = 31; i >= 13; --i) {
3941 if (cfg->used_int_regs & (1 << i)) {
3942 pos += sizeof (gpointer);
3943 ppc_ldptr (code, i, -pos, ppc_r11);
3947 /* FIXME restore from MonoLMF: though this can't happen yet */
3949 ppc_mr (code, ppc_sp, ppc_r11);
3950 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3951 if (cfg->compile_aot) {
3952 /* arch_emit_got_access () patches this */
3953 ppc_load32 (code, ppc_r0, 0);
3954 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3955 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3956 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3958 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3960 ppc_mtctr (code, ppc_r0);
3961 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3968 /* ensure ins->sreg1 is not NULL */
3969 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3972 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3973 if (ppc_is_imm16 (cookie_offset)) {
3974 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3976 ppc_load (code, ppc_r0, cookie_offset);
3977 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3979 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3988 call = (MonoCallInst*)ins;
3989 if (ins->flags & MONO_INST_HAS_METHOD)
3990 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3992 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3993 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3994 ppc_load_func (code, ppc_r0, 0);
3995 ppc_mtlr (code, ppc_r0);
4000 /* FIXME: this should be handled somewhere else in the new jit */
4001 code = emit_move_return_value (cfg, ins, code);
4007 case OP_VOIDCALL_REG:
4009 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4010 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4011 /* FIXME: if we know that this is a method, we
4012 can omit this load */
4013 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4014 ppc_mtlr (code, ppc_r0);
4016 ppc_mtlr (code, ins->sreg1);
4019 /* FIXME: this should be handled somewhere else in the new jit */
4020 code = emit_move_return_value (cfg, ins, code);
4022 case OP_FCALL_MEMBASE:
4023 case OP_LCALL_MEMBASE:
4024 case OP_VCALL_MEMBASE:
4025 case OP_VCALL2_MEMBASE:
4026 case OP_VOIDCALL_MEMBASE:
4027 case OP_CALL_MEMBASE:
4028 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
4029 /* The trampolines clobber this */
4030 ppc_mr (code, ppc_r29, ins->sreg1);
4031 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4033 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4035 ppc_mtlr (code, ppc_r0);
4037 /* FIXME: this should be handled somewhere else in the new jit */
4038 code = emit_move_return_value (cfg, ins, code);
4041 guint8 * zero_loop_jump, * zero_loop_start;
4042 /* keep alignment */
4043 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4044 int area_offset = alloca_waste;
4046 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
4047 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4048 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
4049 /* use ctr to store the number of words to 0 if needed */
4050 if (ins->flags & MONO_INST_INIT) {
4051 /* we zero 4 bytes at a time:
4052 * we add 7 instead of 3 so that we set the counter to
4053 * at least 1, otherwise the bdnz instruction will make
4054 * it negative and iterate billions of times.
4056 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4057 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4058 ppc_mtctr (code, ppc_r0);
4060 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4061 ppc_neg (code, ppc_r11, ppc_r11);
4062 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4064 /* FIXME: make this loop work in 8 byte
4065 increments on PPC64 */
4066 if (ins->flags & MONO_INST_INIT) {
4067 /* adjust the dest reg by -4 so we can use stwu */
4068 /* we actually adjust -8 because we let the loop
4071 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4072 ppc_li (code, ppc_r11, 0);
4073 zero_loop_start = code;
4074 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4075 zero_loop_jump = code;
4076 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4077 ppc_patch (zero_loop_jump, zero_loop_start);
4079 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4084 ppc_mr (code, ppc_r3, ins->sreg1);
4085 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4086 (gpointer)"mono_arch_throw_exception");
4087 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4088 ppc_load_func (code, ppc_r0, 0);
4089 ppc_mtlr (code, ppc_r0);
4098 ppc_mr (code, ppc_r3, ins->sreg1);
4099 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4100 (gpointer)"mono_arch_rethrow_exception");
4101 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4102 ppc_load_func (code, ppc_r0, 0);
4103 ppc_mtlr (code, ppc_r0);
4110 case OP_START_HANDLER: {
4111 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4112 g_assert (spvar->inst_basereg != ppc_sp);
4113 code = emit_reserve_param_area (cfg, code);
4114 ppc_mflr (code, ppc_r0);
4115 if (ppc_is_imm16 (spvar->inst_offset)) {
4116 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4118 ppc_load (code, ppc_r11, spvar->inst_offset);
4119 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4123 case OP_ENDFILTER: {
4124 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4125 g_assert (spvar->inst_basereg != ppc_sp);
4126 code = emit_unreserve_param_area (cfg, code);
4127 if (ins->sreg1 != ppc_r3)
4128 ppc_mr (code, ppc_r3, ins->sreg1);
4129 if (ppc_is_imm16 (spvar->inst_offset)) {
4130 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4132 ppc_load (code, ppc_r11, spvar->inst_offset);
4133 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4135 ppc_mtlr (code, ppc_r0);
4139 case OP_ENDFINALLY: {
4140 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4141 g_assert (spvar->inst_basereg != ppc_sp);
4142 code = emit_unreserve_param_area (cfg, code);
4143 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4144 ppc_mtlr (code, ppc_r0);
4148 case OP_CALL_HANDLER:
4149 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4153 ins->inst_c0 = code - cfg->native_code;
4156 /*if (ins->inst_target_bb->native_offset) {
4158 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4160 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4165 ppc_mtctr (code, ins->sreg1);
4166 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4170 CASE_PPC64 (OP_LCEQ)
4171 ppc_li (code, ins->dreg, 0);
4172 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4173 ppc_li (code, ins->dreg, 1);
4179 CASE_PPC64 (OP_LCLT)
4180 CASE_PPC64 (OP_LCLT_UN)
4181 ppc_li (code, ins->dreg, 1);
4182 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4183 ppc_li (code, ins->dreg, 0);
4189 CASE_PPC64 (OP_LCGT)
4190 CASE_PPC64 (OP_LCGT_UN)
4191 ppc_li (code, ins->dreg, 1);
4192 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4193 ppc_li (code, ins->dreg, 0);
4195 case OP_COND_EXC_EQ:
4196 case OP_COND_EXC_NE_UN:
4197 case OP_COND_EXC_LT:
4198 case OP_COND_EXC_LT_UN:
4199 case OP_COND_EXC_GT:
4200 case OP_COND_EXC_GT_UN:
4201 case OP_COND_EXC_GE:
4202 case OP_COND_EXC_GE_UN:
4203 case OP_COND_EXC_LE:
4204 case OP_COND_EXC_LE_UN:
4205 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4207 case OP_COND_EXC_IEQ:
4208 case OP_COND_EXC_INE_UN:
4209 case OP_COND_EXC_ILT:
4210 case OP_COND_EXC_ILT_UN:
4211 case OP_COND_EXC_IGT:
4212 case OP_COND_EXC_IGT_UN:
4213 case OP_COND_EXC_IGE:
4214 case OP_COND_EXC_IGE_UN:
4215 case OP_COND_EXC_ILE:
4216 case OP_COND_EXC_ILE_UN:
4217 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4229 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4232 /* floating point opcodes */
4234 g_assert (cfg->compile_aot);
4236 /* FIXME: Optimize this */
4238 ppc_mflr (code, ppc_r11);
4240 *(double*)code = *(double*)ins->inst_p0;
4242 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4245 g_assert_not_reached ();
4247 case OP_STORER8_MEMBASE_REG:
4248 if (ppc_is_imm16 (ins->inst_offset)) {
4249 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4251 if (ppc_is_imm32 (ins->inst_offset)) {
4252 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4253 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4255 ppc_load (code, ppc_r0, ins->inst_offset);
4256 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4260 case OP_LOADR8_MEMBASE:
4261 if (ppc_is_imm16 (ins->inst_offset)) {
4262 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4264 if (ppc_is_imm32 (ins->inst_offset)) {
4265 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4266 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4268 ppc_load (code, ppc_r0, ins->inst_offset);
4269 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4273 case OP_STORER4_MEMBASE_REG:
4274 ppc_frsp (code, ins->sreg1, ins->sreg1);
4275 if (ppc_is_imm16 (ins->inst_offset)) {
4276 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4278 if (ppc_is_imm32 (ins->inst_offset)) {
4279 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4280 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4282 ppc_load (code, ppc_r0, ins->inst_offset);
4283 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4287 case OP_LOADR4_MEMBASE:
4288 if (ppc_is_imm16 (ins->inst_offset)) {
4289 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4291 if (ppc_is_imm32 (ins->inst_offset)) {
4292 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4293 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4295 ppc_load (code, ppc_r0, ins->inst_offset);
4296 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4300 case OP_LOADR4_MEMINDEX:
4301 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4303 case OP_LOADR8_MEMINDEX:
4304 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4306 case OP_STORER4_MEMINDEX:
4307 ppc_frsp (code, ins->sreg1, ins->sreg1);
4308 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4310 case OP_STORER8_MEMINDEX:
4311 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4314 case CEE_CONV_R4: /* FIXME: change precision */
4316 g_assert_not_reached ();
4317 case OP_FCONV_TO_I1:
4318 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4320 case OP_FCONV_TO_U1:
4321 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4323 case OP_FCONV_TO_I2:
4324 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4326 case OP_FCONV_TO_U2:
4327 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4329 case OP_FCONV_TO_I4:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4333 case OP_FCONV_TO_U4:
4335 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4337 case OP_LCONV_TO_R_UN:
4338 g_assert_not_reached ();
4339 /* Implemented as helper calls */
4341 case OP_LCONV_TO_OVF_I4_2:
4342 case OP_LCONV_TO_OVF_I: {
4343 #ifdef __mono_ppc64__
4346 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4347 // Check if its negative
4348 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4349 negative_branch = code;
4350 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4351 // Its positive msword == 0
4352 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4353 msword_positive_branch = code;
4354 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4356 ovf_ex_target = code;
4357 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4359 ppc_patch (negative_branch, code);
4360 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4361 msword_negative_branch = code;
4362 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4363 ppc_patch (msword_negative_branch, ovf_ex_target);
4365 ppc_patch (msword_positive_branch, code);
4366 if (ins->dreg != ins->sreg1)
4367 ppc_mr (code, ins->dreg, ins->sreg1);
4372 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4375 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4378 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4381 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4384 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4387 ppc_fneg (code, ins->dreg, ins->sreg1);
4391 g_assert_not_reached ();
4394 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4397 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4398 ppc_li (code, ins->dreg, 0);
4399 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4400 ppc_li (code, ins->dreg, 1);
4403 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4404 ppc_li (code, ins->dreg, 1);
4405 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4406 ppc_li (code, ins->dreg, 0);
4409 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4410 ppc_li (code, ins->dreg, 1);
4411 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4412 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4413 ppc_li (code, ins->dreg, 0);
4416 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4417 ppc_li (code, ins->dreg, 1);
4418 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4419 ppc_li (code, ins->dreg, 0);
4422 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4423 ppc_li (code, ins->dreg, 1);
4424 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4425 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4426 ppc_li (code, ins->dreg, 0);
4429 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4432 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4435 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4436 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4439 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4440 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4443 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4444 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4447 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4448 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4451 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4452 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4455 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4458 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4459 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4462 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4465 g_assert_not_reached ();
4466 case OP_CHECK_FINITE: {
4467 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4468 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4469 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4470 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4473 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4474 #ifdef __mono_ppc64__
4475 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4477 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4482 #ifdef __mono_ppc64__
4483 case OP_ICONV_TO_I4:
4485 ppc_extsw (code, ins->dreg, ins->sreg1);
4487 case OP_ICONV_TO_U4:
4489 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4491 case OP_ICONV_TO_R4:
4492 case OP_ICONV_TO_R8:
4493 case OP_LCONV_TO_R4:
4494 case OP_LCONV_TO_R8: {
4496 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4497 ppc_extsw (code, ppc_r0, ins->sreg1);
4502 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4503 ppc_mffgpr (code, ins->dreg, tmp);
4505 ppc_str (code, tmp, -8, ppc_r1);
4506 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4508 ppc_fcfid (code, ins->dreg, ins->dreg);
4509 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4510 ppc_frsp (code, ins->dreg, ins->dreg);
4514 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4517 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4520 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4522 ppc_mfspr (code, ppc_r0, ppc_xer);
4523 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4524 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4526 case OP_COND_EXC_OV:
4527 ppc_mfspr (code, ppc_r0, ppc_xer);
4528 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4529 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4541 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4543 case OP_FCONV_TO_I8:
4544 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4546 case OP_FCONV_TO_U8:
4547 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4549 case OP_STOREI4_MEMBASE_REG:
4550 if (ppc_is_imm16 (ins->inst_offset)) {
4551 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4553 ppc_load (code, ppc_r0, ins->inst_offset);
4554 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4557 case OP_STOREI4_MEMINDEX:
4558 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4561 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4563 case OP_ISHR_UN_IMM:
4564 if (ins->inst_imm & 0x1f)
4565 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4567 ppc_mr (code, ins->dreg, ins->sreg1);
4569 case OP_ATOMIC_ADD_NEW_I4:
4570 case OP_ATOMIC_ADD_NEW_I8: {
4571 guint8 *loop = code, *branch;
4572 g_assert (ins->inst_offset == 0);
4573 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4574 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4576 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4577 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4578 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4579 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4581 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4583 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4584 ppc_patch (branch, loop);
4585 ppc_mr (code, ins->dreg, ppc_r0);
4589 case OP_ICONV_TO_R4:
4590 case OP_ICONV_TO_R8: {
4591 if (cpu_hw_caps & PPC_ISA_64) {
4592 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4593 ppc_stw (code, ppc_r0, -8, ppc_r1);
4594 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4595 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4596 ppc_fcfid (code, ins->dreg, ins->dreg);
4597 if (ins->opcode == OP_ICONV_TO_R4)
4598 ppc_frsp (code, ins->dreg, ins->dreg);
4603 case OP_ATOMIC_CAS_I4:
4604 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4605 int location = ins->sreg1;
4606 int value = ins->sreg2;
4607 int comparand = ins->sreg3;
4608 guint8 *start, *not_equal, *lost_reservation;
4611 if (ins->opcode == OP_ATOMIC_CAS_I4)
4612 ppc_lwarx (code, ppc_r0, 0, location);
4613 #ifdef __mono_ppc64__
4615 ppc_ldarx (code, ppc_r0, 0, location);
4617 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4620 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4621 if (ins->opcode == OP_ATOMIC_CAS_I4)
4622 ppc_stwcxd (code, value, 0, location);
4623 #ifdef __mono_ppc64__
4625 ppc_stdcxd (code, value, 0, location);
4628 lost_reservation = code;
4629 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4630 ppc_patch (lost_reservation, start);
4632 ppc_patch (not_equal, code);
4633 ppc_mr (code, ins->dreg, ppc_r0);
4638 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4639 g_assert_not_reached ();
4642 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4643 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4644 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4645 g_assert_not_reached ();
4651 last_offset = offset;
4654 cfg->code_len = code - cfg->native_code;
4658 mono_arch_register_lowlevel_calls (void)
4660 /* The signature doesn't matter */
4661 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4664 #ifdef __mono_ppc64__
4665 #define patch_load_sequence(ip,val) do {\
4666 guint16 *__load = (guint16*)(ip); \
4667 g_assert (sizeof (val) == sizeof (gsize)); \
4668 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4669 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4670 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4671 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4674 #define patch_load_sequence(ip,val) do {\
4675 guint16 *__lis_ori = (guint16*)(ip); \
4676 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4677 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4682 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4684 MonoJumpInfo *patch_info;
4685 gboolean compile_aot = !run_cctors;
4687 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4688 unsigned char *ip = patch_info->ip.i + code;
4689 unsigned char *target;
4690 gboolean is_fd = FALSE;
4692 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4695 switch (patch_info->type) {
4696 case MONO_PATCH_INFO_BB:
4697 case MONO_PATCH_INFO_LABEL:
4700 /* No need to patch these */
4705 switch (patch_info->type) {
4706 case MONO_PATCH_INFO_IP:
4707 patch_load_sequence (ip, ip);
4709 case MONO_PATCH_INFO_METHOD_REL:
4710 g_assert_not_reached ();
4711 *((gpointer *)(ip)) = code + patch_info->data.offset;
4713 case MONO_PATCH_INFO_SWITCH: {
4714 gpointer *table = (gpointer *)patch_info->data.table->table;
4717 patch_load_sequence (ip, table);
4719 for (i = 0; i < patch_info->data.table->table_size; i++) {
4720 table [i] = (glong)patch_info->data.table->table [i] + code;
4722 /* we put into the table the absolute address, no need for ppc_patch in this case */
4725 case MONO_PATCH_INFO_METHODCONST:
4726 case MONO_PATCH_INFO_CLASS:
4727 case MONO_PATCH_INFO_IMAGE:
4728 case MONO_PATCH_INFO_FIELD:
4729 case MONO_PATCH_INFO_VTABLE:
4730 case MONO_PATCH_INFO_IID:
4731 case MONO_PATCH_INFO_SFLDA:
4732 case MONO_PATCH_INFO_LDSTR:
4733 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4734 case MONO_PATCH_INFO_LDTOKEN:
4735 /* from OP_AOTCONST : lis + ori */
4736 patch_load_sequence (ip, target);
4738 case MONO_PATCH_INFO_R4:
4739 case MONO_PATCH_INFO_R8:
4740 g_assert_not_reached ();
4741 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4743 case MONO_PATCH_INFO_EXC_NAME:
4744 g_assert_not_reached ();
4745 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4747 case MONO_PATCH_INFO_NONE:
4748 case MONO_PATCH_INFO_BB_OVF:
4749 case MONO_PATCH_INFO_EXC_OVF:
4750 /* everything is dealt with at epilog output time */
4752 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4753 case MONO_PATCH_INFO_INTERNAL_METHOD:
4754 case MONO_PATCH_INFO_ABS:
4755 case MONO_PATCH_INFO_CLASS_INIT:
4756 case MONO_PATCH_INFO_RGCTX_FETCH:
4763 ppc_patch_full (ip, target, is_fd);
4768 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4769 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4770 * the instruction offset immediate for all the registers.
4773 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4777 for (i = 13; i <= 31; i++) {
4778 if (used_int_regs & (1 << i)) {
4779 ppc_str (code, i, pos, base_reg);
4780 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4781 pos += sizeof (mgreg_t);
4785 /* pos is the start of the MonoLMF structure */
4786 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4787 for (i = 13; i <= 31; i++) {
4788 ppc_str (code, i, offset, base_reg);
4789 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4790 offset += sizeof (mgreg_t);
4792 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4793 for (i = 14; i < 32; i++) {
4794 ppc_stfd (code, i, offset, base_reg);
4795 offset += sizeof (gdouble);
4802 * Stack frame layout:
4804 * ------------------- sp
4805 * MonoLMF structure or saved registers
4806 * -------------------
4808 * -------------------
4810 * -------------------
4811 * optional 8 bytes for tracing
4812 * -------------------
4813 * param area size is cfg->param_area
4814 * -------------------
4815 * linkage area size is PPC_STACK_PARAM_OFFSET
4816 * ------------------- sp
4820 mono_arch_emit_prolog (MonoCompile *cfg)
4822 MonoMethod *method = cfg->method;
4824 MonoMethodSignature *sig;
4826 long alloc_size, pos, max_offset, cfa_offset;
4832 int tailcall_struct_index;
4834 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4837 sig = mono_method_signature (method);
4838 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4839 code = cfg->native_code = g_malloc (cfg->code_size);
4843 /* We currently emit unwind info for aot, but don't use it */
4844 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4846 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4847 ppc_mflr (code, ppc_r0);
4848 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4849 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4852 alloc_size = cfg->stack_offset;
4855 if (!method->save_lmf) {
4856 for (i = 31; i >= 13; --i) {
4857 if (cfg->used_int_regs & (1 << i)) {
4858 pos += sizeof (mgreg_t);
4862 pos += sizeof (MonoLMF);
4866 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4867 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4868 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4869 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4872 cfg->stack_usage = alloc_size;
4873 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4875 if (ppc_is_imm16 (-alloc_size)) {
4876 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4877 cfa_offset = alloc_size;
4878 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4879 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4882 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4883 ppc_load (code, ppc_r0, -alloc_size);
4884 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4885 cfa_offset = alloc_size;
4886 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4887 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4890 if (cfg->frame_reg != ppc_sp) {
4891 ppc_mr (code, cfg->frame_reg, ppc_sp);
4892 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4895 /* store runtime generic context */
4896 if (cfg->rgctx_var) {
4897 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4898 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4900 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4903 /* compute max_offset in order to use short forward jumps
4904 * we always do it on ppc because the immediate displacement
4905 * for jumps is too small
4908 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4910 bb->max_offset = max_offset;
4912 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4915 MONO_BB_FOR_EACH_INS (bb, ins)
4916 max_offset += ins_native_length (cfg, ins);
4919 /* load arguments allocated to register from the stack */
4922 cinfo = calculate_sizes (sig, sig->pinvoke);
4924 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4925 ArgInfo *ainfo = &cinfo->ret;
4927 inst = cfg->vret_addr;
4930 if (ppc_is_imm16 (inst->inst_offset)) {
4931 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4933 ppc_load (code, ppc_r11, inst->inst_offset);
4934 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4938 tailcall_struct_index = 0;
4939 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4940 ArgInfo *ainfo = cinfo->args + i;
4941 inst = cfg->args [pos];
4943 if (cfg->verbose_level > 2)
4944 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4945 if (inst->opcode == OP_REGVAR) {
4946 if (ainfo->regtype == RegTypeGeneral)
4947 ppc_mr (code, inst->dreg, ainfo->reg);
4948 else if (ainfo->regtype == RegTypeFP)
4949 ppc_fmr (code, inst->dreg, ainfo->reg);
4950 else if (ainfo->regtype == RegTypeBase) {
4951 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4952 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4954 g_assert_not_reached ();
4956 if (cfg->verbose_level > 2)
4957 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4959 /* the argument should be put on the stack: FIXME handle size != word */
4960 if (ainfo->regtype == RegTypeGeneral) {
4961 switch (ainfo->size) {
4963 if (ppc_is_imm16 (inst->inst_offset)) {
4964 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4966 if (ppc_is_imm32 (inst->inst_offset)) {
4967 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4968 ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
4970 ppc_load (code, ppc_r11, inst->inst_offset);
4971 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4976 if (ppc_is_imm16 (inst->inst_offset)) {
4977 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4979 if (ppc_is_imm32 (inst->inst_offset)) {
4980 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4981 ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
4983 ppc_load (code, ppc_r11, inst->inst_offset);
4984 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4988 #ifdef __mono_ppc64__
4990 if (ppc_is_imm16 (inst->inst_offset)) {
4991 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4993 if (ppc_is_imm32 (inst->inst_offset)) {
4994 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4995 ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
4997 ppc_load (code, ppc_r11, inst->inst_offset);
4998 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5003 if (ppc_is_imm16 (inst->inst_offset)) {
5004 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5006 ppc_load (code, ppc_r11, inst->inst_offset);
5007 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
5012 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5013 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5014 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5016 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5017 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5018 ppc_stw (code, ainfo->reg, 0, ppc_r11);
5019 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
5024 if (ppc_is_imm16 (inst->inst_offset)) {
5025 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5027 if (ppc_is_imm32 (inst->inst_offset)) {
5028 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5029 ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
5031 ppc_load (code, ppc_r11, inst->inst_offset);
5032 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5037 } else if (ainfo->regtype == RegTypeBase) {
5038 g_assert (ppc_is_imm16 (ainfo->offset));
5039 /* load the previous stack pointer in r11 */
5040 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5041 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
5042 switch (ainfo->size) {
5044 if (ppc_is_imm16 (inst->inst_offset)) {
5045 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5047 if (ppc_is_imm32 (inst->inst_offset)) {
5048 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5049 ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
5051 ppc_load (code, ppc_r11, inst->inst_offset);
5052 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5057 if (ppc_is_imm16 (inst->inst_offset)) {
5058 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5060 if (ppc_is_imm32 (inst->inst_offset)) {
5061 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5062 ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
5064 ppc_load (code, ppc_r11, inst->inst_offset);
5065 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5069 #ifdef __mono_ppc64__
5071 if (ppc_is_imm16 (inst->inst_offset)) {
5072 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5074 if (ppc_is_imm32 (inst->inst_offset)) {
5075 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5076 ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
5078 ppc_load (code, ppc_r11, inst->inst_offset);
5079 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5084 if (ppc_is_imm16 (inst->inst_offset)) {
5085 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5087 ppc_load (code, ppc_r11, inst->inst_offset);
5088 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
5093 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5094 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5095 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5096 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5097 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5099 /* use r12 to load the 2nd half of the long before we clobber r11. */
5100 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5101 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5102 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5103 ppc_stw (code, ppc_r0, 0, ppc_r11);
5104 ppc_stw (code, ppc_r12, 4, ppc_r11);
5109 if (ppc_is_imm16 (inst->inst_offset)) {
5110 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5112 if (ppc_is_imm32 (inst->inst_offset)) {
5113 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5114 ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
5116 ppc_load (code, ppc_r11, inst->inst_offset);
5117 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5122 } else if (ainfo->regtype == RegTypeFP) {
5123 g_assert (ppc_is_imm16 (inst->inst_offset));
5124 if (ainfo->size == 8)
5125 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5126 else if (ainfo->size == 4)
5127 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5129 g_assert_not_reached ();
5130 } else if (ainfo->regtype == RegTypeStructByVal) {
5131 int doffset = inst->inst_offset;
5135 g_assert (ppc_is_imm16 (inst->inst_offset));
5136 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5137 /* FIXME: what if there is no class? */
5138 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5139 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5140 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5143 * Darwin handles 1 and 2 byte
5144 * structs specially by
5145 * loading h/b into the arg
5146 * register. Only done for
5150 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5152 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5156 #ifdef __mono_ppc64__
5158 g_assert (cur_reg == 0);
5159 ppc_sldi (code, ppc_r0, ainfo->reg,
5160 (sizeof (gpointer) - ainfo->bytes) * 8);
5161 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5165 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5166 inst->inst_basereg);
5169 soffset += sizeof (gpointer);
5170 doffset += sizeof (gpointer);
5172 if (ainfo->vtsize) {
5173 /* FIXME: we need to do the shifting here, too */
5176 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5177 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5178 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5179 code = emit_memcpy (code, size - soffset,
5180 inst->inst_basereg, doffset,
5181 ppc_r11, ainfo->offset + soffset);
5183 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5184 inst->inst_basereg, doffset,
5185 ppc_r11, ainfo->offset + soffset);
5188 } else if (ainfo->regtype == RegTypeStructByAddr) {
5189 /* if it was originally a RegTypeBase */
5190 if (ainfo->offset) {
5191 /* load the previous stack pointer in r11 */
5192 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5193 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5195 ppc_mr (code, ppc_r11, ainfo->reg);
5198 if (cfg->tailcall_valuetype_addrs) {
5199 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5201 g_assert (ppc_is_imm16 (addr->inst_offset));
5202 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5204 tailcall_struct_index++;
5207 g_assert (ppc_is_imm16 (inst->inst_offset));
5208 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5209 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5211 g_assert_not_reached ();
5216 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5217 if (cfg->compile_aot)
5218 /* AOT code is only used in the root domain */
5219 ppc_load_ptr (code, ppc_r3, 0);
5221 ppc_load_ptr (code, ppc_r3, cfg->domain);
5222 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5223 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5224 ppc_load_func (code, ppc_r0, 0);
5225 ppc_mtlr (code, ppc_r0);
5232 if (method->save_lmf) {
5233 if (lmf_pthread_key != -1) {
5234 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5235 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5236 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5238 if (cfg->compile_aot) {
5239 /* Compute the got address which is needed by the PLT entry */
5240 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5242 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5243 (gpointer)"mono_get_lmf_addr");
5244 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5245 ppc_load_func (code, ppc_r0, 0);
5246 ppc_mtlr (code, ppc_r0);
5252 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5253 /* lmf_offset is the offset from the previous stack pointer,
5254 * alloc_size is the total stack space allocated, so the offset
5255 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5256 * The pointer to the struct is put in ppc_r11 (new_lmf).
5257 * The callee-saved registers are already in the MonoLMF structure
5259 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5260 /* ppc_r3 is the result from mono_get_lmf_addr () */
5261 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5262 /* new_lmf->previous_lmf = *lmf_addr */
5263 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5264 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5265 /* *(lmf_addr) = r11 */
5266 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5267 /* save method info */
5268 if (cfg->compile_aot)
5270 ppc_load (code, ppc_r0, 0);
5272 ppc_load_ptr (code, ppc_r0, method);
5273 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5274 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5275 /* save the current IP */
5276 if (cfg->compile_aot) {
5278 ppc_mflr (code, ppc_r0);
5280 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5281 #ifdef __mono_ppc64__
5282 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5284 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5287 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5291 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5293 cfg->code_len = code - cfg->native_code;
5294 g_assert (cfg->code_len <= cfg->code_size);
5301 mono_arch_emit_epilog (MonoCompile *cfg)
5303 MonoMethod *method = cfg->method;
5305 int max_epilog_size = 16 + 20*4;
5308 if (cfg->method->save_lmf)
5309 max_epilog_size += 128;
5311 if (mono_jit_trace_calls != NULL)
5312 max_epilog_size += 50;
5314 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5315 max_epilog_size += 50;
5317 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5318 cfg->code_size *= 2;
5319 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5320 mono_jit_stats.code_reallocs++;
5324 * Keep in sync with OP_JMP
5326 code = cfg->native_code + cfg->code_len;
5328 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5329 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5333 if (method->save_lmf) {
5335 pos += sizeof (MonoLMF);
5337 /* save the frame reg in r8 */
5338 ppc_mr (code, ppc_r8, cfg->frame_reg);
5339 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5340 /* r5 = previous_lmf */
5341 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5343 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5344 /* *(lmf_addr) = previous_lmf */
5345 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5346 /* FIXME: speedup: there is no actual need to restore the registers if
5347 * we didn't actually change them (idea from Zoltan).
5350 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5352 /*for (i = 14; i < 32; i++) {
5353 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5355 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5356 /* use the saved copy of the frame reg in r8 */
5357 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5358 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5359 ppc_mtlr (code, ppc_r0);
5361 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5363 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5364 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5365 if (ppc_is_imm16 (return_offset)) {
5366 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5368 ppc_load (code, ppc_r11, return_offset);
5369 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5371 ppc_mtlr (code, ppc_r0);
5373 if (ppc_is_imm16 (cfg->stack_usage)) {
5374 int offset = cfg->stack_usage;
5375 for (i = 13; i <= 31; i++) {
5376 if (cfg->used_int_regs & (1 << i))
5377 offset -= sizeof (mgreg_t);
5379 if (cfg->frame_reg != ppc_sp)
5380 ppc_mr (code, ppc_r11, cfg->frame_reg);
5381 /* note r31 (possibly the frame register) is restored last */
5382 for (i = 13; i <= 31; i++) {
5383 if (cfg->used_int_regs & (1 << i)) {
5384 ppc_ldr (code, i, offset, cfg->frame_reg);
5385 offset += sizeof (mgreg_t);
5388 if (cfg->frame_reg != ppc_sp)
5389 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5391 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5393 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5394 if (cfg->used_int_regs) {
5395 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5396 for (i = 31; i >= 13; --i) {
5397 if (cfg->used_int_regs & (1 << i)) {
5398 pos += sizeof (mgreg_t);
5399 ppc_ldr (code, i, -pos, ppc_r11);
5402 ppc_mr (code, ppc_sp, ppc_r11);
5404 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5411 cfg->code_len = code - cfg->native_code;
5413 g_assert (cfg->code_len < cfg->code_size);
5417 /* remove once throw_exception_by_name is eliminated */
5419 exception_id_by_name (const char *name)
5421 if (strcmp (name, "IndexOutOfRangeException") == 0)
5422 return MONO_EXC_INDEX_OUT_OF_RANGE;
5423 if (strcmp (name, "OverflowException") == 0)
5424 return MONO_EXC_OVERFLOW;
5425 if (strcmp (name, "ArithmeticException") == 0)
5426 return MONO_EXC_ARITHMETIC;
5427 if (strcmp (name, "DivideByZeroException") == 0)
5428 return MONO_EXC_DIVIDE_BY_ZERO;
5429 if (strcmp (name, "InvalidCastException") == 0)
5430 return MONO_EXC_INVALID_CAST;
5431 if (strcmp (name, "NullReferenceException") == 0)
5432 return MONO_EXC_NULL_REF;
5433 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5434 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5435 g_error ("Unknown intrinsic exception %s\n", name);
5440 mono_arch_emit_exceptions (MonoCompile *cfg)
5442 MonoJumpInfo *patch_info;
5445 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5446 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5447 int max_epilog_size = 50;
5449 /* count the number of exception infos */
5452 * make sure we have enough space for exceptions
5454 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5455 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5456 i = exception_id_by_name (patch_info->data.target);
5457 if (!exc_throw_found [i]) {
5458 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5459 exc_throw_found [i] = TRUE;
5461 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5462 max_epilog_size += 12;
5463 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5464 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5465 i = exception_id_by_name (ovfj->data.exception);
5466 if (!exc_throw_found [i]) {
5467 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5468 exc_throw_found [i] = TRUE;
5470 max_epilog_size += 8;
5474 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5475 cfg->code_size *= 2;
5476 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5477 mono_jit_stats.code_reallocs++;
5480 code = cfg->native_code + cfg->code_len;
5482 /* add code to raise exceptions */
5483 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5484 switch (patch_info->type) {
5485 case MONO_PATCH_INFO_BB_OVF: {
5486 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5487 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5488 /* patch the initial jump */
5489 ppc_patch (ip, code);
5490 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5492 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5493 /* jump back to the true target */
5495 ip = ovfj->data.bb->native_offset + cfg->native_code;
5496 ppc_patch (code - 4, ip);
5497 patch_info->type = MONO_PATCH_INFO_NONE;
5500 case MONO_PATCH_INFO_EXC_OVF: {
5501 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5502 MonoJumpInfo *newji;
5503 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5504 unsigned char *bcl = code;
5505 /* patch the initial jump: we arrived here with a call */
5506 ppc_patch (ip, code);
5507 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5509 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5510 /* patch the conditional jump to the right handler */
5511 /* make it processed next */
5512 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5513 newji->type = MONO_PATCH_INFO_EXC;
5514 newji->ip.i = bcl - cfg->native_code;
5515 newji->data.target = ovfj->data.exception;
5516 newji->next = patch_info->next;
5517 patch_info->next = newji;
5518 patch_info->type = MONO_PATCH_INFO_NONE;
5521 case MONO_PATCH_INFO_EXC: {
5522 MonoClass *exc_class;
5524 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5525 i = exception_id_by_name (patch_info->data.target);
5526 if (exc_throw_pos [i]) {
5527 ppc_patch (ip, exc_throw_pos [i]);
5528 patch_info->type = MONO_PATCH_INFO_NONE;
5531 exc_throw_pos [i] = code;
5534 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5535 g_assert (exc_class);
5537 ppc_patch (ip, code);
5538 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5539 ppc_load (code, ppc_r3, exc_class->type_token);
5540 /* we got here from a conditional call, so the calling ip is set in lr */
5541 ppc_mflr (code, ppc_r4);
5542 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5543 patch_info->data.name = "mono_arch_throw_corlib_exception";
5544 patch_info->ip.i = code - cfg->native_code;
5545 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5546 ppc_load_func (code, ppc_r0, 0);
5547 ppc_mtctr (code, ppc_r0);
5548 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5560 cfg->code_len = code - cfg->native_code;
5562 g_assert (cfg->code_len <= cfg->code_size);
5567 try_offset_access (void *value, guint32 idx)
5569 register void* me __asm__ ("r2");
5570 void ***p = (void***)((char*)me + 284);
5571 int idx1 = idx / 32;
5572 int idx2 = idx % 32;
5575 if (value != p[idx1][idx2])
5582 setup_tls_access (void)
5586 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5587 size_t conf_size = 0;
5590 /* FIXME for darwin */
5591 guint32 *ins, *code;
5592 guint32 cmplwi_1023, li_0x48, blr_ins;
5596 tls_mode = TLS_MODE_FAILED;
5599 if (tls_mode == TLS_MODE_FAILED)
5601 if (g_getenv ("MONO_NO_TLS")) {
5602 tls_mode = TLS_MODE_FAILED;
5606 if (tls_mode == TLS_MODE_DETECT) {
5607 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5608 tls_mode = TLS_MODE_DARWIN_G4;
5609 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5610 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5611 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5612 tls_mode = TLS_MODE_NPTL;
5613 #elif !defined(TARGET_PS3)
5614 ins = (guint32*)pthread_getspecific;
5615 /* uncond branch to the real method */
5616 if ((*ins >> 26) == 18) {
5618 val = (*ins & ~3) << 6;
5622 ins = (guint32*)(long)val;
5624 ins = (guint32*) ((char*)ins + val);
5627 code = &cmplwi_1023;
5628 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5630 ppc_li (code, ppc_r4, 0x48);
5633 if (*ins == cmplwi_1023) {
5634 int found_lwz_284 = 0;
5635 for (ptk = 0; ptk < 20; ++ptk) {
5637 if (!*ins || *ins == blr_ins)
5639 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5644 if (!found_lwz_284) {
5645 tls_mode = TLS_MODE_FAILED;
5648 tls_mode = TLS_MODE_LTHREADS;
5649 } else if (*ins == li_0x48) {
5651 /* uncond branch to the real method */
5652 if ((*ins >> 26) == 18) {
5654 val = (*ins & ~3) << 6;
5658 ins = (guint32*)(long)val;
5660 ins = (guint32*) ((char*)ins + val);
5662 code = (guint32*)&val;
5663 ppc_li (code, ppc_r0, 0x7FF2);
5664 if (ins [1] == val) {
5665 /* Darwin on G4, implement */
5666 tls_mode = TLS_MODE_FAILED;
5669 code = (guint32*)&val;
5670 ppc_mfspr (code, ppc_r3, 104);
5671 if (ins [1] != val) {
5672 tls_mode = TLS_MODE_FAILED;
5675 tls_mode = TLS_MODE_DARWIN_G5;
5678 tls_mode = TLS_MODE_FAILED;
5682 tls_mode = TLS_MODE_FAILED;
5688 if (tls_mode == TLS_MODE_DETECT)
5689 tls_mode = TLS_MODE_FAILED;
5690 if (tls_mode == TLS_MODE_FAILED)
5692 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5693 monodomain_key = mono_domain_get_tls_offset();
5695 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5696 mono_domain_get_tls_offset returning -1) then use keyed access. */
5697 if (monodomain_key == -1) {
5698 ptk = mono_domain_get_tls_key ();
5700 ptk = mono_pthread_key_for_tls (ptk);
5702 monodomain_key = ptk;
5707 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5708 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5710 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5711 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5712 if (lmf_pthread_key == -1) {
5713 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5715 /*g_print ("MonoLMF at: %d\n", ptk);*/
5716 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5717 init_tls_failed = 1;
5720 lmf_pthread_key = ptk;
5727 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5729 setup_tls_access ();
5733 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5737 #ifdef MONO_ARCH_HAVE_IMT
5739 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5741 #define LOADSTORE_SIZE 4
5742 #define JUMP_IMM_SIZE 12
5743 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5744 #define ENABLE_WRONG_METHOD_CHECK 0
5747 * LOCKING: called with the domain lock held
5750 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5751 gpointer fail_tramp)
5755 guint8 *code, *start;
5757 for (i = 0; i < count; ++i) {
5758 MonoIMTCheckItem *item = imt_entries [i];
5759 if (item->is_equals) {
5760 if (item->check_target_idx) {
5761 if (!item->compare_done)
5762 item->chunk_size += CMP_SIZE;
5763 if (item->has_target_code)
5764 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5766 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5769 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5770 if (!item->has_target_code)
5771 item->chunk_size += LOADSTORE_SIZE;
5773 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5774 #if ENABLE_WRONG_METHOD_CHECK
5775 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5780 item->chunk_size += CMP_SIZE + BR_SIZE;
5781 imt_entries [item->check_target_idx]->compare_done = TRUE;
5783 size += item->chunk_size;
5786 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5788 /* the initial load of the vtable address */
5789 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5790 code = mono_domain_code_reserve (domain, size);
5795 * We need to save and restore r11 because it might be
5796 * used by the caller as the vtable register, so
5797 * clobbering it will trip up the magic trampoline.
5799 * FIXME: Get rid of this by making sure that r11 is
5800 * not used as the vtable register in interface calls.
5802 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5803 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5805 for (i = 0; i < count; ++i) {
5806 MonoIMTCheckItem *item = imt_entries [i];
5807 item->code_target = code;
5808 if (item->is_equals) {
5809 if (item->check_target_idx) {
5810 if (!item->compare_done) {
5811 ppc_load (code, ppc_r0, (gsize)item->key);
5812 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5814 item->jmp_code = code;
5815 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5816 if (item->has_target_code) {
5817 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5819 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5820 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5822 ppc_mtctr (code, ppc_r0);
5823 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5826 ppc_load (code, ppc_r0, (gulong)item->key);
5827 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5828 item->jmp_code = code;
5829 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5830 if (item->has_target_code) {
5831 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5834 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5835 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5837 ppc_mtctr (code, ppc_r0);
5838 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5839 ppc_patch (item->jmp_code, code);
5840 ppc_load_ptr (code, ppc_r0, fail_tramp);
5841 ppc_mtctr (code, ppc_r0);
5842 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5843 item->jmp_code = NULL;
5845 /* enable the commented code to assert on wrong method */
5846 #if ENABLE_WRONG_METHOD_CHECK
5847 ppc_load (code, ppc_r0, (guint32)item->key);
5848 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5849 item->jmp_code = code;
5850 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5852 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5853 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5854 ppc_mtctr (code, ppc_r0);
5855 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5856 #if ENABLE_WRONG_METHOD_CHECK
5857 ppc_patch (item->jmp_code, code);
5859 item->jmp_code = NULL;
5864 ppc_load (code, ppc_r0, (gulong)item->key);
5865 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5866 item->jmp_code = code;
5867 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5870 /* patch the branches to get to the target items */
5871 for (i = 0; i < count; ++i) {
5872 MonoIMTCheckItem *item = imt_entries [i];
5873 if (item->jmp_code) {
5874 if (item->check_target_idx) {
5875 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5881 mono_stats.imt_thunks_size += code - start;
5882 g_assert (code - start <= size);
5883 mono_arch_flush_icache (start, size);
5888 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5890 mgreg_t *r = (mgreg_t*)regs;
5892 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5897 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5899 mgreg_t *r = (mgreg_t*)regs;
5901 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5905 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5912 mono_arch_print_tree (MonoInst *tree, int arity)
5917 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5921 setup_tls_access ();
5922 if (monodomain_key == -1)
5925 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5926 ins->inst_offset = monodomain_key;
5931 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5934 return MONO_CONTEXT_GET_SP (ctx);
5936 g_assert (reg >= ppc_r13);
5938 return (gpointer)(gsize)ctx->regs [reg - ppc_r13];
5942 mono_arch_get_patch_offset (guint8 *code)
5948 * mono_aot_emit_load_got_addr:
5950 * Emit code to load the got address.
5951 * On PPC, the result is placed into r30.
5954 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5957 ppc_mflr (code, ppc_r30);
5959 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5961 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5962 /* arch_emit_got_address () patches this */
5963 #if defined(TARGET_POWERPC64)
5969 ppc_load32 (code, ppc_r0, 0);
5970 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5977 * mono_ppc_emit_load_aotconst:
5979 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5980 * TARGET from the mscorlib GOT in full-aot code.
5981 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5985 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5987 /* Load the mscorlib got address */
5988 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5989 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5990 /* arch_emit_got_access () patches this */
5991 ppc_load32 (code, ppc_r0, 0);
5992 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5997 /* Soft Debug support */
5998 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6005 * mono_arch_set_breakpoint:
6007 * See mini-amd64.c for docs.
6010 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6013 guint8 *orig_code = code;
6015 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
6016 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
6018 g_assert (code - orig_code == BREAKPOINT_SIZE);
6020 mono_arch_flush_icache (orig_code, code - orig_code);
6024 * mono_arch_clear_breakpoint:
6026 * See mini-amd64.c for docs.
6029 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6034 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6037 mono_arch_flush_icache (ip, code - ip);
6041 * mono_arch_is_breakpoint_event:
6043 * See mini-amd64.c for docs.
6046 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6048 siginfo_t* sinfo = (siginfo_t*) info;
6049 /* Sometimes the address is off by 4 */
6050 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6057 * mono_arch_get_ip_for_breakpoint:
6059 * See mini-amd64.c for docs.
6062 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6064 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6066 /* ip points at the ldptr instruction */
6067 ip -= PPC_LOAD_SEQUENCE_LENGTH;
6073 * mono_arch_skip_breakpoint:
6075 * See mini-amd64.c for docs.
6078 mono_arch_skip_breakpoint (MonoContext *ctx)
6080 /* skip the ldptr */
6081 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6089 * mono_arch_start_single_stepping:
6091 * See mini-amd64.c for docs.
6094 mono_arch_start_single_stepping (void)
6096 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6100 * mono_arch_stop_single_stepping:
6102 * See mini-amd64.c for docs.
6105 mono_arch_stop_single_stepping (void)
6107 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6111 * mono_arch_is_single_step_event:
6113 * See mini-amd64.c for docs.
6116 mono_arch_is_single_step_event (void *info, void *sigctx)
6118 siginfo_t* sinfo = (siginfo_t*) info;
6119 /* Sometimes the address is off by 4 */
6120 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6127 * mono_arch_get_ip_for_single_step:
6129 * See mini-amd64.c for docs.
6132 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6134 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6136 /* ip points after the ldptr instruction */
6141 * mono_arch_skip_single_step:
6143 * See mini-amd64.c for docs.
6146 mono_arch_skip_single_step (MonoContext *ctx)
6148 /* skip the ldptr */
6149 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6153 * mono_arch_create_seq_point_info:
6155 * See mini-amd64.c for docs.
6158 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)