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:
757 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
762 for (i = 0; i < cfg->num_varinfo; i++) {
763 MonoInst *ins = cfg->varinfo [i];
764 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
767 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
770 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
773 /* we can only allocate 32 bit values */
774 if (is_regsize_var (ins->inst_vtype)) {
775 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
776 g_assert (i == vmv->idx);
777 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
783 #endif /* ifndef DISABLE_JIT */
786 mono_arch_get_global_int_regs (MonoCompile *cfg)
790 if (cfg->frame_reg != ppc_sp)
792 /* ppc_r13 is used by the system on PPC EABI */
793 for (i = 14; i < top; ++i) {
795 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
796 * since the trampolines can clobber r11.
798 if (!(cfg->compile_aot && i == 29))
799 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
806 * mono_arch_regalloc_cost:
808 * Return the cost, in number of memory references, of the action of
809 * allocating the variable VMV into a register during global register
813 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
820 mono_arch_flush_icache (guint8 *code, gint size)
822 #ifdef MONO_CROSS_COMPILE
825 guint8 *endp, *start;
829 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
830 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
831 #if defined(G_COMPILER_CODEWARRIOR)
832 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
833 for (p = start; p < endp; p += cachelineinc) {
837 for (p = start; p < endp; p += cachelineinc) {
843 for (p = start; p < endp; p += cachelineinc) {
854 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
855 * The sync is required to insure that the store queue is completely empty.
856 * While the icbi performs no cache operations, icbi/isync is required to
857 * kill local prefetch.
859 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
861 asm ("icbi 0,%0;" : : "r"(code) : "memory");
865 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
866 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
867 for (p = start; p < endp; p += cachelineinc) {
868 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
871 for (p = start; p < endp; p += cachelineinc) {
872 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
877 for (p = start; p < endp; p += cachelineinc) {
878 /* for ISA2.0+ implementations we should not need any extra sync between the
879 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
880 * So I am not sure which chip had this problem but its not an issue on
881 * of the ISA V2 chips.
883 if (cpu_hw_caps & PPC_ISA_2X)
884 asm ("icbi 0,%0;" : : "r"(p) : "memory");
886 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
888 if (!(cpu_hw_caps & PPC_ISA_2X))
896 mono_arch_flush_register_windows (void)
901 #define ALWAYS_ON_STACK(s) s
902 #define FP_ALSO_IN_REG(s) s
904 #ifdef __mono_ppc64__
905 #define ALWAYS_ON_STACK(s) s
906 #define FP_ALSO_IN_REG(s) s
908 #define ALWAYS_ON_STACK(s)
909 #define FP_ALSO_IN_REG(s)
911 #define ALIGN_DOUBLES
924 guint32 vtsize; /* in param area */
926 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
927 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
928 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
929 guint8 bytes : 4; /* size in bytes - only valid for
930 RegTypeStructByVal if the struct fits
931 in one word, otherwise it's 0*/
946 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
948 #ifdef __mono_ppc64__
953 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
954 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
955 ainfo->reg = ppc_sp; /* in the caller */
956 ainfo->regtype = RegTypeBase;
957 *stack_size += sizeof (gpointer);
959 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
963 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
965 //*stack_size += (*stack_size % 8);
967 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
968 ainfo->reg = ppc_sp; /* in the caller */
969 ainfo->regtype = RegTypeBase;
976 ALWAYS_ON_STACK (*stack_size += 8);
984 #if defined(__APPLE__) || defined(__mono_ppc64__)
986 has_only_a_r48_field (MonoClass *klass)
990 gboolean have_field = FALSE;
992 while ((f = mono_class_get_fields (klass, &iter))) {
993 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
996 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1007 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
1010 int n = sig->hasthis + sig->param_count;
1011 MonoType *simpletype;
1012 guint32 stack_size = 0;
1013 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1015 fr = PPC_FIRST_FPARG_REG;
1016 gr = PPC_FIRST_ARG_REG;
1018 /* FIXME: handle returning a struct */
1019 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1020 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1021 cinfo->struct_ret = PPC_FIRST_ARG_REG;
1026 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1029 DEBUG(printf("params: %d\n", sig->param_count));
1030 for (i = 0; i < sig->param_count; ++i) {
1031 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1032 /* Prevent implicit arguments and sig_cookie from
1033 being passed in registers */
1034 gr = PPC_LAST_ARG_REG + 1;
1035 /* FIXME: don't we have to set fr, too? */
1036 /* Emit the signature cookie just before the implicit arguments */
1037 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1039 DEBUG(printf("param %d: ", i));
1040 if (sig->params [i]->byref) {
1041 DEBUG(printf("byref\n"));
1042 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1046 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1047 switch (simpletype->type) {
1048 case MONO_TYPE_BOOLEAN:
1051 cinfo->args [n].size = 1;
1052 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1055 case MONO_TYPE_CHAR:
1058 cinfo->args [n].size = 2;
1059 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1064 cinfo->args [n].size = 4;
1065 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1071 case MONO_TYPE_FNPTR:
1072 case MONO_TYPE_CLASS:
1073 case MONO_TYPE_OBJECT:
1074 case MONO_TYPE_STRING:
1075 case MONO_TYPE_SZARRAY:
1076 case MONO_TYPE_ARRAY:
1077 cinfo->args [n].size = sizeof (gpointer);
1078 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1081 case MONO_TYPE_GENERICINST:
1082 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1083 cinfo->args [n].size = sizeof (gpointer);
1084 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1089 case MONO_TYPE_VALUETYPE:
1090 case MONO_TYPE_TYPEDBYREF: {
1094 klass = mono_class_from_mono_type (sig->params [i]);
1095 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1096 size = sizeof (MonoTypedRef);
1097 else if (is_pinvoke)
1098 size = mono_class_native_size (klass, NULL);
1100 size = mono_class_value_size (klass, NULL);
1102 #if defined(__APPLE__) || defined(__mono_ppc64__)
1103 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1104 cinfo->args [n].size = size;
1106 /* It was 7, now it is 8 in LinuxPPC */
1107 if (fr <= PPC_LAST_FPARG_REG) {
1108 cinfo->args [n].regtype = RegTypeFP;
1109 cinfo->args [n].reg = fr;
1111 FP_ALSO_IN_REG (gr ++);
1113 FP_ALSO_IN_REG (gr ++);
1114 ALWAYS_ON_STACK (stack_size += size);
1116 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1117 cinfo->args [n].regtype = RegTypeBase;
1118 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1125 DEBUG(printf ("load %d bytes struct\n",
1126 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1128 #if PPC_PASS_STRUCTS_BY_VALUE
1130 int align_size = size;
1132 int rest = PPC_LAST_ARG_REG - gr + 1;
1135 align_size += (sizeof (gpointer) - 1);
1136 align_size &= ~(sizeof (gpointer) - 1);
1137 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1138 n_in_regs = MIN (rest, nregs);
1142 /* FIXME: check this */
1143 if (size >= 3 && size % 4 != 0)
1146 cinfo->args [n].regtype = RegTypeStructByVal;
1147 cinfo->args [n].vtregs = n_in_regs;
1148 cinfo->args [n].size = n_in_regs;
1149 cinfo->args [n].vtsize = nregs - n_in_regs;
1150 cinfo->args [n].reg = gr;
1152 #ifdef __mono_ppc64__
1153 if (nregs == 1 && is_pinvoke)
1154 cinfo->args [n].bytes = size;
1157 cinfo->args [n].bytes = 0;
1159 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1160 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1161 stack_size += nregs * sizeof (gpointer);
1164 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1165 cinfo->args [n].regtype = RegTypeStructByAddr;
1166 cinfo->args [n].vtsize = size;
1173 cinfo->args [n].size = 8;
1174 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1178 cinfo->args [n].size = 4;
1180 /* It was 7, now it is 8 in LinuxPPC */
1181 if (fr <= PPC_LAST_FPARG_REG) {
1182 cinfo->args [n].regtype = RegTypeFP;
1183 cinfo->args [n].reg = fr;
1185 FP_ALSO_IN_REG (gr ++);
1186 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1188 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1189 cinfo->args [n].regtype = RegTypeBase;
1190 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1191 stack_size += SIZEOF_REGISTER;
1196 cinfo->args [n].size = 8;
1197 /* It was 7, now it is 8 in LinuxPPC */
1198 if (fr <= PPC_LAST_FPARG_REG) {
1199 cinfo->args [n].regtype = RegTypeFP;
1200 cinfo->args [n].reg = fr;
1202 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1203 ALWAYS_ON_STACK (stack_size += 8);
1205 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1206 cinfo->args [n].regtype = RegTypeBase;
1207 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1213 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1217 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1218 /* Prevent implicit arguments and sig_cookie from
1219 being passed in registers */
1220 gr = PPC_LAST_ARG_REG + 1;
1221 /* Emit the signature cookie just before the implicit arguments */
1222 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1226 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1227 switch (simpletype->type) {
1228 case MONO_TYPE_BOOLEAN:
1233 case MONO_TYPE_CHAR:
1239 case MONO_TYPE_FNPTR:
1240 case MONO_TYPE_CLASS:
1241 case MONO_TYPE_OBJECT:
1242 case MONO_TYPE_SZARRAY:
1243 case MONO_TYPE_ARRAY:
1244 case MONO_TYPE_STRING:
1245 cinfo->ret.reg = ppc_r3;
1249 cinfo->ret.reg = ppc_r3;
1253 cinfo->ret.reg = ppc_f1;
1254 cinfo->ret.regtype = RegTypeFP;
1256 case MONO_TYPE_GENERICINST:
1257 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1258 cinfo->ret.reg = ppc_r3;
1262 case MONO_TYPE_VALUETYPE:
1264 case MONO_TYPE_TYPEDBYREF:
1265 case MONO_TYPE_VOID:
1268 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1272 /* align stack size to 16 */
1273 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1274 stack_size = (stack_size + 15) & ~15;
1276 cinfo->stack_usage = stack_size;
1281 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1283 #if !PPC_PASS_STRUCTS_BY_VALUE
1284 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1285 int num_structs = 0;
1288 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1291 for (i = 0; i < sig->param_count; ++i) {
1292 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1293 if (type->type == MONO_TYPE_VALUETYPE)
1298 cfg->tailcall_valuetype_addrs =
1299 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1300 for (i = 0; i < num_structs; ++i) {
1301 cfg->tailcall_valuetype_addrs [i] =
1302 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1303 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1310 * Set var information according to the calling convention. ppc version.
1311 * The locals var stuff should most likely be split in another method.
1314 mono_arch_allocate_vars (MonoCompile *m)
1316 MonoMethodSignature *sig;
1317 MonoMethodHeader *header;
1319 int i, offset, size, align, curinst;
1320 int frame_reg = ppc_sp;
1322 guint32 locals_stack_size, locals_stack_align;
1324 allocate_tailcall_valuetype_addrs (m);
1326 m->flags |= MONO_CFG_HAS_SPILLUP;
1328 /* allow room for the vararg method args: void* and long/double */
1329 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1330 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1331 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1332 * call convs needs to be handled this way.
1334 if (m->flags & MONO_CFG_HAS_VARARGS)
1335 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1336 /* gtk-sharp and other broken code will dllimport vararg functions even with
1337 * non-varargs signatures. Since there is little hope people will get this right
1338 * we assume they won't.
1340 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1341 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1346 * We use the frame register also for any method that has
1347 * exception clauses. This way, when the handlers are called,
1348 * the code will reference local variables using the frame reg instead of
1349 * the stack pointer: if we had to restore the stack pointer, we'd
1350 * corrupt the method frames that are already on the stack (since
1351 * filters get called before stack unwinding happens) when the filter
1352 * code would call any method (this also applies to finally etc.).
1354 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1355 frame_reg = ppc_r31;
1356 m->frame_reg = frame_reg;
1357 if (frame_reg != ppc_sp) {
1358 m->used_int_regs |= 1 << frame_reg;
1361 sig = mono_method_signature (m->method);
1365 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1366 m->ret->opcode = OP_REGVAR;
1367 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1369 /* FIXME: handle long values? */
1370 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1371 case MONO_TYPE_VOID:
1375 m->ret->opcode = OP_REGVAR;
1376 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1379 m->ret->opcode = OP_REGVAR;
1380 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1384 /* local vars are at a positive offset from the stack pointer */
1386 * also note that if the function uses alloca, we use ppc_r31
1387 * to point at the local variables.
1389 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1390 /* align the offset to 16 bytes: not sure this is needed here */
1392 //offset &= ~(16 - 1);
1394 /* add parameter area size for called functions */
1395 offset += m->param_area;
1397 offset &= ~(16 - 1);
1399 /* allow room to save the return value */
1400 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1403 /* the MonoLMF structure is stored just below the stack pointer */
1406 /* this stuff should not be needed on ppc and the new jit,
1407 * because a call on ppc to the handlers doesn't change the
1408 * stack pointer and the jist doesn't manipulate the stack pointer
1409 * for operations involving valuetypes.
1411 /* reserve space to store the esp */
1412 offset += sizeof (gpointer);
1414 /* this is a global constant */
1415 mono_exc_esp_offset = offset;
1418 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1419 offset += sizeof(gpointer) - 1;
1420 offset &= ~(sizeof(gpointer) - 1);
1422 m->vret_addr->opcode = OP_REGOFFSET;
1423 m->vret_addr->inst_basereg = frame_reg;
1424 m->vret_addr->inst_offset = offset;
1426 if (G_UNLIKELY (m->verbose_level > 1)) {
1427 printf ("vret_addr =");
1428 mono_print_ins (m->vret_addr);
1431 offset += sizeof(gpointer);
1434 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1435 if (locals_stack_align) {
1436 offset += (locals_stack_align - 1);
1437 offset &= ~(locals_stack_align - 1);
1439 for (i = m->locals_start; i < m->num_varinfo; i++) {
1440 if (offsets [i] != -1) {
1441 MonoInst *inst = m->varinfo [i];
1442 inst->opcode = OP_REGOFFSET;
1443 inst->inst_basereg = frame_reg;
1444 inst->inst_offset = offset + offsets [i];
1446 g_print ("allocating local %d (%s) to %d\n",
1447 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1451 offset += locals_stack_size;
1455 inst = m->args [curinst];
1456 if (inst->opcode != OP_REGVAR) {
1457 inst->opcode = OP_REGOFFSET;
1458 inst->inst_basereg = frame_reg;
1459 offset += sizeof (gpointer) - 1;
1460 offset &= ~(sizeof (gpointer) - 1);
1461 inst->inst_offset = offset;
1462 offset += sizeof (gpointer);
1467 for (i = 0; i < sig->param_count; ++i) {
1468 inst = m->args [curinst];
1469 if (inst->opcode != OP_REGVAR) {
1470 inst->opcode = OP_REGOFFSET;
1471 inst->inst_basereg = frame_reg;
1473 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1474 inst->backend.is_pinvoke = 1;
1476 size = mono_type_size (sig->params [i], &align);
1478 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1479 size = align = sizeof (gpointer);
1480 offset += align - 1;
1481 offset &= ~(align - 1);
1482 inst->inst_offset = offset;
1488 /* some storage for fp conversions */
1491 m->arch.fp_conv_var_offset = offset;
1494 /* align the offset to 16 bytes */
1496 offset &= ~(16 - 1);
1499 m->stack_offset = offset;
1501 if (sig->call_convention == MONO_CALL_VARARG) {
1502 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1504 m->sig_cookie = cinfo->sig_cookie.offset;
1511 mono_arch_create_vars (MonoCompile *cfg)
1513 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1515 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1516 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1520 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1521 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1525 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1527 int sig_reg = mono_alloc_ireg (cfg);
1529 /* FIXME: Add support for signature tokens to AOT */
1530 cfg->disable_aot = TRUE;
1532 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1533 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1534 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1538 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1541 MonoMethodSignature *sig;
1545 sig = call->signature;
1546 n = sig->param_count + sig->hasthis;
1548 cinfo = calculate_sizes (sig, sig->pinvoke);
1550 for (i = 0; i < n; ++i) {
1551 ArgInfo *ainfo = cinfo->args + i;
1554 if (i >= sig->hasthis)
1555 t = sig->params [i - sig->hasthis];
1557 t = &mono_defaults.int_class->byval_arg;
1558 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1560 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1561 emit_sig_cookie (cfg, call, cinfo);
1563 in = call->args [i];
1565 if (ainfo->regtype == RegTypeGeneral) {
1566 #ifndef __mono_ppc64__
1567 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1568 MONO_INST_NEW (cfg, ins, OP_MOVE);
1569 ins->dreg = mono_alloc_ireg (cfg);
1570 ins->sreg1 = in->dreg + 1;
1571 MONO_ADD_INS (cfg->cbb, ins);
1572 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1574 MONO_INST_NEW (cfg, ins, OP_MOVE);
1575 ins->dreg = mono_alloc_ireg (cfg);
1576 ins->sreg1 = in->dreg + 2;
1577 MONO_ADD_INS (cfg->cbb, ins);
1578 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1582 MONO_INST_NEW (cfg, ins, OP_MOVE);
1583 ins->dreg = mono_alloc_ireg (cfg);
1584 ins->sreg1 = in->dreg;
1585 MONO_ADD_INS (cfg->cbb, ins);
1587 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1589 } else if (ainfo->regtype == RegTypeStructByAddr) {
1590 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1591 ins->opcode = OP_OUTARG_VT;
1592 ins->sreg1 = in->dreg;
1593 ins->klass = in->klass;
1594 ins->inst_p0 = call;
1595 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1596 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1597 MONO_ADD_INS (cfg->cbb, ins);
1598 } else if (ainfo->regtype == RegTypeStructByVal) {
1599 /* this is further handled in mono_arch_emit_outarg_vt () */
1600 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1601 ins->opcode = OP_OUTARG_VT;
1602 ins->sreg1 = in->dreg;
1603 ins->klass = in->klass;
1604 ins->inst_p0 = call;
1605 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1606 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1607 MONO_ADD_INS (cfg->cbb, ins);
1608 } else if (ainfo->regtype == RegTypeBase) {
1609 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1610 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1611 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1612 if (t->type == MONO_TYPE_R8)
1613 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1615 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1617 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1619 } else if (ainfo->regtype == RegTypeFP) {
1620 if (t->type == MONO_TYPE_VALUETYPE) {
1621 /* this is further handled in mono_arch_emit_outarg_vt () */
1622 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1623 ins->opcode = OP_OUTARG_VT;
1624 ins->sreg1 = in->dreg;
1625 ins->klass = in->klass;
1626 ins->inst_p0 = call;
1627 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1628 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1629 MONO_ADD_INS (cfg->cbb, ins);
1631 cfg->flags |= MONO_CFG_HAS_FPOUT;
1633 int dreg = mono_alloc_freg (cfg);
1635 if (ainfo->size == 4) {
1636 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1638 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1640 ins->sreg1 = in->dreg;
1641 MONO_ADD_INS (cfg->cbb, ins);
1644 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1645 cfg->flags |= MONO_CFG_HAS_FPOUT;
1648 g_assert_not_reached ();
1652 /* Emit the signature cookie in the case that there is no
1653 additional argument */
1654 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1655 emit_sig_cookie (cfg, call, cinfo);
1657 if (cinfo->struct_ret) {
1660 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1661 vtarg->sreg1 = call->vret_var->dreg;
1662 vtarg->dreg = mono_alloc_preg (cfg);
1663 MONO_ADD_INS (cfg->cbb, vtarg);
1665 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1668 call->stack_usage = cinfo->stack_usage;
1669 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1670 cfg->flags |= MONO_CFG_HAS_CALLS;
1676 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1678 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1679 ArgInfo *ainfo = ins->inst_p1;
1680 int ovf_size = ainfo->vtsize;
1681 int doffset = ainfo->offset;
1682 int i, soffset, dreg;
1684 if (ainfo->regtype == RegTypeStructByVal) {
1691 * Darwin pinvokes needs some special handling for 1
1692 * and 2 byte arguments
1694 g_assert (ins->klass);
1695 if (call->signature->pinvoke)
1696 size = mono_class_native_size (ins->klass, NULL);
1697 if (size == 2 || size == 1) {
1698 int tmpr = mono_alloc_ireg (cfg);
1700 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1702 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1703 dreg = mono_alloc_ireg (cfg);
1704 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1705 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1708 for (i = 0; i < ainfo->vtregs; ++i) {
1709 int antipadding = 0;
1712 antipadding = sizeof (gpointer) - ainfo->bytes;
1714 dreg = mono_alloc_ireg (cfg);
1715 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1717 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1718 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1719 soffset += sizeof (gpointer);
1722 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1723 } else if (ainfo->regtype == RegTypeFP) {
1724 int tmpr = mono_alloc_freg (cfg);
1725 if (ainfo->size == 4)
1726 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1728 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1729 dreg = mono_alloc_freg (cfg);
1730 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1731 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1733 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1737 /* FIXME: alignment? */
1738 if (call->signature->pinvoke) {
1739 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1740 vtcopy->backend.is_pinvoke = 1;
1742 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1745 g_assert (ovf_size > 0);
1747 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1748 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1751 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1753 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1758 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1760 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1761 mono_method_signature (method)->ret);
1764 #ifndef __mono_ppc64__
1765 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1768 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1769 ins->sreg1 = val->dreg + 1;
1770 ins->sreg2 = val->dreg + 2;
1771 MONO_ADD_INS (cfg->cbb, ins);
1775 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1776 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1780 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1783 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1785 mono_arch_is_inst_imm (gint64 imm)
1791 * Allow tracing to work with this interface (with an optional argument)
1795 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1799 ppc_load_ptr (code, ppc_r3, cfg->method);
1800 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1801 ppc_load_func (code, ppc_r0, func);
1802 ppc_mtlr (code, ppc_r0);
1816 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1819 int save_mode = SAVE_NONE;
1821 MonoMethod *method = cfg->method;
1822 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1823 mono_method_signature (method)->ret)->type;
1824 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1828 offset = code - cfg->native_code;
1829 /* we need about 16 instructions */
1830 if (offset > (cfg->code_size - 16 * 4)) {
1831 cfg->code_size *= 2;
1832 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1833 code = cfg->native_code + offset;
1837 case MONO_TYPE_VOID:
1838 /* special case string .ctor icall */
1839 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1840 save_mode = SAVE_ONE;
1842 save_mode = SAVE_NONE;
1844 #ifndef __mono_ppc64__
1847 save_mode = SAVE_TWO;
1852 save_mode = SAVE_FP;
1854 case MONO_TYPE_VALUETYPE:
1855 save_mode = SAVE_STRUCT;
1858 save_mode = SAVE_ONE;
1862 switch (save_mode) {
1864 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1865 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1866 if (enable_arguments) {
1867 ppc_mr (code, ppc_r5, ppc_r4);
1868 ppc_mr (code, ppc_r4, ppc_r3);
1872 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1873 if (enable_arguments) {
1874 ppc_mr (code, ppc_r4, ppc_r3);
1878 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1879 if (enable_arguments) {
1880 /* FIXME: what reg? */
1881 ppc_fmr (code, ppc_f3, ppc_f1);
1882 /* FIXME: use 8 byte load on PPC64 */
1883 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1884 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1888 if (enable_arguments) {
1889 /* FIXME: get the actual address */
1890 ppc_mr (code, ppc_r4, ppc_r3);
1898 ppc_load_ptr (code, ppc_r3, cfg->method);
1899 ppc_load_func (code, ppc_r0, func);
1900 ppc_mtlr (code, ppc_r0);
1903 switch (save_mode) {
1905 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1906 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1909 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1912 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1922 * Conditional branches have a small offset, so if it is likely overflowed,
1923 * we do a branch to the end of the method (uncond branches have much larger
1924 * offsets) where we perform the conditional and jump back unconditionally.
1925 * It's slightly slower, since we add two uncond branches, but it's very simple
1926 * with the current patch implementation and such large methods are likely not
1927 * going to be perf critical anyway.
1932 const char *exception;
1939 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1940 if (0 && ins->inst_true_bb->native_offset) { \
1941 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1943 int br_disp = ins->inst_true_bb->max_offset - offset; \
1944 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1945 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1946 ovfj->data.bb = ins->inst_true_bb; \
1947 ovfj->ip_offset = 0; \
1948 ovfj->b0_cond = (b0); \
1949 ovfj->b1_cond = (b1); \
1950 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1953 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1954 ppc_bc (code, (b0), (b1), 0); \
1958 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1960 /* emit an exception if condition is fail
1962 * We assign the extra code used to throw the implicit exceptions
1963 * to cfg->bb_exit as far as the big branch handling is concerned
1965 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1967 int br_disp = cfg->bb_exit->max_offset - offset; \
1968 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1969 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1970 ovfj->data.exception = (exc_name); \
1971 ovfj->ip_offset = code - cfg->native_code; \
1972 ovfj->b0_cond = (b0); \
1973 ovfj->b1_cond = (b1); \
1974 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1976 cfg->bb_exit->max_offset += 24; \
1978 mono_add_patch_info (cfg, code - cfg->native_code, \
1979 MONO_PATCH_INFO_EXC, exc_name); \
1980 ppc_bcl (code, (b0), (b1), 0); \
1984 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1987 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1992 normalize_opcode (int opcode)
1995 #ifndef __mono_ilp32__
1996 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1997 return OP_LOAD_MEMBASE;
1998 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1999 return OP_LOAD_MEMINDEX;
2000 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2001 return OP_STORE_MEMBASE_REG;
2002 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2003 return OP_STORE_MEMBASE_IMM;
2004 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2005 return OP_STORE_MEMINDEX;
2007 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2009 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2010 return OP_SHR_UN_IMM;
2017 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2019 MonoInst *ins, *n, *last_ins = NULL;
2021 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2022 switch (normalize_opcode (ins->opcode)) {
2024 /* remove unnecessary multiplication with 1 */
2025 if (ins->inst_imm == 1) {
2026 if (ins->dreg != ins->sreg1) {
2027 ins->opcode = OP_MOVE;
2029 MONO_DELETE_INS (bb, ins);
2033 int power2 = mono_is_power_of_two (ins->inst_imm);
2035 ins->opcode = OP_SHL_IMM;
2036 ins->inst_imm = power2;
2040 case OP_LOAD_MEMBASE:
2042 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2043 * OP_LOAD_MEMBASE offset(basereg), reg
2045 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2046 ins->inst_basereg == last_ins->inst_destbasereg &&
2047 ins->inst_offset == last_ins->inst_offset) {
2048 if (ins->dreg == last_ins->sreg1) {
2049 MONO_DELETE_INS (bb, ins);
2052 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2053 ins->opcode = OP_MOVE;
2054 ins->sreg1 = last_ins->sreg1;
2058 * Note: reg1 must be different from the basereg in the second load
2059 * OP_LOAD_MEMBASE offset(basereg), reg1
2060 * OP_LOAD_MEMBASE offset(basereg), reg2
2062 * OP_LOAD_MEMBASE offset(basereg), reg1
2063 * OP_MOVE reg1, reg2
2065 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2066 ins->inst_basereg != last_ins->dreg &&
2067 ins->inst_basereg == last_ins->inst_basereg &&
2068 ins->inst_offset == last_ins->inst_offset) {
2070 if (ins->dreg == last_ins->dreg) {
2071 MONO_DELETE_INS (bb, ins);
2074 ins->opcode = OP_MOVE;
2075 ins->sreg1 = last_ins->dreg;
2078 //g_assert_not_reached ();
2082 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2083 * OP_LOAD_MEMBASE offset(basereg), reg
2085 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2086 * OP_ICONST reg, imm
2088 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2089 ins->inst_basereg == last_ins->inst_destbasereg &&
2090 ins->inst_offset == last_ins->inst_offset) {
2091 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2092 ins->opcode = OP_ICONST;
2093 ins->inst_c0 = last_ins->inst_imm;
2094 g_assert_not_reached (); // check this rule
2098 case OP_LOADU1_MEMBASE:
2099 case OP_LOADI1_MEMBASE:
2100 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2101 ins->inst_basereg == last_ins->inst_destbasereg &&
2102 ins->inst_offset == last_ins->inst_offset) {
2103 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2104 ins->sreg1 = last_ins->sreg1;
2107 case OP_LOADU2_MEMBASE:
2108 case OP_LOADI2_MEMBASE:
2109 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2110 ins->inst_basereg == last_ins->inst_destbasereg &&
2111 ins->inst_offset == last_ins->inst_offset) {
2112 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2113 ins->sreg1 = last_ins->sreg1;
2116 #ifdef __mono_ppc64__
2117 case OP_LOADU4_MEMBASE:
2118 case OP_LOADI4_MEMBASE:
2119 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2120 ins->inst_basereg == last_ins->inst_destbasereg &&
2121 ins->inst_offset == last_ins->inst_offset) {
2122 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2123 ins->sreg1 = last_ins->sreg1;
2128 ins->opcode = OP_MOVE;
2132 if (ins->dreg == ins->sreg1) {
2133 MONO_DELETE_INS (bb, ins);
2137 * OP_MOVE sreg, dreg
2138 * OP_MOVE dreg, sreg
2140 if (last_ins && last_ins->opcode == OP_MOVE &&
2141 ins->sreg1 == last_ins->dreg &&
2142 ins->dreg == last_ins->sreg1) {
2143 MONO_DELETE_INS (bb, ins);
2151 bb->last_ins = last_ins;
2155 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2157 switch (ins->opcode) {
2158 case OP_ICONV_TO_R_UN: {
2159 #if G_BYTE_ORDER == G_BIG_ENDIAN
2160 static const guint64 adjust_val = 0x4330000000000000ULL;
2162 static const guint64 adjust_val = 0x0000000000003043ULL;
2164 int msw_reg = mono_alloc_ireg (cfg);
2165 int adj_reg = mono_alloc_freg (cfg);
2166 int tmp_reg = mono_alloc_freg (cfg);
2167 int basereg = ppc_sp;
2169 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2170 if (!ppc_is_imm16 (offset + 4)) {
2171 basereg = mono_alloc_ireg (cfg);
2172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2174 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2175 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2176 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2177 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2179 ins->opcode = OP_NOP;
2182 #ifndef __mono_ppc64__
2183 case OP_ICONV_TO_R4:
2184 case OP_ICONV_TO_R8: {
2185 /* If we have a PPC_FEATURE_64 machine we can avoid
2186 this and use the fcfid instruction. Otherwise
2187 on an old 32-bit chip and we have to do this the
2189 if (!(cpu_hw_caps & PPC_ISA_64)) {
2190 /* FIXME: change precision for CEE_CONV_R4 */
2191 static const guint64 adjust_val = 0x4330000080000000ULL;
2192 int msw_reg = mono_alloc_ireg (cfg);
2193 int xored = mono_alloc_ireg (cfg);
2194 int adj_reg = mono_alloc_freg (cfg);
2195 int tmp_reg = mono_alloc_freg (cfg);
2196 int basereg = ppc_sp;
2198 if (!ppc_is_imm16 (offset + 4)) {
2199 basereg = mono_alloc_ireg (cfg);
2200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2202 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2204 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2205 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2206 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2207 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2208 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2209 if (ins->opcode == OP_ICONV_TO_R4)
2210 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2211 ins->opcode = OP_NOP;
2217 int msw_reg = mono_alloc_ireg (cfg);
2218 int basereg = ppc_sp;
2220 if (!ppc_is_imm16 (offset + 4)) {
2221 basereg = mono_alloc_ireg (cfg);
2222 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2224 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2225 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2226 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2227 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2228 ins->opcode = OP_NOP;
2231 #ifdef __mono_ppc64__
2233 case OP_IADD_OVF_UN:
2235 int shifted1_reg = mono_alloc_ireg (cfg);
2236 int shifted2_reg = mono_alloc_ireg (cfg);
2237 int result_shifted_reg = mono_alloc_ireg (cfg);
2239 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2241 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2242 if (ins->opcode == OP_IADD_OVF_UN)
2243 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2245 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2246 ins->opcode = OP_NOP;
2253 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2255 switch (ins->opcode) {
2257 /* ADC sets the condition code */
2258 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2262 case OP_LADD_OVF_UN:
2263 /* ADC sets the condition code */
2264 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2269 /* SBB sets the condition code */
2270 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2274 case OP_LSUB_OVF_UN:
2275 /* SBB sets the condition code */
2276 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2281 /* This is the old version from inssel-long32.brg */
2282 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 1, ins->sreg1 + 1);
2283 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 2, ins->sreg1 + 2);
2284 /* ADC sets the condition codes */
2285 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 1, ins->dreg + 1, 1);
2286 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->dreg + 2, 0);
2295 * the branch_b0_table should maintain the order of these
2309 branch_b0_table [] = {
2324 branch_b1_table [] = {
2338 #define NEW_INS(cfg,dest,op) do { \
2339 MONO_INST_NEW((cfg), (dest), (op)); \
2340 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2344 map_to_reg_reg_op (int op)
2353 case OP_COMPARE_IMM:
2355 case OP_ICOMPARE_IMM:
2357 case OP_LCOMPARE_IMM:
2373 case OP_LOAD_MEMBASE:
2374 return OP_LOAD_MEMINDEX;
2375 case OP_LOADI4_MEMBASE:
2376 return OP_LOADI4_MEMINDEX;
2377 case OP_LOADU4_MEMBASE:
2378 return OP_LOADU4_MEMINDEX;
2379 case OP_LOADI8_MEMBASE:
2380 return OP_LOADI8_MEMINDEX;
2381 case OP_LOADU1_MEMBASE:
2382 return OP_LOADU1_MEMINDEX;
2383 case OP_LOADI2_MEMBASE:
2384 return OP_LOADI2_MEMINDEX;
2385 case OP_LOADU2_MEMBASE:
2386 return OP_LOADU2_MEMINDEX;
2387 case OP_LOADI1_MEMBASE:
2388 return OP_LOADI1_MEMINDEX;
2389 case OP_LOADR4_MEMBASE:
2390 return OP_LOADR4_MEMINDEX;
2391 case OP_LOADR8_MEMBASE:
2392 return OP_LOADR8_MEMINDEX;
2393 case OP_STOREI1_MEMBASE_REG:
2394 return OP_STOREI1_MEMINDEX;
2395 case OP_STOREI2_MEMBASE_REG:
2396 return OP_STOREI2_MEMINDEX;
2397 case OP_STOREI4_MEMBASE_REG:
2398 return OP_STOREI4_MEMINDEX;
2399 case OP_STOREI8_MEMBASE_REG:
2400 return OP_STOREI8_MEMINDEX;
2401 case OP_STORE_MEMBASE_REG:
2402 return OP_STORE_MEMINDEX;
2403 case OP_STORER4_MEMBASE_REG:
2404 return OP_STORER4_MEMINDEX;
2405 case OP_STORER8_MEMBASE_REG:
2406 return OP_STORER8_MEMINDEX;
2407 case OP_STORE_MEMBASE_IMM:
2408 return OP_STORE_MEMBASE_REG;
2409 case OP_STOREI1_MEMBASE_IMM:
2410 return OP_STOREI1_MEMBASE_REG;
2411 case OP_STOREI2_MEMBASE_IMM:
2412 return OP_STOREI2_MEMBASE_REG;
2413 case OP_STOREI4_MEMBASE_IMM:
2414 return OP_STOREI4_MEMBASE_REG;
2415 case OP_STOREI8_MEMBASE_IMM:
2416 return OP_STOREI8_MEMBASE_REG;
2418 return mono_op_imm_to_op (op);
2421 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2423 #define compare_opcode_is_unsigned(opcode) \
2424 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2425 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2426 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2427 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2428 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2429 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2430 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2431 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2434 * Remove from the instruction list the instructions that can't be
2435 * represented with very simple instructions with no register
2439 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2441 MonoInst *ins, *next, *temp, *last_ins = NULL;
2444 MONO_BB_FOR_EACH_INS (bb, ins) {
2446 switch (ins->opcode) {
2447 case OP_IDIV_UN_IMM:
2450 case OP_IREM_UN_IMM:
2451 NEW_INS (cfg, temp, OP_ICONST);
2452 temp->inst_c0 = ins->inst_imm;
2453 temp->dreg = mono_alloc_ireg (cfg);
2454 ins->sreg2 = temp->dreg;
2455 if (ins->opcode == OP_IDIV_IMM)
2456 ins->opcode = OP_IDIV;
2457 else if (ins->opcode == OP_IREM_IMM)
2458 ins->opcode = OP_IREM;
2459 else if (ins->opcode == OP_IDIV_UN_IMM)
2460 ins->opcode = OP_IDIV_UN;
2461 else if (ins->opcode == OP_IREM_UN_IMM)
2462 ins->opcode = OP_IREM_UN;
2464 /* handle rem separately */
2468 CASE_PPC64 (OP_LREM)
2469 CASE_PPC64 (OP_LREM_UN) {
2471 /* we change a rem dest, src1, src2 to
2472 * div temp1, src1, src2
2473 * mul temp2, temp1, src2
2474 * sub dest, src1, temp2
2476 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2477 NEW_INS (cfg, mul, OP_IMUL);
2478 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2479 ins->opcode = OP_ISUB;
2481 NEW_INS (cfg, mul, OP_LMUL);
2482 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2483 ins->opcode = OP_LSUB;
2485 temp->sreg1 = ins->sreg1;
2486 temp->sreg2 = ins->sreg2;
2487 temp->dreg = mono_alloc_ireg (cfg);
2488 mul->sreg1 = temp->dreg;
2489 mul->sreg2 = ins->sreg2;
2490 mul->dreg = mono_alloc_ireg (cfg);
2491 ins->sreg2 = mul->dreg;
2495 CASE_PPC64 (OP_LADD_IMM)
2498 if (!ppc_is_imm16 (ins->inst_imm)) {
2499 NEW_INS (cfg, temp, OP_ICONST);
2500 temp->inst_c0 = ins->inst_imm;
2501 temp->dreg = mono_alloc_ireg (cfg);
2502 ins->sreg2 = temp->dreg;
2503 ins->opcode = map_to_reg_reg_op (ins->opcode);
2507 CASE_PPC64 (OP_LSUB_IMM)
2509 if (!ppc_is_imm16 (-ins->inst_imm)) {
2510 NEW_INS (cfg, temp, OP_ICONST);
2511 temp->inst_c0 = ins->inst_imm;
2512 temp->dreg = mono_alloc_ireg (cfg);
2513 ins->sreg2 = temp->dreg;
2514 ins->opcode = map_to_reg_reg_op (ins->opcode);
2526 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2527 #ifdef __mono_ppc64__
2528 if (ins->inst_imm & 0xffffffff00000000ULL)
2532 NEW_INS (cfg, temp, OP_ICONST);
2533 temp->inst_c0 = ins->inst_imm;
2534 temp->dreg = mono_alloc_ireg (cfg);
2535 ins->sreg2 = temp->dreg;
2536 ins->opcode = map_to_reg_reg_op (ins->opcode);
2545 NEW_INS (cfg, temp, OP_ICONST);
2546 temp->inst_c0 = ins->inst_imm;
2547 temp->dreg = mono_alloc_ireg (cfg);
2548 ins->sreg2 = temp->dreg;
2549 ins->opcode = map_to_reg_reg_op (ins->opcode);
2551 case OP_COMPARE_IMM:
2552 case OP_ICOMPARE_IMM:
2553 CASE_PPC64 (OP_LCOMPARE_IMM)
2555 /* Branch opts can eliminate the branch */
2556 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2557 ins->opcode = OP_NOP;
2561 if (compare_opcode_is_unsigned (next->opcode)) {
2562 if (!ppc_is_uimm16 (ins->inst_imm)) {
2563 NEW_INS (cfg, temp, OP_ICONST);
2564 temp->inst_c0 = ins->inst_imm;
2565 temp->dreg = mono_alloc_ireg (cfg);
2566 ins->sreg2 = temp->dreg;
2567 ins->opcode = map_to_reg_reg_op (ins->opcode);
2570 if (!ppc_is_imm16 (ins->inst_imm)) {
2571 NEW_INS (cfg, temp, OP_ICONST);
2572 temp->inst_c0 = ins->inst_imm;
2573 temp->dreg = mono_alloc_ireg (cfg);
2574 ins->sreg2 = temp->dreg;
2575 ins->opcode = map_to_reg_reg_op (ins->opcode);
2581 if (ins->inst_imm == 1) {
2582 ins->opcode = OP_MOVE;
2585 if (ins->inst_imm == 0) {
2586 ins->opcode = OP_ICONST;
2590 imm = mono_is_power_of_two (ins->inst_imm);
2592 ins->opcode = OP_SHL_IMM;
2593 ins->inst_imm = imm;
2596 if (!ppc_is_imm16 (ins->inst_imm)) {
2597 NEW_INS (cfg, temp, OP_ICONST);
2598 temp->inst_c0 = ins->inst_imm;
2599 temp->dreg = mono_alloc_ireg (cfg);
2600 ins->sreg2 = temp->dreg;
2601 ins->opcode = map_to_reg_reg_op (ins->opcode);
2604 case OP_LOCALLOC_IMM:
2605 NEW_INS (cfg, temp, OP_ICONST);
2606 temp->inst_c0 = ins->inst_imm;
2607 temp->dreg = mono_alloc_ireg (cfg);
2608 ins->sreg1 = temp->dreg;
2609 ins->opcode = OP_LOCALLOC;
2611 case OP_LOAD_MEMBASE:
2612 case OP_LOADI4_MEMBASE:
2613 CASE_PPC64 (OP_LOADI8_MEMBASE)
2614 case OP_LOADU4_MEMBASE:
2615 case OP_LOADI2_MEMBASE:
2616 case OP_LOADU2_MEMBASE:
2617 case OP_LOADI1_MEMBASE:
2618 case OP_LOADU1_MEMBASE:
2619 case OP_LOADR4_MEMBASE:
2620 case OP_LOADR8_MEMBASE:
2621 case OP_STORE_MEMBASE_REG:
2622 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2623 case OP_STOREI4_MEMBASE_REG:
2624 case OP_STOREI2_MEMBASE_REG:
2625 case OP_STOREI1_MEMBASE_REG:
2626 case OP_STORER4_MEMBASE_REG:
2627 case OP_STORER8_MEMBASE_REG:
2628 /* we can do two things: load the immed in a register
2629 * and use an indexed load, or see if the immed can be
2630 * represented as an ad_imm + a load with a smaller offset
2631 * that fits. We just do the first for now, optimize later.
2633 if (ppc_is_imm16 (ins->inst_offset))
2635 NEW_INS (cfg, temp, OP_ICONST);
2636 temp->inst_c0 = ins->inst_offset;
2637 temp->dreg = mono_alloc_ireg (cfg);
2638 ins->sreg2 = temp->dreg;
2639 ins->opcode = map_to_reg_reg_op (ins->opcode);
2641 case OP_STORE_MEMBASE_IMM:
2642 case OP_STOREI1_MEMBASE_IMM:
2643 case OP_STOREI2_MEMBASE_IMM:
2644 case OP_STOREI4_MEMBASE_IMM:
2645 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2646 NEW_INS (cfg, temp, OP_ICONST);
2647 temp->inst_c0 = ins->inst_imm;
2648 temp->dreg = mono_alloc_ireg (cfg);
2649 ins->sreg1 = temp->dreg;
2650 ins->opcode = map_to_reg_reg_op (ins->opcode);
2652 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2655 if (cfg->compile_aot) {
2656 /* Keep these in the aot case */
2659 NEW_INS (cfg, temp, OP_ICONST);
2660 temp->inst_c0 = (gulong)ins->inst_p0;
2661 temp->dreg = mono_alloc_ireg (cfg);
2662 ins->inst_basereg = temp->dreg;
2663 ins->inst_offset = 0;
2664 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2666 /* make it handle the possibly big ins->inst_offset
2667 * later optimize to use lis + load_membase
2673 bb->last_ins = last_ins;
2674 bb->max_vreg = cfg->next_vreg;
2678 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2680 long offset = cfg->arch.fp_conv_var_offset;
2682 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2683 #ifdef __mono_ppc64__
2685 ppc_fctidz (code, ppc_f0, sreg);
2690 ppc_fctiwz (code, ppc_f0, sreg);
2693 if (ppc_is_imm16 (offset + sub_offset)) {
2694 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2696 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2698 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2700 ppc_load (code, dreg, offset);
2701 ppc_add (code, dreg, dreg, cfg->frame_reg);
2702 ppc_stfd (code, ppc_f0, 0, dreg);
2704 ppc_ldr (code, dreg, sub_offset, dreg);
2706 ppc_lwz (code, dreg, sub_offset, dreg);
2710 ppc_andid (code, dreg, dreg, 0xff);
2712 ppc_andid (code, dreg, dreg, 0xffff);
2713 #ifdef __mono_ppc64__
2715 ppc_clrldi (code, dreg, dreg, 32);
2719 ppc_extsb (code, dreg, dreg);
2721 ppc_extsh (code, dreg, dreg);
2722 #ifdef __mono_ppc64__
2724 ppc_extsw (code, dreg, dreg);
2732 const guchar *target;
2737 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2740 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2741 #ifdef __mono_ppc64__
2742 g_assert_not_reached ();
2744 PatchData *pdata = (PatchData*)user_data;
2745 guchar *code = data;
2746 guint32 *thunks = data;
2747 guint32 *endthunks = (guint32*)(code + bsize);
2751 int difflow, diffhigh;
2753 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2754 difflow = (char*)pdata->code - (char*)thunks;
2755 diffhigh = (char*)pdata->code - (char*)endthunks;
2756 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2759 templ = (guchar*)load;
2760 ppc_load_sequence (templ, ppc_r0, pdata->target);
2762 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2763 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2764 while (thunks < endthunks) {
2765 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2766 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2767 ppc_patch (pdata->code, (guchar*)thunks);
2770 static int num_thunks = 0;
2772 if ((num_thunks % 20) == 0)
2773 g_print ("num_thunks lookup: %d\n", num_thunks);
2776 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2777 /* found a free slot instead: emit thunk */
2778 code = (guchar*)thunks;
2779 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2780 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2781 ppc_mtctr (code, ppc_r0);
2782 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2783 mono_arch_flush_icache ((guchar*)thunks, 16);
2785 ppc_patch (pdata->code, (guchar*)thunks);
2788 static int num_thunks = 0;
2790 if ((num_thunks % 20) == 0)
2791 g_print ("num_thunks: %d\n", num_thunks);
2795 /* skip 16 bytes, the size of the thunk */
2799 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2806 handle_thunk (int absolute, guchar *code, const guchar *target) {
2807 MonoDomain *domain = mono_domain_get ();
2811 pdata.target = target;
2812 pdata.absolute = absolute;
2815 mono_domain_lock (domain);
2816 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2819 /* this uses the first available slot */
2821 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2823 mono_domain_unlock (domain);
2825 if (pdata.found != 1)
2826 g_print ("thunk failed for %p from %p\n", target, code);
2827 g_assert (pdata.found == 1);
2831 patch_ins (guint8 *code, guint32 ins)
2833 *(guint32*)code = GUINT32_TO_BE (ins);
2834 mono_arch_flush_icache (code, 4);
2838 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2840 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2841 guint32 prim = ins >> 26;
2844 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2846 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2847 gint diff = target - code;
2850 if (diff <= 33554431){
2851 ins = (18 << 26) | (diff) | (ins & 1);
2852 patch_ins (code, ins);
2856 /* diff between 0 and -33554432 */
2857 if (diff >= -33554432){
2858 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2859 patch_ins (code, ins);
2864 if ((glong)target >= 0){
2865 if ((glong)target <= 33554431){
2866 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2867 patch_ins (code, ins);
2871 if ((glong)target >= -33554432){
2872 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2873 patch_ins (code, ins);
2878 handle_thunk (TRUE, code, target);
2881 g_assert_not_reached ();
2889 guint32 li = (gulong)target;
2890 ins = (ins & 0xffff0000) | (ins & 3);
2891 ovf = li & 0xffff0000;
2892 if (ovf != 0 && ovf != 0xffff0000)
2893 g_assert_not_reached ();
2896 // FIXME: assert the top bits of li are 0
2898 gint diff = target - code;
2899 ins = (ins & 0xffff0000) | (ins & 3);
2900 ovf = diff & 0xffff0000;
2901 if (ovf != 0 && ovf != 0xffff0000)
2902 g_assert_not_reached ();
2906 patch_ins (code, ins);
2910 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2911 #ifdef __mono_ppc64__
2912 guint32 *seq = (guint32*)code;
2913 guint32 *branch_ins;
2915 /* the trampoline code will try to patch the blrl, blr, bcctr */
2916 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2918 if (ppc_opcode (seq [-3]) == 58 || ppc_opcode (seq [-3]) == 31) /* ld || mr */
2923 if (ppc_opcode (seq [5]) == 58 || ppc_opcode (seq [5]) == 31) /* ld || mr */
2924 branch_ins = seq + 8;
2926 branch_ins = seq + 6;
2929 seq = (guint32*)code;
2930 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2931 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2933 if (ppc_opcode (seq [5]) == 58) { /* ld */
2934 g_assert (ppc_opcode (seq [6]) == 58); /* ld */
2937 guint8 *buf = (guint8*)&seq [5];
2938 ppc_mr (buf, ppc_r0, ppc_r11);
2943 target = mono_get_addr_from_ftnptr ((gpointer)target);
2946 /* FIXME: make this thread safe */
2947 /* FIXME: we're assuming we're using r11 here */
2948 ppc_load_ptr_sequence (code, ppc_r11, target);
2949 mono_arch_flush_icache ((guint8*)seq, 28);
2952 /* the trampoline code will try to patch the blrl, blr, bcctr */
2953 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2956 /* this is the lis/ori/mtlr/blrl sequence */
2957 seq = (guint32*)code;
2958 g_assert ((seq [0] >> 26) == 15);
2959 g_assert ((seq [1] >> 26) == 24);
2960 g_assert ((seq [2] >> 26) == 31);
2961 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2962 /* FIXME: make this thread safe */
2963 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2964 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2965 mono_arch_flush_icache (code - 8, 8);
2968 g_assert_not_reached ();
2970 // g_print ("patched with 0x%08x\n", ins);
2974 ppc_patch (guchar *code, const guchar *target)
2976 ppc_patch_full (code, target, FALSE);
2980 mono_ppc_patch (guchar *code, const guchar *target)
2982 ppc_patch (code, target);
2986 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2988 switch (ins->opcode) {
2991 case OP_FCALL_MEMBASE:
2992 if (ins->dreg != ppc_f1)
2993 ppc_fmr (code, ins->dreg, ppc_f1);
3001 * emit_load_volatile_arguments:
3003 * Load volatile arguments from the stack to the original input registers.
3004 * Required before a tail call.
3007 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3009 MonoMethod *method = cfg->method;
3010 MonoMethodSignature *sig;
3014 int struct_index = 0;
3016 sig = mono_method_signature (method);
3018 /* This is the opposite of the code in emit_prolog */
3022 cinfo = calculate_sizes (sig, sig->pinvoke);
3024 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3025 ArgInfo *ainfo = &cinfo->ret;
3026 inst = cfg->vret_addr;
3027 g_assert (ppc_is_imm16 (inst->inst_offset));
3028 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3030 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3031 ArgInfo *ainfo = cinfo->args + i;
3032 inst = cfg->args [pos];
3034 g_assert (inst->opcode != OP_REGVAR);
3035 g_assert (ppc_is_imm16 (inst->inst_offset));
3037 switch (ainfo->regtype) {
3038 case RegTypeGeneral:
3039 switch (ainfo->size) {
3041 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3044 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3046 #ifdef __mono_ppc64__
3048 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3052 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3058 switch (ainfo->size) {
3060 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3063 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3066 g_assert_not_reached ();
3071 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3072 &inst->klass->byval_arg);
3074 #ifndef __mono_ppc64__
3075 if (type->type == MONO_TYPE_I8)
3079 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3080 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3081 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3082 } else if (type->type == MONO_TYPE_I4) {
3083 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3084 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3092 case RegTypeStructByVal: {
3103 * Darwin pinvokes needs some special handling
3104 * for 1 and 2 byte arguments
3106 if (method->signature->pinvoke)
3107 size = mono_class_native_size (inst->klass, NULL);
3108 if (size == 1 || size == 2) {
3113 for (j = 0; j < ainfo->vtregs; ++j) {
3114 ppc_ldptr (code, ainfo->reg + j,
3115 inst->inst_offset + j * sizeof (gpointer),
3116 inst->inst_basereg);
3117 /* FIXME: shift to the right */
3124 case RegTypeStructByAddr: {
3125 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3127 g_assert (ppc_is_imm16 (addr->inst_offset));
3128 g_assert (!ainfo->offset);
3129 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3136 g_assert_not_reached ();
3147 /* This must be kept in sync with emit_load_volatile_arguments(). */
3149 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3151 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3152 MonoMethodSignature *sig;
3157 if (ins->opcode != OP_JMP)
3160 call = (MonoCallInst*)ins;
3161 sig = mono_method_signature (cfg->method);
3162 cinfo = calculate_sizes (sig, sig->pinvoke);
3164 if (MONO_TYPE_ISSTRUCT (sig->ret))
3166 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3167 ArgInfo *ainfo = cinfo->args + i;
3169 switch (ainfo->regtype) {
3170 case RegTypeGeneral:
3179 case RegTypeStructByVal:
3180 len += 4 * ainfo->size;
3183 case RegTypeStructByAddr:
3188 g_assert_not_reached ();
3198 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3200 long size = cfg->param_area;
3202 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3203 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3208 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3209 if (ppc_is_imm16 (-size)) {
3210 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3212 ppc_load (code, ppc_r11, -size);
3213 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3220 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3222 long size = cfg->param_area;
3224 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3225 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3230 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3231 if (ppc_is_imm16 (size)) {
3232 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3234 ppc_load (code, ppc_r11, size);
3235 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3241 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3245 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3247 MonoInst *ins, *next;
3250 guint8 *code = cfg->native_code + cfg->code_len;
3251 MonoInst *last_ins = NULL;
3252 guint last_offset = 0;
3256 /* we don't align basic blocks of loops on ppc */
3258 if (cfg->verbose_level > 2)
3259 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3261 cpos = bb->max_offset;
3263 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3264 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3265 //g_assert (!mono_compile_aot);
3268 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3269 /* this is not thread save, but good enough */
3270 /* fixme: howto handle overflows? */
3271 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3274 MONO_BB_FOR_EACH_INS (bb, ins) {
3275 offset = code - cfg->native_code;
3277 max_len = ins_native_length (cfg, ins);
3279 if (offset > (cfg->code_size - max_len - 16)) {
3280 cfg->code_size *= 2;
3281 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3282 code = cfg->native_code + offset;
3284 // if (ins->cil_code)
3285 // g_print ("cil code\n");
3286 mono_debug_record_line_number (cfg, ins, offset);
3288 switch (normalize_opcode (ins->opcode)) {
3289 case OP_RELAXED_NOP:
3292 case OP_DUMMY_STORE:
3293 case OP_NOT_REACHED:
3296 case OP_SEQ_POINT: {
3299 if (cfg->compile_aot)
3303 * Read from the single stepping trigger page. This will cause a
3304 * SIGSEGV when single stepping is enabled.
3305 * We do this _before_ the breakpoint, so single stepping after
3306 * a breakpoint is hit will step to the next IL offset.
3308 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3309 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3310 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3313 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3316 * A placeholder for a possible breakpoint inserted by
3317 * mono_arch_set_breakpoint ().
3319 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3324 emit_tls_access (code, ins->dreg, ins->inst_offset);
3327 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3328 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3329 ppc_mr (code, ppc_r4, ppc_r0);
3332 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3333 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3334 ppc_mr (code, ppc_r4, ppc_r0);
3336 case OP_MEMORY_BARRIER:
3339 case OP_STOREI1_MEMBASE_REG:
3340 if (ppc_is_imm16 (ins->inst_offset)) {
3341 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3343 if (ppc_is_imm32 (ins->inst_offset)) {
3344 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3345 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3347 ppc_load (code, ppc_r0, ins->inst_offset);
3348 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3352 case OP_STOREI2_MEMBASE_REG:
3353 if (ppc_is_imm16 (ins->inst_offset)) {
3354 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3356 if (ppc_is_imm32 (ins->inst_offset)) {
3357 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3358 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3360 ppc_load (code, ppc_r0, ins->inst_offset);
3361 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3365 case OP_STORE_MEMBASE_REG:
3366 if (ppc_is_imm16 (ins->inst_offset)) {
3367 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3369 if (ppc_is_imm32 (ins->inst_offset)) {
3370 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3371 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3373 ppc_load (code, ppc_r0, ins->inst_offset);
3374 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3378 #ifdef __mono_ilp32__
3379 case OP_STOREI8_MEMBASE_REG:
3380 if (ppc_is_imm16 (ins->inst_offset)) {
3381 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3383 ppc_load (code, ppc_r0, ins->inst_offset);
3384 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3388 case OP_STOREI1_MEMINDEX:
3389 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3391 case OP_STOREI2_MEMINDEX:
3392 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3394 case OP_STORE_MEMINDEX:
3395 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3398 g_assert_not_reached ();
3400 case OP_LOAD_MEMBASE:
3401 if (ppc_is_imm16 (ins->inst_offset)) {
3402 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3404 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3405 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3406 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3408 ppc_load (code, ppc_r0, ins->inst_offset);
3409 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3413 case OP_LOADI4_MEMBASE:
3414 #ifdef __mono_ppc64__
3415 if (ppc_is_imm16 (ins->inst_offset)) {
3416 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3418 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3419 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3420 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3422 ppc_load (code, ppc_r0, ins->inst_offset);
3423 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3428 case OP_LOADU4_MEMBASE:
3429 if (ppc_is_imm16 (ins->inst_offset)) {
3430 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3432 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3433 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3434 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3436 ppc_load (code, ppc_r0, ins->inst_offset);
3437 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3441 case OP_LOADI1_MEMBASE:
3442 case OP_LOADU1_MEMBASE:
3443 if (ppc_is_imm16 (ins->inst_offset)) {
3444 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3446 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3447 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3448 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3450 ppc_load (code, ppc_r0, ins->inst_offset);
3451 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3454 if (ins->opcode == OP_LOADI1_MEMBASE)
3455 ppc_extsb (code, ins->dreg, ins->dreg);
3457 case OP_LOADU2_MEMBASE:
3458 if (ppc_is_imm16 (ins->inst_offset)) {
3459 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3461 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3462 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3463 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3465 ppc_load (code, ppc_r0, ins->inst_offset);
3466 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3470 case OP_LOADI2_MEMBASE:
3471 if (ppc_is_imm16 (ins->inst_offset)) {
3472 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3474 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3475 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3476 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3478 ppc_load (code, ppc_r0, ins->inst_offset);
3479 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3483 #ifdef __mono_ilp32__
3484 case OP_LOADI8_MEMBASE:
3485 if (ppc_is_imm16 (ins->inst_offset)) {
3486 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3488 ppc_load (code, ppc_r0, ins->inst_offset);
3489 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3493 case OP_LOAD_MEMINDEX:
3494 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3496 case OP_LOADI4_MEMINDEX:
3497 #ifdef __mono_ppc64__
3498 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3501 case OP_LOADU4_MEMINDEX:
3502 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3504 case OP_LOADU2_MEMINDEX:
3505 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3507 case OP_LOADI2_MEMINDEX:
3508 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3510 case OP_LOADU1_MEMINDEX:
3511 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3513 case OP_LOADI1_MEMINDEX:
3514 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3515 ppc_extsb (code, ins->dreg, ins->dreg);
3517 case OP_ICONV_TO_I1:
3518 CASE_PPC64 (OP_LCONV_TO_I1)
3519 ppc_extsb (code, ins->dreg, ins->sreg1);
3521 case OP_ICONV_TO_I2:
3522 CASE_PPC64 (OP_LCONV_TO_I2)
3523 ppc_extsh (code, ins->dreg, ins->sreg1);
3525 case OP_ICONV_TO_U1:
3526 CASE_PPC64 (OP_LCONV_TO_U1)
3527 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3529 case OP_ICONV_TO_U2:
3530 CASE_PPC64 (OP_LCONV_TO_U2)
3531 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3535 CASE_PPC64 (OP_LCOMPARE)
3536 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3538 if (next && compare_opcode_is_unsigned (next->opcode))
3539 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3541 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3543 case OP_COMPARE_IMM:
3544 case OP_ICOMPARE_IMM:
3545 CASE_PPC64 (OP_LCOMPARE_IMM)
3546 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3548 if (next && compare_opcode_is_unsigned (next->opcode)) {
3549 if (ppc_is_uimm16 (ins->inst_imm)) {
3550 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3552 g_assert_not_reached ();
3555 if (ppc_is_imm16 (ins->inst_imm)) {
3556 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3558 g_assert_not_reached ();
3567 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3570 CASE_PPC64 (OP_LADD)
3571 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3575 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3578 if (ppc_is_imm16 (ins->inst_imm)) {
3579 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3581 g_assert_not_reached ();
3586 CASE_PPC64 (OP_LADD_IMM)
3587 if (ppc_is_imm16 (ins->inst_imm)) {
3588 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3590 g_assert_not_reached ();
3594 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3596 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3597 ppc_mfspr (code, ppc_r0, ppc_xer);
3598 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3599 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3601 case OP_IADD_OVF_UN:
3602 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3604 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3605 ppc_mfspr (code, ppc_r0, ppc_xer);
3606 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3607 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3610 CASE_PPC64 (OP_LSUB_OVF)
3611 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3613 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3614 ppc_mfspr (code, ppc_r0, ppc_xer);
3615 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3616 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3618 case OP_ISUB_OVF_UN:
3619 CASE_PPC64 (OP_LSUB_OVF_UN)
3620 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3622 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3623 ppc_mfspr (code, ppc_r0, ppc_xer);
3624 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3625 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3627 case OP_ADD_OVF_CARRY:
3628 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3630 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3631 ppc_mfspr (code, ppc_r0, ppc_xer);
3632 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3633 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3635 case OP_ADD_OVF_UN_CARRY:
3636 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3638 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3639 ppc_mfspr (code, ppc_r0, ppc_xer);
3640 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3641 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3643 case OP_SUB_OVF_CARRY:
3644 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3646 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3647 ppc_mfspr (code, ppc_r0, ppc_xer);
3648 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3649 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3651 case OP_SUB_OVF_UN_CARRY:
3652 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3654 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3655 ppc_mfspr (code, ppc_r0, ppc_xer);
3656 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3657 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3661 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3664 CASE_PPC64 (OP_LSUB)
3665 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3669 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3673 CASE_PPC64 (OP_LSUB_IMM)
3674 // we add the negated value
3675 if (ppc_is_imm16 (-ins->inst_imm))
3676 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3678 g_assert_not_reached ();
3682 g_assert (ppc_is_imm16 (ins->inst_imm));
3683 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3686 ppc_subfze (code, ins->dreg, ins->sreg1);
3689 CASE_PPC64 (OP_LAND)
3690 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3691 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3695 CASE_PPC64 (OP_LAND_IMM)
3696 if (!(ins->inst_imm & 0xffff0000)) {
3697 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3698 } else if (!(ins->inst_imm & 0xffff)) {
3699 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3701 g_assert_not_reached ();
3705 CASE_PPC64 (OP_LDIV) {
3706 guint8 *divisor_is_m1;
3707 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3709 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3710 divisor_is_m1 = code;
3711 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3712 ppc_lis (code, ppc_r0, 0x8000);
3713 #ifdef __mono_ppc64__
3714 if (ins->opcode == OP_LDIV)
3715 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3717 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3718 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3719 ppc_patch (divisor_is_m1, code);
3720 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3722 if (ins->opcode == OP_IDIV)
3723 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3724 #ifdef __mono_ppc64__
3726 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3728 ppc_mfspr (code, ppc_r0, ppc_xer);
3729 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3730 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3734 CASE_PPC64 (OP_LDIV_UN)
3735 if (ins->opcode == OP_IDIV_UN)
3736 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3737 #ifdef __mono_ppc64__
3739 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3741 ppc_mfspr (code, ppc_r0, ppc_xer);
3742 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3743 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3749 g_assert_not_reached ();
3752 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3756 CASE_PPC64 (OP_LOR_IMM)
3757 if (!(ins->inst_imm & 0xffff0000)) {
3758 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3759 } else if (!(ins->inst_imm & 0xffff)) {
3760 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3762 g_assert_not_reached ();
3766 CASE_PPC64 (OP_LXOR)
3767 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3771 CASE_PPC64 (OP_LXOR_IMM)
3772 if (!(ins->inst_imm & 0xffff0000)) {
3773 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3774 } else if (!(ins->inst_imm & 0xffff)) {
3775 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3777 g_assert_not_reached ();
3781 CASE_PPC64 (OP_LSHL)
3782 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3786 CASE_PPC64 (OP_LSHL_IMM)
3787 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3790 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3793 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3796 if (MASK_SHIFT_IMM (ins->inst_imm))
3797 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3799 ppc_mr (code, ins->dreg, ins->sreg1);
3802 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3805 CASE_PPC64 (OP_LNOT)
3806 ppc_not (code, ins->dreg, ins->sreg1);
3809 CASE_PPC64 (OP_LNEG)
3810 ppc_neg (code, ins->dreg, ins->sreg1);
3813 CASE_PPC64 (OP_LMUL)
3814 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3818 CASE_PPC64 (OP_LMUL_IMM)
3819 if (ppc_is_imm16 (ins->inst_imm)) {
3820 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3822 g_assert_not_reached ();
3826 CASE_PPC64 (OP_LMUL_OVF)
3827 /* we annot use mcrxr, since it's not implemented on some processors
3828 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3830 if (ins->opcode == OP_IMUL_OVF)
3831 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3832 #ifdef __mono_ppc64__
3834 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3836 ppc_mfspr (code, ppc_r0, ppc_xer);
3837 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3838 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3840 case OP_IMUL_OVF_UN:
3841 CASE_PPC64 (OP_LMUL_OVF_UN)
3842 /* we first multiply to get the high word and compare to 0
3843 * to set the flags, then the result is discarded and then
3844 * we multiply to get the lower * bits result
3846 if (ins->opcode == OP_IMUL_OVF_UN)
3847 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3848 #ifdef __mono_ppc64__
3850 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3852 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3853 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3854 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3857 ppc_load (code, ins->dreg, ins->inst_c0);
3860 ppc_load (code, ins->dreg, ins->inst_l);
3863 case OP_LOAD_GOTADDR:
3864 /* The PLT implementation depends on this */
3865 g_assert (ins->dreg == ppc_r30);
3867 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3870 // FIXME: Fix max instruction length
3871 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3872 /* arch_emit_got_access () patches this */
3873 ppc_load32 (code, ppc_r0, 0);
3874 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3877 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3878 ppc_load_sequence (code, ins->dreg, 0);
3880 CASE_PPC32 (OP_ICONV_TO_I4)
3881 CASE_PPC32 (OP_ICONV_TO_U4)
3883 ppc_mr (code, ins->dreg, ins->sreg1);
3886 int saved = ins->sreg1;
3887 if (ins->sreg1 == ppc_r3) {
3888 ppc_mr (code, ppc_r0, ins->sreg1);
3891 if (ins->sreg2 != ppc_r3)
3892 ppc_mr (code, ppc_r3, ins->sreg2);
3893 if (saved != ppc_r4)
3894 ppc_mr (code, ppc_r4, saved);
3898 ppc_fmr (code, ins->dreg, ins->sreg1);
3900 case OP_FCONV_TO_R4:
3901 ppc_frsp (code, ins->dreg, ins->sreg1);
3907 * Keep in sync with mono_arch_emit_epilog
3909 g_assert (!cfg->method->save_lmf);
3911 * Note: we can use ppc_r11 here because it is dead anyway:
3912 * we're leaving the method.
3914 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3915 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3916 if (ppc_is_imm16 (ret_offset)) {
3917 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3919 ppc_load (code, ppc_r11, ret_offset);
3920 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3922 ppc_mtlr (code, ppc_r0);
3925 code = emit_load_volatile_arguments (cfg, code);
3927 if (ppc_is_imm16 (cfg->stack_usage)) {
3928 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3930 /* cfg->stack_usage is an int, so we can use
3931 * an addis/addi sequence here even in 64-bit. */
3932 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3933 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3935 if (!cfg->method->save_lmf) {
3936 /*for (i = 31; i >= 14; --i) {
3937 if (cfg->used_float_regs & (1 << i)) {
3938 pos += sizeof (double);
3939 ppc_lfd (code, i, -pos, cfg->frame_reg);
3943 for (i = 31; i >= 13; --i) {
3944 if (cfg->used_int_regs & (1 << i)) {
3945 pos += sizeof (gpointer);
3946 ppc_ldptr (code, i, -pos, ppc_r11);
3950 /* FIXME restore from MonoLMF: though this can't happen yet */
3952 ppc_mr (code, ppc_sp, ppc_r11);
3953 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3954 if (cfg->compile_aot) {
3955 /* arch_emit_got_access () patches this */
3956 ppc_load32 (code, ppc_r0, 0);
3957 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3958 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3959 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3961 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3963 ppc_mtctr (code, ppc_r0);
3964 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3971 /* ensure ins->sreg1 is not NULL */
3972 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3975 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3976 if (ppc_is_imm16 (cookie_offset)) {
3977 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3979 ppc_load (code, ppc_r0, cookie_offset);
3980 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3982 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3991 call = (MonoCallInst*)ins;
3992 if (ins->flags & MONO_INST_HAS_METHOD)
3993 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3995 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3996 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3997 ppc_load_func (code, ppc_r0, 0);
3998 ppc_mtlr (code, ppc_r0);
4003 /* FIXME: this should be handled somewhere else in the new jit */
4004 code = emit_move_return_value (cfg, ins, code);
4010 case OP_VOIDCALL_REG:
4012 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4013 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4014 /* FIXME: if we know that this is a method, we
4015 can omit this load */
4016 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4017 ppc_mtlr (code, ppc_r0);
4019 ppc_mtlr (code, ins->sreg1);
4022 /* FIXME: this should be handled somewhere else in the new jit */
4023 code = emit_move_return_value (cfg, ins, code);
4025 case OP_FCALL_MEMBASE:
4026 case OP_LCALL_MEMBASE:
4027 case OP_VCALL_MEMBASE:
4028 case OP_VCALL2_MEMBASE:
4029 case OP_VOIDCALL_MEMBASE:
4030 case OP_CALL_MEMBASE:
4031 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
4032 /* The trampolines clobber this */
4033 ppc_mr (code, ppc_r29, ins->sreg1);
4034 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4036 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4038 ppc_mtlr (code, ppc_r0);
4040 /* FIXME: this should be handled somewhere else in the new jit */
4041 code = emit_move_return_value (cfg, ins, code);
4044 guint8 * zero_loop_jump, * zero_loop_start;
4045 /* keep alignment */
4046 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4047 int area_offset = alloca_waste;
4049 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
4050 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4051 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
4052 /* use ctr to store the number of words to 0 if needed */
4053 if (ins->flags & MONO_INST_INIT) {
4054 /* we zero 4 bytes at a time:
4055 * we add 7 instead of 3 so that we set the counter to
4056 * at least 1, otherwise the bdnz instruction will make
4057 * it negative and iterate billions of times.
4059 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4060 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4061 ppc_mtctr (code, ppc_r0);
4063 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4064 ppc_neg (code, ppc_r11, ppc_r11);
4065 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4067 /* FIXME: make this loop work in 8 byte
4068 increments on PPC64 */
4069 if (ins->flags & MONO_INST_INIT) {
4070 /* adjust the dest reg by -4 so we can use stwu */
4071 /* we actually adjust -8 because we let the loop
4074 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4075 ppc_li (code, ppc_r11, 0);
4076 zero_loop_start = code;
4077 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4078 zero_loop_jump = code;
4079 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4080 ppc_patch (zero_loop_jump, zero_loop_start);
4082 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4087 ppc_mr (code, ppc_r3, ins->sreg1);
4088 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4089 (gpointer)"mono_arch_throw_exception");
4090 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4091 ppc_load_func (code, ppc_r0, 0);
4092 ppc_mtlr (code, ppc_r0);
4101 ppc_mr (code, ppc_r3, ins->sreg1);
4102 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4103 (gpointer)"mono_arch_rethrow_exception");
4104 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4105 ppc_load_func (code, ppc_r0, 0);
4106 ppc_mtlr (code, ppc_r0);
4113 case OP_START_HANDLER: {
4114 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4115 g_assert (spvar->inst_basereg != ppc_sp);
4116 code = emit_reserve_param_area (cfg, code);
4117 ppc_mflr (code, ppc_r0);
4118 if (ppc_is_imm16 (spvar->inst_offset)) {
4119 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4121 ppc_load (code, ppc_r11, spvar->inst_offset);
4122 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4126 case OP_ENDFILTER: {
4127 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4128 g_assert (spvar->inst_basereg != ppc_sp);
4129 code = emit_unreserve_param_area (cfg, code);
4130 if (ins->sreg1 != ppc_r3)
4131 ppc_mr (code, ppc_r3, ins->sreg1);
4132 if (ppc_is_imm16 (spvar->inst_offset)) {
4133 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4135 ppc_load (code, ppc_r11, spvar->inst_offset);
4136 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4138 ppc_mtlr (code, ppc_r0);
4142 case OP_ENDFINALLY: {
4143 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4144 g_assert (spvar->inst_basereg != ppc_sp);
4145 code = emit_unreserve_param_area (cfg, code);
4146 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4147 ppc_mtlr (code, ppc_r0);
4151 case OP_CALL_HANDLER:
4152 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4154 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4157 ins->inst_c0 = code - cfg->native_code;
4160 /*if (ins->inst_target_bb->native_offset) {
4162 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4164 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4169 ppc_mtctr (code, ins->sreg1);
4170 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4174 CASE_PPC64 (OP_LCEQ)
4175 ppc_li (code, ins->dreg, 0);
4176 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4177 ppc_li (code, ins->dreg, 1);
4183 CASE_PPC64 (OP_LCLT)
4184 CASE_PPC64 (OP_LCLT_UN)
4185 ppc_li (code, ins->dreg, 1);
4186 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4187 ppc_li (code, ins->dreg, 0);
4193 CASE_PPC64 (OP_LCGT)
4194 CASE_PPC64 (OP_LCGT_UN)
4195 ppc_li (code, ins->dreg, 1);
4196 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4197 ppc_li (code, ins->dreg, 0);
4199 case OP_COND_EXC_EQ:
4200 case OP_COND_EXC_NE_UN:
4201 case OP_COND_EXC_LT:
4202 case OP_COND_EXC_LT_UN:
4203 case OP_COND_EXC_GT:
4204 case OP_COND_EXC_GT_UN:
4205 case OP_COND_EXC_GE:
4206 case OP_COND_EXC_GE_UN:
4207 case OP_COND_EXC_LE:
4208 case OP_COND_EXC_LE_UN:
4209 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4211 case OP_COND_EXC_IEQ:
4212 case OP_COND_EXC_INE_UN:
4213 case OP_COND_EXC_ILT:
4214 case OP_COND_EXC_ILT_UN:
4215 case OP_COND_EXC_IGT:
4216 case OP_COND_EXC_IGT_UN:
4217 case OP_COND_EXC_IGE:
4218 case OP_COND_EXC_IGE_UN:
4219 case OP_COND_EXC_ILE:
4220 case OP_COND_EXC_ILE_UN:
4221 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4233 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4236 /* floating point opcodes */
4238 g_assert (cfg->compile_aot);
4240 /* FIXME: Optimize this */
4242 ppc_mflr (code, ppc_r11);
4244 *(double*)code = *(double*)ins->inst_p0;
4246 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4249 g_assert_not_reached ();
4251 case OP_STORER8_MEMBASE_REG:
4252 if (ppc_is_imm16 (ins->inst_offset)) {
4253 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4255 if (ppc_is_imm32 (ins->inst_offset)) {
4256 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4257 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4259 ppc_load (code, ppc_r0, ins->inst_offset);
4260 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4264 case OP_LOADR8_MEMBASE:
4265 if (ppc_is_imm16 (ins->inst_offset)) {
4266 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4268 if (ppc_is_imm32 (ins->inst_offset)) {
4269 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4270 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4272 ppc_load (code, ppc_r0, ins->inst_offset);
4273 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4277 case OP_STORER4_MEMBASE_REG:
4278 ppc_frsp (code, ins->sreg1, ins->sreg1);
4279 if (ppc_is_imm16 (ins->inst_offset)) {
4280 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4282 if (ppc_is_imm32 (ins->inst_offset)) {
4283 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4284 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4286 ppc_load (code, ppc_r0, ins->inst_offset);
4287 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4291 case OP_LOADR4_MEMBASE:
4292 if (ppc_is_imm16 (ins->inst_offset)) {
4293 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4295 if (ppc_is_imm32 (ins->inst_offset)) {
4296 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4297 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4299 ppc_load (code, ppc_r0, ins->inst_offset);
4300 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4304 case OP_LOADR4_MEMINDEX:
4305 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4307 case OP_LOADR8_MEMINDEX:
4308 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4310 case OP_STORER4_MEMINDEX:
4311 ppc_frsp (code, ins->sreg1, ins->sreg1);
4312 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4314 case OP_STORER8_MEMINDEX:
4315 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4318 case CEE_CONV_R4: /* FIXME: change precision */
4320 g_assert_not_reached ();
4321 case OP_FCONV_TO_I1:
4322 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4324 case OP_FCONV_TO_U1:
4325 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4327 case OP_FCONV_TO_I2:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4330 case OP_FCONV_TO_U2:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4333 case OP_FCONV_TO_I4:
4335 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4337 case OP_FCONV_TO_U4:
4339 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4341 case OP_LCONV_TO_R_UN:
4342 g_assert_not_reached ();
4343 /* Implemented as helper calls */
4345 case OP_LCONV_TO_OVF_I4_2:
4346 case OP_LCONV_TO_OVF_I: {
4347 #ifdef __mono_ppc64__
4350 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4351 // Check if its negative
4352 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4353 negative_branch = code;
4354 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4355 // Its positive msword == 0
4356 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4357 msword_positive_branch = code;
4358 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4360 ovf_ex_target = code;
4361 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4363 ppc_patch (negative_branch, code);
4364 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4365 msword_negative_branch = code;
4366 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4367 ppc_patch (msword_negative_branch, ovf_ex_target);
4369 ppc_patch (msword_positive_branch, code);
4370 if (ins->dreg != ins->sreg1)
4371 ppc_mr (code, ins->dreg, ins->sreg1);
4376 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4379 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4382 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4385 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4388 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4391 ppc_fneg (code, ins->dreg, ins->sreg1);
4395 g_assert_not_reached ();
4398 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4401 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4402 ppc_li (code, ins->dreg, 0);
4403 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4404 ppc_li (code, ins->dreg, 1);
4407 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4408 ppc_li (code, ins->dreg, 1);
4409 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4410 ppc_li (code, ins->dreg, 0);
4413 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4414 ppc_li (code, ins->dreg, 1);
4415 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4416 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4417 ppc_li (code, ins->dreg, 0);
4420 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4421 ppc_li (code, ins->dreg, 1);
4422 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4423 ppc_li (code, ins->dreg, 0);
4426 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 1);
4428 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4429 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4430 ppc_li (code, ins->dreg, 0);
4433 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4436 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4439 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4440 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4443 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4444 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4447 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4448 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4451 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4452 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4455 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4456 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4459 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4462 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4463 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4466 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4469 g_assert_not_reached ();
4470 case OP_CHECK_FINITE: {
4471 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4472 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4473 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4474 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4477 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4478 #ifdef __mono_ppc64__
4479 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4481 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4486 #ifdef __mono_ppc64__
4487 case OP_ICONV_TO_I4:
4489 ppc_extsw (code, ins->dreg, ins->sreg1);
4491 case OP_ICONV_TO_U4:
4493 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4495 case OP_ICONV_TO_R4:
4496 case OP_ICONV_TO_R8:
4497 case OP_LCONV_TO_R4:
4498 case OP_LCONV_TO_R8: {
4500 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4501 ppc_extsw (code, ppc_r0, ins->sreg1);
4506 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4507 ppc_mffgpr (code, ins->dreg, tmp);
4509 ppc_str (code, tmp, -8, ppc_r1);
4510 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4512 ppc_fcfid (code, ins->dreg, ins->dreg);
4513 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4514 ppc_frsp (code, ins->dreg, ins->dreg);
4518 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4521 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4524 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4526 ppc_mfspr (code, ppc_r0, ppc_xer);
4527 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4528 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4530 case OP_COND_EXC_OV:
4531 ppc_mfspr (code, ppc_r0, ppc_xer);
4532 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4533 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4545 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4547 case OP_FCONV_TO_I8:
4548 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4550 case OP_FCONV_TO_U8:
4551 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4553 case OP_STOREI4_MEMBASE_REG:
4554 if (ppc_is_imm16 (ins->inst_offset)) {
4555 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4557 ppc_load (code, ppc_r0, ins->inst_offset);
4558 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4561 case OP_STOREI4_MEMINDEX:
4562 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4565 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4567 case OP_ISHR_UN_IMM:
4568 if (ins->inst_imm & 0x1f)
4569 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4571 ppc_mr (code, ins->dreg, ins->sreg1);
4573 case OP_ATOMIC_ADD_NEW_I4:
4574 case OP_ATOMIC_ADD_NEW_I8: {
4575 guint8 *loop = code, *branch;
4576 g_assert (ins->inst_offset == 0);
4577 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4578 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4580 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4581 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4582 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4583 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4585 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4587 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4588 ppc_patch (branch, loop);
4589 ppc_mr (code, ins->dreg, ppc_r0);
4593 case OP_ICONV_TO_R4:
4594 case OP_ICONV_TO_R8: {
4595 if (cpu_hw_caps & PPC_ISA_64) {
4596 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4597 ppc_stw (code, ppc_r0, -8, ppc_r1);
4598 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4599 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4600 ppc_fcfid (code, ins->dreg, ins->dreg);
4601 if (ins->opcode == OP_ICONV_TO_R4)
4602 ppc_frsp (code, ins->dreg, ins->dreg);
4607 case OP_ATOMIC_CAS_I4:
4608 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4609 int location = ins->sreg1;
4610 int value = ins->sreg2;
4611 int comparand = ins->sreg3;
4612 guint8 *start, *not_equal, *lost_reservation;
4615 if (ins->opcode == OP_ATOMIC_CAS_I4)
4616 ppc_lwarx (code, ppc_r0, 0, location);
4617 #ifdef __mono_ppc64__
4619 ppc_ldarx (code, ppc_r0, 0, location);
4621 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4624 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4625 if (ins->opcode == OP_ATOMIC_CAS_I4)
4626 ppc_stwcxd (code, value, 0, location);
4627 #ifdef __mono_ppc64__
4629 ppc_stdcxd (code, value, 0, location);
4632 lost_reservation = code;
4633 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4634 ppc_patch (lost_reservation, start);
4636 ppc_patch (not_equal, code);
4637 ppc_mr (code, ins->dreg, ppc_r0);
4642 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4643 g_assert_not_reached ();
4646 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4647 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4648 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4649 g_assert_not_reached ();
4655 last_offset = offset;
4658 cfg->code_len = code - cfg->native_code;
4660 #endif /* !DISABLE_JIT */
4663 mono_arch_register_lowlevel_calls (void)
4665 /* The signature doesn't matter */
4666 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4669 #ifdef __mono_ppc64__
4670 #define patch_load_sequence(ip,val) do {\
4671 guint16 *__load = (guint16*)(ip); \
4672 g_assert (sizeof (val) == sizeof (gsize)); \
4673 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4674 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4675 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4676 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4679 #define patch_load_sequence(ip,val) do {\
4680 guint16 *__lis_ori = (guint16*)(ip); \
4681 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4682 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4688 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4690 MonoJumpInfo *patch_info;
4691 gboolean compile_aot = !run_cctors;
4693 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4694 unsigned char *ip = patch_info->ip.i + code;
4695 unsigned char *target;
4696 gboolean is_fd = FALSE;
4698 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4701 switch (patch_info->type) {
4702 case MONO_PATCH_INFO_BB:
4703 case MONO_PATCH_INFO_LABEL:
4706 /* No need to patch these */
4711 switch (patch_info->type) {
4712 case MONO_PATCH_INFO_IP:
4713 patch_load_sequence (ip, ip);
4715 case MONO_PATCH_INFO_METHOD_REL:
4716 g_assert_not_reached ();
4717 *((gpointer *)(ip)) = code + patch_info->data.offset;
4719 case MONO_PATCH_INFO_SWITCH: {
4720 gpointer *table = (gpointer *)patch_info->data.table->table;
4723 patch_load_sequence (ip, table);
4725 for (i = 0; i < patch_info->data.table->table_size; i++) {
4726 table [i] = (glong)patch_info->data.table->table [i] + code;
4728 /* we put into the table the absolute address, no need for ppc_patch in this case */
4731 case MONO_PATCH_INFO_METHODCONST:
4732 case MONO_PATCH_INFO_CLASS:
4733 case MONO_PATCH_INFO_IMAGE:
4734 case MONO_PATCH_INFO_FIELD:
4735 case MONO_PATCH_INFO_VTABLE:
4736 case MONO_PATCH_INFO_IID:
4737 case MONO_PATCH_INFO_SFLDA:
4738 case MONO_PATCH_INFO_LDSTR:
4739 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4740 case MONO_PATCH_INFO_LDTOKEN:
4741 /* from OP_AOTCONST : lis + ori */
4742 patch_load_sequence (ip, target);
4744 case MONO_PATCH_INFO_R4:
4745 case MONO_PATCH_INFO_R8:
4746 g_assert_not_reached ();
4747 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4749 case MONO_PATCH_INFO_EXC_NAME:
4750 g_assert_not_reached ();
4751 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4753 case MONO_PATCH_INFO_NONE:
4754 case MONO_PATCH_INFO_BB_OVF:
4755 case MONO_PATCH_INFO_EXC_OVF:
4756 /* everything is dealt with at epilog output time */
4758 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4759 case MONO_PATCH_INFO_INTERNAL_METHOD:
4760 case MONO_PATCH_INFO_ABS:
4761 case MONO_PATCH_INFO_CLASS_INIT:
4762 case MONO_PATCH_INFO_RGCTX_FETCH:
4769 ppc_patch_full (ip, target, is_fd);
4774 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4775 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4776 * the instruction offset immediate for all the registers.
4779 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4783 for (i = 13; i <= 31; i++) {
4784 if (used_int_regs & (1 << i)) {
4785 ppc_str (code, i, pos, base_reg);
4786 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4787 pos += sizeof (mgreg_t);
4791 /* pos is the start of the MonoLMF structure */
4792 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4793 for (i = 13; i <= 31; i++) {
4794 ppc_str (code, i, offset, base_reg);
4795 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4796 offset += sizeof (mgreg_t);
4798 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4799 for (i = 14; i < 32; i++) {
4800 ppc_stfd (code, i, offset, base_reg);
4801 offset += sizeof (gdouble);
4808 * Stack frame layout:
4810 * ------------------- sp
4811 * MonoLMF structure or saved registers
4812 * -------------------
4814 * -------------------
4816 * -------------------
4817 * optional 8 bytes for tracing
4818 * -------------------
4819 * param area size is cfg->param_area
4820 * -------------------
4821 * linkage area size is PPC_STACK_PARAM_OFFSET
4822 * ------------------- sp
4826 mono_arch_emit_prolog (MonoCompile *cfg)
4828 MonoMethod *method = cfg->method;
4830 MonoMethodSignature *sig;
4832 long alloc_size, pos, max_offset, cfa_offset;
4838 int tailcall_struct_index;
4840 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4843 sig = mono_method_signature (method);
4844 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4845 code = cfg->native_code = g_malloc (cfg->code_size);
4849 /* We currently emit unwind info for aot, but don't use it */
4850 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4852 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4853 ppc_mflr (code, ppc_r0);
4854 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4855 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4858 alloc_size = cfg->stack_offset;
4861 if (!method->save_lmf) {
4862 for (i = 31; i >= 13; --i) {
4863 if (cfg->used_int_regs & (1 << i)) {
4864 pos += sizeof (mgreg_t);
4868 pos += sizeof (MonoLMF);
4872 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4873 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4874 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4875 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4878 cfg->stack_usage = alloc_size;
4879 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4881 if (ppc_is_imm16 (-alloc_size)) {
4882 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4883 cfa_offset = alloc_size;
4884 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4885 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4888 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4889 ppc_load (code, ppc_r0, -alloc_size);
4890 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4891 cfa_offset = alloc_size;
4892 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4893 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4896 if (cfg->frame_reg != ppc_sp) {
4897 ppc_mr (code, cfg->frame_reg, ppc_sp);
4898 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4901 /* store runtime generic context */
4902 if (cfg->rgctx_var) {
4903 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4904 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4906 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4909 /* compute max_offset in order to use short forward jumps
4910 * we always do it on ppc because the immediate displacement
4911 * for jumps is too small
4914 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4916 bb->max_offset = max_offset;
4918 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4921 MONO_BB_FOR_EACH_INS (bb, ins)
4922 max_offset += ins_native_length (cfg, ins);
4925 /* load arguments allocated to register from the stack */
4928 cinfo = calculate_sizes (sig, sig->pinvoke);
4930 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4931 ArgInfo *ainfo = &cinfo->ret;
4933 inst = cfg->vret_addr;
4936 if (ppc_is_imm16 (inst->inst_offset)) {
4937 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4939 ppc_load (code, ppc_r11, inst->inst_offset);
4940 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4944 tailcall_struct_index = 0;
4945 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4946 ArgInfo *ainfo = cinfo->args + i;
4947 inst = cfg->args [pos];
4949 if (cfg->verbose_level > 2)
4950 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4951 if (inst->opcode == OP_REGVAR) {
4952 if (ainfo->regtype == RegTypeGeneral)
4953 ppc_mr (code, inst->dreg, ainfo->reg);
4954 else if (ainfo->regtype == RegTypeFP)
4955 ppc_fmr (code, inst->dreg, ainfo->reg);
4956 else if (ainfo->regtype == RegTypeBase) {
4957 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4958 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4960 g_assert_not_reached ();
4962 if (cfg->verbose_level > 2)
4963 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4965 /* the argument should be put on the stack: FIXME handle size != word */
4966 if (ainfo->regtype == RegTypeGeneral) {
4967 switch (ainfo->size) {
4969 if (ppc_is_imm16 (inst->inst_offset)) {
4970 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4972 if (ppc_is_imm32 (inst->inst_offset)) {
4973 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4974 ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
4976 ppc_load (code, ppc_r11, inst->inst_offset);
4977 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4982 if (ppc_is_imm16 (inst->inst_offset)) {
4983 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4985 if (ppc_is_imm32 (inst->inst_offset)) {
4986 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4987 ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
4989 ppc_load (code, ppc_r11, inst->inst_offset);
4990 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4994 #ifdef __mono_ppc64__
4996 if (ppc_is_imm16 (inst->inst_offset)) {
4997 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4999 if (ppc_is_imm32 (inst->inst_offset)) {
5000 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5001 ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
5003 ppc_load (code, ppc_r11, inst->inst_offset);
5004 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5009 if (ppc_is_imm16 (inst->inst_offset)) {
5010 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5012 ppc_load (code, ppc_r11, inst->inst_offset);
5013 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
5018 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5019 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5020 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5022 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5023 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5024 ppc_stw (code, ainfo->reg, 0, ppc_r11);
5025 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
5030 if (ppc_is_imm16 (inst->inst_offset)) {
5031 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5033 if (ppc_is_imm32 (inst->inst_offset)) {
5034 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5035 ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
5037 ppc_load (code, ppc_r11, inst->inst_offset);
5038 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5043 } else if (ainfo->regtype == RegTypeBase) {
5044 g_assert (ppc_is_imm16 (ainfo->offset));
5045 /* load the previous stack pointer in r11 */
5046 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5047 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
5048 switch (ainfo->size) {
5050 if (ppc_is_imm16 (inst->inst_offset)) {
5051 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5053 if (ppc_is_imm32 (inst->inst_offset)) {
5054 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5055 ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
5057 ppc_load (code, ppc_r11, inst->inst_offset);
5058 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5063 if (ppc_is_imm16 (inst->inst_offset)) {
5064 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5066 if (ppc_is_imm32 (inst->inst_offset)) {
5067 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5068 ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
5070 ppc_load (code, ppc_r11, inst->inst_offset);
5071 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5075 #ifdef __mono_ppc64__
5077 if (ppc_is_imm16 (inst->inst_offset)) {
5078 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5080 if (ppc_is_imm32 (inst->inst_offset)) {
5081 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5082 ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
5084 ppc_load (code, ppc_r11, inst->inst_offset);
5085 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5090 if (ppc_is_imm16 (inst->inst_offset)) {
5091 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5093 ppc_load (code, ppc_r11, inst->inst_offset);
5094 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
5099 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5100 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5101 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5102 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5103 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5105 /* use r12 to load the 2nd half of the long before we clobber r11. */
5106 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5107 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5108 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5109 ppc_stw (code, ppc_r0, 0, ppc_r11);
5110 ppc_stw (code, ppc_r12, 4, ppc_r11);
5115 if (ppc_is_imm16 (inst->inst_offset)) {
5116 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5118 if (ppc_is_imm32 (inst->inst_offset)) {
5119 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5120 ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
5122 ppc_load (code, ppc_r11, inst->inst_offset);
5123 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5128 } else if (ainfo->regtype == RegTypeFP) {
5129 g_assert (ppc_is_imm16 (inst->inst_offset));
5130 if (ainfo->size == 8)
5131 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5132 else if (ainfo->size == 4)
5133 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5135 g_assert_not_reached ();
5136 } else if (ainfo->regtype == RegTypeStructByVal) {
5137 int doffset = inst->inst_offset;
5141 g_assert (ppc_is_imm16 (inst->inst_offset));
5142 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5143 /* FIXME: what if there is no class? */
5144 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5145 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5146 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5149 * Darwin handles 1 and 2 byte
5150 * structs specially by
5151 * loading h/b into the arg
5152 * register. Only done for
5156 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5158 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5162 #ifdef __mono_ppc64__
5164 g_assert (cur_reg == 0);
5165 ppc_sldi (code, ppc_r0, ainfo->reg,
5166 (sizeof (gpointer) - ainfo->bytes) * 8);
5167 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5171 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5172 inst->inst_basereg);
5175 soffset += sizeof (gpointer);
5176 doffset += sizeof (gpointer);
5178 if (ainfo->vtsize) {
5179 /* FIXME: we need to do the shifting here, too */
5182 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5183 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5184 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5185 code = emit_memcpy (code, size - soffset,
5186 inst->inst_basereg, doffset,
5187 ppc_r11, ainfo->offset + soffset);
5189 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5190 inst->inst_basereg, doffset,
5191 ppc_r11, ainfo->offset + soffset);
5194 } else if (ainfo->regtype == RegTypeStructByAddr) {
5195 /* if it was originally a RegTypeBase */
5196 if (ainfo->offset) {
5197 /* load the previous stack pointer in r11 */
5198 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5199 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5201 ppc_mr (code, ppc_r11, ainfo->reg);
5204 if (cfg->tailcall_valuetype_addrs) {
5205 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5207 g_assert (ppc_is_imm16 (addr->inst_offset));
5208 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5210 tailcall_struct_index++;
5213 g_assert (ppc_is_imm16 (inst->inst_offset));
5214 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5215 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5217 g_assert_not_reached ();
5222 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5223 if (cfg->compile_aot)
5224 /* AOT code is only used in the root domain */
5225 ppc_load_ptr (code, ppc_r3, 0);
5227 ppc_load_ptr (code, ppc_r3, cfg->domain);
5228 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5229 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5230 ppc_load_func (code, ppc_r0, 0);
5231 ppc_mtlr (code, ppc_r0);
5238 if (method->save_lmf) {
5239 if (lmf_pthread_key != -1) {
5240 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5241 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5242 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5244 if (cfg->compile_aot) {
5245 /* Compute the got address which is needed by the PLT entry */
5246 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5248 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5249 (gpointer)"mono_get_lmf_addr");
5250 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5251 ppc_load_func (code, ppc_r0, 0);
5252 ppc_mtlr (code, ppc_r0);
5258 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5259 /* lmf_offset is the offset from the previous stack pointer,
5260 * alloc_size is the total stack space allocated, so the offset
5261 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5262 * The pointer to the struct is put in ppc_r11 (new_lmf).
5263 * The callee-saved registers are already in the MonoLMF structure
5265 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5266 /* ppc_r3 is the result from mono_get_lmf_addr () */
5267 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5268 /* new_lmf->previous_lmf = *lmf_addr */
5269 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5270 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5271 /* *(lmf_addr) = r11 */
5272 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5273 /* save method info */
5274 if (cfg->compile_aot)
5276 ppc_load (code, ppc_r0, 0);
5278 ppc_load_ptr (code, ppc_r0, method);
5279 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5280 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5281 /* save the current IP */
5282 if (cfg->compile_aot) {
5284 ppc_mflr (code, ppc_r0);
5286 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5287 #ifdef __mono_ppc64__
5288 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5290 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5293 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5297 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5299 cfg->code_len = code - cfg->native_code;
5300 g_assert (cfg->code_len <= cfg->code_size);
5307 mono_arch_emit_epilog (MonoCompile *cfg)
5309 MonoMethod *method = cfg->method;
5311 int max_epilog_size = 16 + 20*4;
5314 if (cfg->method->save_lmf)
5315 max_epilog_size += 128;
5317 if (mono_jit_trace_calls != NULL)
5318 max_epilog_size += 50;
5320 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5321 max_epilog_size += 50;
5323 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5324 cfg->code_size *= 2;
5325 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5326 mono_jit_stats.code_reallocs++;
5330 * Keep in sync with OP_JMP
5332 code = cfg->native_code + cfg->code_len;
5334 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5335 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5339 if (method->save_lmf) {
5341 pos += sizeof (MonoLMF);
5343 /* save the frame reg in r8 */
5344 ppc_mr (code, ppc_r8, cfg->frame_reg);
5345 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5346 /* r5 = previous_lmf */
5347 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5349 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5350 /* *(lmf_addr) = previous_lmf */
5351 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5352 /* FIXME: speedup: there is no actual need to restore the registers if
5353 * we didn't actually change them (idea from Zoltan).
5356 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5358 /*for (i = 14; i < 32; i++) {
5359 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5361 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5362 /* use the saved copy of the frame reg in r8 */
5363 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5364 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5365 ppc_mtlr (code, ppc_r0);
5367 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5369 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5370 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5371 if (ppc_is_imm16 (return_offset)) {
5372 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5374 ppc_load (code, ppc_r11, return_offset);
5375 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5377 ppc_mtlr (code, ppc_r0);
5379 if (ppc_is_imm16 (cfg->stack_usage)) {
5380 int offset = cfg->stack_usage;
5381 for (i = 13; i <= 31; i++) {
5382 if (cfg->used_int_regs & (1 << i))
5383 offset -= sizeof (mgreg_t);
5385 if (cfg->frame_reg != ppc_sp)
5386 ppc_mr (code, ppc_r11, cfg->frame_reg);
5387 /* note r31 (possibly the frame register) is restored last */
5388 for (i = 13; i <= 31; i++) {
5389 if (cfg->used_int_regs & (1 << i)) {
5390 ppc_ldr (code, i, offset, cfg->frame_reg);
5391 offset += sizeof (mgreg_t);
5394 if (cfg->frame_reg != ppc_sp)
5395 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5397 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5399 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5400 if (cfg->used_int_regs) {
5401 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5402 for (i = 31; i >= 13; --i) {
5403 if (cfg->used_int_regs & (1 << i)) {
5404 pos += sizeof (mgreg_t);
5405 ppc_ldr (code, i, -pos, ppc_r11);
5408 ppc_mr (code, ppc_sp, ppc_r11);
5410 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5417 cfg->code_len = code - cfg->native_code;
5419 g_assert (cfg->code_len < cfg->code_size);
5422 #endif /* ifndef DISABLE_JIT */
5424 /* remove once throw_exception_by_name is eliminated */
5426 exception_id_by_name (const char *name)
5428 if (strcmp (name, "IndexOutOfRangeException") == 0)
5429 return MONO_EXC_INDEX_OUT_OF_RANGE;
5430 if (strcmp (name, "OverflowException") == 0)
5431 return MONO_EXC_OVERFLOW;
5432 if (strcmp (name, "ArithmeticException") == 0)
5433 return MONO_EXC_ARITHMETIC;
5434 if (strcmp (name, "DivideByZeroException") == 0)
5435 return MONO_EXC_DIVIDE_BY_ZERO;
5436 if (strcmp (name, "InvalidCastException") == 0)
5437 return MONO_EXC_INVALID_CAST;
5438 if (strcmp (name, "NullReferenceException") == 0)
5439 return MONO_EXC_NULL_REF;
5440 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5441 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5442 g_error ("Unknown intrinsic exception %s\n", name);
5448 mono_arch_emit_exceptions (MonoCompile *cfg)
5450 MonoJumpInfo *patch_info;
5453 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5454 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5455 int max_epilog_size = 50;
5457 /* count the number of exception infos */
5460 * make sure we have enough space for exceptions
5462 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5463 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5464 i = exception_id_by_name (patch_info->data.target);
5465 if (!exc_throw_found [i]) {
5466 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5467 exc_throw_found [i] = TRUE;
5469 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5470 max_epilog_size += 12;
5471 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5472 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5473 i = exception_id_by_name (ovfj->data.exception);
5474 if (!exc_throw_found [i]) {
5475 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5476 exc_throw_found [i] = TRUE;
5478 max_epilog_size += 8;
5482 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5483 cfg->code_size *= 2;
5484 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5485 mono_jit_stats.code_reallocs++;
5488 code = cfg->native_code + cfg->code_len;
5490 /* add code to raise exceptions */
5491 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5492 switch (patch_info->type) {
5493 case MONO_PATCH_INFO_BB_OVF: {
5494 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5495 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5496 /* patch the initial jump */
5497 ppc_patch (ip, code);
5498 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5500 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5501 /* jump back to the true target */
5503 ip = ovfj->data.bb->native_offset + cfg->native_code;
5504 ppc_patch (code - 4, ip);
5505 patch_info->type = MONO_PATCH_INFO_NONE;
5508 case MONO_PATCH_INFO_EXC_OVF: {
5509 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5510 MonoJumpInfo *newji;
5511 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5512 unsigned char *bcl = code;
5513 /* patch the initial jump: we arrived here with a call */
5514 ppc_patch (ip, code);
5515 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5517 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5518 /* patch the conditional jump to the right handler */
5519 /* make it processed next */
5520 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5521 newji->type = MONO_PATCH_INFO_EXC;
5522 newji->ip.i = bcl - cfg->native_code;
5523 newji->data.target = ovfj->data.exception;
5524 newji->next = patch_info->next;
5525 patch_info->next = newji;
5526 patch_info->type = MONO_PATCH_INFO_NONE;
5529 case MONO_PATCH_INFO_EXC: {
5530 MonoClass *exc_class;
5532 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5533 i = exception_id_by_name (patch_info->data.target);
5534 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5535 ppc_patch (ip, exc_throw_pos [i]);
5536 patch_info->type = MONO_PATCH_INFO_NONE;
5539 exc_throw_pos [i] = code;
5542 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5543 g_assert (exc_class);
5545 ppc_patch (ip, code);
5546 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5547 ppc_load (code, ppc_r3, exc_class->type_token);
5548 /* we got here from a conditional call, so the calling ip is set in lr */
5549 ppc_mflr (code, ppc_r4);
5550 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5551 patch_info->data.name = "mono_arch_throw_corlib_exception";
5552 patch_info->ip.i = code - cfg->native_code;
5553 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5554 ppc_load_func (code, ppc_r0, 0);
5555 ppc_mtctr (code, ppc_r0);
5556 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5568 cfg->code_len = code - cfg->native_code;
5570 g_assert (cfg->code_len <= cfg->code_size);
5576 try_offset_access (void *value, guint32 idx)
5578 register void* me __asm__ ("r2");
5579 void ***p = (void***)((char*)me + 284);
5580 int idx1 = idx / 32;
5581 int idx2 = idx % 32;
5584 if (value != p[idx1][idx2])
5591 setup_tls_access (void)
5595 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5596 size_t conf_size = 0;
5599 /* FIXME for darwin */
5600 guint32 *ins, *code;
5601 guint32 cmplwi_1023, li_0x48, blr_ins;
5605 tls_mode = TLS_MODE_FAILED;
5608 if (tls_mode == TLS_MODE_FAILED)
5610 if (g_getenv ("MONO_NO_TLS")) {
5611 tls_mode = TLS_MODE_FAILED;
5615 if (tls_mode == TLS_MODE_DETECT) {
5616 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5617 tls_mode = TLS_MODE_DARWIN_G4;
5618 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5619 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5620 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5621 tls_mode = TLS_MODE_NPTL;
5622 #elif !defined(TARGET_PS3)
5623 ins = (guint32*)pthread_getspecific;
5624 /* uncond branch to the real method */
5625 if ((*ins >> 26) == 18) {
5627 val = (*ins & ~3) << 6;
5631 ins = (guint32*)(long)val;
5633 ins = (guint32*) ((char*)ins + val);
5636 code = &cmplwi_1023;
5637 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5639 ppc_li (code, ppc_r4, 0x48);
5642 if (*ins == cmplwi_1023) {
5643 int found_lwz_284 = 0;
5644 for (ptk = 0; ptk < 20; ++ptk) {
5646 if (!*ins || *ins == blr_ins)
5648 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5653 if (!found_lwz_284) {
5654 tls_mode = TLS_MODE_FAILED;
5657 tls_mode = TLS_MODE_LTHREADS;
5658 } else if (*ins == li_0x48) {
5660 /* uncond branch to the real method */
5661 if ((*ins >> 26) == 18) {
5663 val = (*ins & ~3) << 6;
5667 ins = (guint32*)(long)val;
5669 ins = (guint32*) ((char*)ins + val);
5671 code = (guint32*)&val;
5672 ppc_li (code, ppc_r0, 0x7FF2);
5673 if (ins [1] == val) {
5674 /* Darwin on G4, implement */
5675 tls_mode = TLS_MODE_FAILED;
5678 code = (guint32*)&val;
5679 ppc_mfspr (code, ppc_r3, 104);
5680 if (ins [1] != val) {
5681 tls_mode = TLS_MODE_FAILED;
5684 tls_mode = TLS_MODE_DARWIN_G5;
5687 tls_mode = TLS_MODE_FAILED;
5691 tls_mode = TLS_MODE_FAILED;
5697 if (tls_mode == TLS_MODE_DETECT)
5698 tls_mode = TLS_MODE_FAILED;
5699 if (tls_mode == TLS_MODE_FAILED)
5701 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5702 monodomain_key = mono_domain_get_tls_offset();
5704 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5705 mono_domain_get_tls_offset returning -1) then use keyed access. */
5706 if (monodomain_key == -1) {
5707 ptk = mono_domain_get_tls_key ();
5709 ptk = mono_pthread_key_for_tls (ptk);
5711 monodomain_key = ptk;
5716 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5717 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5719 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5720 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5721 if (lmf_pthread_key == -1) {
5722 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5724 /*g_print ("MonoLMF at: %d\n", ptk);*/
5725 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5726 init_tls_failed = 1;
5729 lmf_pthread_key = ptk;
5736 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5738 setup_tls_access ();
5742 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5746 #ifdef MONO_ARCH_HAVE_IMT
5748 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5750 #define LOADSTORE_SIZE 4
5751 #define JUMP_IMM_SIZE 12
5752 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5753 #define ENABLE_WRONG_METHOD_CHECK 0
5756 * LOCKING: called with the domain lock held
5759 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5760 gpointer fail_tramp)
5764 guint8 *code, *start;
5766 for (i = 0; i < count; ++i) {
5767 MonoIMTCheckItem *item = imt_entries [i];
5768 if (item->is_equals) {
5769 if (item->check_target_idx) {
5770 if (!item->compare_done)
5771 item->chunk_size += CMP_SIZE;
5772 if (item->has_target_code)
5773 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5775 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5778 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5779 if (!item->has_target_code)
5780 item->chunk_size += LOADSTORE_SIZE;
5782 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5783 #if ENABLE_WRONG_METHOD_CHECK
5784 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5789 item->chunk_size += CMP_SIZE + BR_SIZE;
5790 imt_entries [item->check_target_idx]->compare_done = TRUE;
5792 size += item->chunk_size;
5794 /* the initial load of the vtable address */
5795 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5797 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5799 code = mono_domain_code_reserve (domain, size);
5804 * We need to save and restore r11 because it might be
5805 * used by the caller as the vtable register, so
5806 * clobbering it will trip up the magic trampoline.
5808 * FIXME: Get rid of this by making sure that r11 is
5809 * not used as the vtable register in interface calls.
5811 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5812 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5814 for (i = 0; i < count; ++i) {
5815 MonoIMTCheckItem *item = imt_entries [i];
5816 item->code_target = code;
5817 if (item->is_equals) {
5818 if (item->check_target_idx) {
5819 if (!item->compare_done) {
5820 ppc_load (code, ppc_r0, (gsize)item->key);
5821 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5823 item->jmp_code = code;
5824 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5825 if (item->has_target_code) {
5826 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5828 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5829 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5831 ppc_mtctr (code, ppc_r0);
5832 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5835 ppc_load (code, ppc_r0, (gulong)item->key);
5836 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5837 item->jmp_code = code;
5838 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5839 if (item->has_target_code) {
5840 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5843 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5844 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5846 ppc_mtctr (code, ppc_r0);
5847 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5848 ppc_patch (item->jmp_code, code);
5849 ppc_load_ptr (code, ppc_r0, fail_tramp);
5850 ppc_mtctr (code, ppc_r0);
5851 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5852 item->jmp_code = NULL;
5854 /* enable the commented code to assert on wrong method */
5855 #if ENABLE_WRONG_METHOD_CHECK
5856 ppc_load (code, ppc_r0, (guint32)item->key);
5857 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5858 item->jmp_code = code;
5859 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5861 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5862 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5863 ppc_mtctr (code, ppc_r0);
5864 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5865 #if ENABLE_WRONG_METHOD_CHECK
5866 ppc_patch (item->jmp_code, code);
5868 item->jmp_code = NULL;
5873 ppc_load (code, ppc_r0, (gulong)item->key);
5874 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5875 item->jmp_code = code;
5876 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5879 /* patch the branches to get to the target items */
5880 for (i = 0; i < count; ++i) {
5881 MonoIMTCheckItem *item = imt_entries [i];
5882 if (item->jmp_code) {
5883 if (item->check_target_idx) {
5884 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5890 mono_stats.imt_thunks_size += code - start;
5891 g_assert (code - start <= size);
5892 mono_arch_flush_icache (start, size);
5897 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5899 mgreg_t *r = (mgreg_t*)regs;
5901 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5906 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5908 mgreg_t *r = (mgreg_t*)regs;
5910 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5914 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5921 mono_arch_print_tree (MonoInst *tree, int arity)
5926 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5930 setup_tls_access ();
5931 if (monodomain_key == -1)
5934 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5935 ins->inst_offset = monodomain_key;
5940 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5943 return MONO_CONTEXT_GET_SP (ctx);
5945 g_assert (reg >= ppc_r13);
5947 return (gpointer)(gsize)ctx->regs [reg - ppc_r13];
5951 mono_arch_get_patch_offset (guint8 *code)
5957 * mono_aot_emit_load_got_addr:
5959 * Emit code to load the got address.
5960 * On PPC, the result is placed into r30.
5963 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5966 ppc_mflr (code, ppc_r30);
5968 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5970 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5971 /* arch_emit_got_address () patches this */
5972 #if defined(TARGET_POWERPC64)
5978 ppc_load32 (code, ppc_r0, 0);
5979 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5986 * mono_ppc_emit_load_aotconst:
5988 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5989 * TARGET from the mscorlib GOT in full-aot code.
5990 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5994 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5996 /* Load the mscorlib got address */
5997 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5998 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5999 /* arch_emit_got_access () patches this */
6000 ppc_load32 (code, ppc_r0, 0);
6001 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
6006 /* Soft Debug support */
6007 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6014 * mono_arch_set_breakpoint:
6016 * See mini-amd64.c for docs.
6019 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6022 guint8 *orig_code = code;
6024 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
6025 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
6027 g_assert (code - orig_code == BREAKPOINT_SIZE);
6029 mono_arch_flush_icache (orig_code, code - orig_code);
6033 * mono_arch_clear_breakpoint:
6035 * See mini-amd64.c for docs.
6038 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6043 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6046 mono_arch_flush_icache (ip, code - ip);
6050 * mono_arch_is_breakpoint_event:
6052 * See mini-amd64.c for docs.
6055 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6057 siginfo_t* sinfo = (siginfo_t*) info;
6058 /* Sometimes the address is off by 4 */
6059 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6066 * mono_arch_get_ip_for_breakpoint:
6068 * See mini-amd64.c for docs.
6071 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6073 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6075 /* ip points at the ldptr instruction */
6076 ip -= PPC_LOAD_SEQUENCE_LENGTH;
6082 * mono_arch_skip_breakpoint:
6084 * See mini-amd64.c for docs.
6087 mono_arch_skip_breakpoint (MonoContext *ctx)
6089 /* skip the ldptr */
6090 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6098 * mono_arch_start_single_stepping:
6100 * See mini-amd64.c for docs.
6103 mono_arch_start_single_stepping (void)
6105 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6109 * mono_arch_stop_single_stepping:
6111 * See mini-amd64.c for docs.
6114 mono_arch_stop_single_stepping (void)
6116 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6120 * mono_arch_is_single_step_event:
6122 * See mini-amd64.c for docs.
6125 mono_arch_is_single_step_event (void *info, void *sigctx)
6127 siginfo_t* sinfo = (siginfo_t*) info;
6128 /* Sometimes the address is off by 4 */
6129 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6136 * mono_arch_get_ip_for_single_step:
6138 * See mini-amd64.c for docs.
6141 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6143 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6145 /* ip points after the ldptr instruction */
6150 * mono_arch_skip_single_step:
6152 * See mini-amd64.c for docs.
6155 mono_arch_skip_single_step (MonoContext *ctx)
6157 /* skip the ldptr */
6158 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6162 * mono_arch_create_seq_point_info:
6164 * See mini-amd64.c for docs.
6167 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)