2 * mini-ppc.c: PowerPC backend for the Mono code generator
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Andreas Faerber <andreas.faerber@web.de>
9 * (C) 2003 Ximian, Inc.
10 * (C) 2007-2008 Andreas Faerber
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17 #include <mono/utils/mono-proclib.h>
18 #include <mono/utils/mono-mmap.h>
21 #ifdef TARGET_POWERPC64
22 #include "cpu-ppc64.h"
29 #include <sys/sysctl.h>
35 #define FORCE_INDIR_CALL 1
46 /* cpu_hw_caps contains the flags defined below */
47 static int cpu_hw_caps = 0;
48 static int cachelinesize = 0;
49 static int cachelineinc = 0;
51 PPC_ICACHE_SNOOP = 1 << 0,
52 PPC_MULTIPLE_LS_UNITS = 1 << 1,
53 PPC_SMP_CAPABLE = 1 << 2,
56 PPC_MOVE_FPR_GPR = 1 << 5,
60 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
62 /* This mutex protects architecture specific caches */
63 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
64 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
65 static CRITICAL_SECTION mini_arch_mutex;
67 int mono_exc_esp_offset = 0;
68 static int tls_mode = TLS_MODE_DETECT;
69 static int lmf_pthread_key = -1;
70 static int monodomain_key = -1;
73 * The code generated for sequence points reads from this location, which is
74 * made read-only when single stepping is enabled.
76 static gpointer ss_trigger_page;
78 /* Enabled breakpoints read from this trigger page */
79 static gpointer bp_trigger_page;
82 offsets_from_pthread_key (guint32 key, int *offset2)
86 *offset2 = idx2 * sizeof (gpointer);
87 return 284 + idx1 * sizeof (gpointer);
90 #define emit_linuxthreads_tls(code,dreg,key) do {\
92 off1 = offsets_from_pthread_key ((key), &off2); \
93 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
94 ppc_ldptr ((code), (dreg), off2, (dreg)); \
97 #define emit_darwing5_tls(code,dreg,key) do {\
98 int off1 = 0x48 + key * sizeof (gpointer); \
99 ppc_mfspr ((code), (dreg), 104); \
100 ppc_ldptr ((code), (dreg), off1, (dreg)); \
103 /* FIXME: ensure the sc call preserves all but r3 */
104 #define emit_darwing4_tls(code,dreg,key) do {\
105 int off1 = 0x48 + key * sizeof (gpointer); \
106 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
107 ppc_li ((code), ppc_r0, 0x7FF2); \
109 ppc_lwz ((code), (dreg), off1, ppc_r3); \
110 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
113 #ifdef PPC_THREAD_PTR_REG
114 #define emit_nptl_tls(code,dreg,key) do { \
116 int off2 = key >> 15; \
117 if ((off2 == 0) || (off2 == -1)) { \
118 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
120 int off3 = (off2 + 1) > 1; \
121 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
122 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
126 #define emit_nptl_tls(code,dreg,key) do { \
127 g_assert_not_reached (); \
131 #define emit_tls_access(code,dreg,key) do { \
132 switch (tls_mode) { \
133 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
134 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
135 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
137 default: g_assert_not_reached (); \
141 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
143 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
144 inst->type = STACK_R8; \
146 inst->inst_p0 = (void*)(addr); \
147 mono_bblock_add_inst (cfg->cbb, inst); \
151 mono_arch_regname (int reg) {
152 static const char rnames[][4] = {
153 "r0", "sp", "r2", "r3", "r4",
154 "r5", "r6", "r7", "r8", "r9",
155 "r10", "r11", "r12", "r13", "r14",
156 "r15", "r16", "r17", "r18", "r19",
157 "r20", "r21", "r22", "r23", "r24",
158 "r25", "r26", "r27", "r28", "r29",
161 if (reg >= 0 && reg < 32)
167 mono_arch_fregname (int reg) {
168 static const char rnames[][4] = {
169 "f0", "f1", "f2", "f3", "f4",
170 "f5", "f6", "f7", "f8", "f9",
171 "f10", "f11", "f12", "f13", "f14",
172 "f15", "f16", "f17", "f18", "f19",
173 "f20", "f21", "f22", "f23", "f24",
174 "f25", "f26", "f27", "f28", "f29",
177 if (reg >= 0 && reg < 32)
182 /* this function overwrites r0, r11, r12 */
184 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
186 /* unrolled, use the counter in big */
187 if (size > sizeof (gpointer) * 5) {
188 long shifted = size / SIZEOF_VOID_P;
189 guint8 *copy_loop_start, *copy_loop_jump;
191 ppc_load (code, ppc_r0, shifted);
192 ppc_mtctr (code, ppc_r0);
193 g_assert (sreg == ppc_r11);
194 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
195 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
196 copy_loop_start = code;
197 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
198 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
199 copy_loop_jump = code;
200 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
201 ppc_patch (copy_loop_jump, copy_loop_start);
202 size -= shifted * sizeof (gpointer);
203 doffset = soffset = 0;
206 #ifdef __mono_ppc64__
207 /* the hardware has multiple load/store units and the move is long
208 enough to use more then one regiester, then use load/load/store/store
209 to execute 2 instructions per cycle. */
210 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
212 ppc_ldptr (code, ppc_r0, soffset, sreg);
213 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
214 ppc_stptr (code, ppc_r0, doffset, dreg);
215 ppc_stptr (code, ppc_r12, doffset+8, dreg);
222 ppc_ldr (code, ppc_r0, soffset, sreg);
223 ppc_str (code, ppc_r0, doffset, dreg);
229 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
231 ppc_lwz (code, ppc_r0, soffset, sreg);
232 ppc_lwz (code, ppc_r12, soffset+4, sreg);
233 ppc_stw (code, ppc_r0, doffset, dreg);
234 ppc_stw (code, ppc_r12, doffset+4, dreg);
242 ppc_lwz (code, ppc_r0, soffset, sreg);
243 ppc_stw (code, ppc_r0, doffset, dreg);
249 ppc_lhz (code, ppc_r0, soffset, sreg);
250 ppc_sth (code, ppc_r0, doffset, dreg);
256 ppc_lbz (code, ppc_r0, soffset, sreg);
257 ppc_stb (code, ppc_r0, doffset, dreg);
266 * mono_arch_get_argument_info:
267 * @csig: a method signature
268 * @param_count: the number of parameters to consider
269 * @arg_info: an array to store the result infos
271 * Gathers information on parameters such as size, alignment and
272 * padding. arg_info should be large enought to hold param_count + 1 entries.
274 * Returns the size of the activation frame.
277 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
279 #ifdef __mono_ppc64__
283 int k, frame_size = 0;
284 int size, align, pad;
287 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
288 frame_size += sizeof (gpointer);
292 arg_info [0].offset = offset;
295 frame_size += sizeof (gpointer);
299 arg_info [0].size = frame_size;
301 for (k = 0; k < param_count; k++) {
304 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
306 size = mini_type_stack_size (NULL, csig->params [k], &align);
308 /* ignore alignment for now */
311 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
312 arg_info [k].pad = pad;
314 arg_info [k + 1].pad = 0;
315 arg_info [k + 1].size = size;
317 arg_info [k + 1].offset = offset;
321 align = MONO_ARCH_FRAME_ALIGNMENT;
322 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
323 arg_info [k].pad = pad;
329 #ifdef __mono_ppc64__
331 is_load_sequence (guint32 *seq)
333 return ppc_opcode (seq [0]) == 15 && /* lis */
334 ppc_opcode (seq [1]) == 24 && /* ori */
335 ppc_opcode (seq [2]) == 30 && /* sldi */
336 ppc_opcode (seq [3]) == 25 && /* oris */
337 ppc_opcode (seq [4]) == 24; /* ori */
340 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
341 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
345 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
347 /* code must point to the blrl */
349 mono_ppc_is_direct_call_sequence (guint32 *code)
351 #ifdef __mono_ppc64__
352 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
354 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
355 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
356 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
357 if (!is_load_sequence (&code [-8]))
359 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
360 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
361 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
363 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
364 return is_load_sequence (&code [-8]);
366 return is_load_sequence (&code [-6]);
370 g_assert(*code == 0x4e800021);
372 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
373 return ppc_opcode (code [-1]) == 31 &&
374 ppc_opcode (code [-2]) == 24 &&
375 ppc_opcode (code [-3]) == 15;
380 mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
384 guint32* code = (guint32*)code_ptr;
385 mgreg_t *r = (mgreg_t*)regs;
389 /* This is the 'blrl' instruction */
392 /* Sanity check: instruction must be 'blrl' */
393 if (*code != 0x4e800021)
396 if (mono_ppc_is_direct_call_sequence (code))
399 /* FIXME: more sanity checks here */
400 /* OK, we're now at the 'blrl' instruction. Now walk backwards
401 till we get to a 'mtlr rA' */
403 if((*code & 0x7c0803a6) == 0x7c0803a6) {
405 /* Here we are: we reached the 'mtlr rA'.
406 Extract the register from the instruction */
407 reg = (*code & 0x03e00000) >> 21;
409 /* ok, this is a lwz reg, offset (vtreg)
410 * it is emitted with:
411 * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
413 soff = (*code & 0xffff);
415 reg = (*code >> 16) & 0x1f;
416 g_assert (reg != ppc_r1);
417 /*g_print ("patching reg is %d\n", reg);*/
418 o = (gpointer)(gsize)r [reg];
422 *displacement = offset;
426 #define MAX_ARCH_DELEGATE_PARAMS 7
429 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
431 guint8 *code, *start;
434 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
436 start = code = mono_global_codeman_reserve (size);
438 code = mono_ppc_create_pre_code_ftnptr (code);
440 /* Replace the this argument with the target */
441 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
442 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
443 /* it's a function descriptor */
444 /* Can't use ldptr as it doesn't work with r0 */
445 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
447 ppc_mtctr (code, ppc_r0);
448 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
449 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
451 g_assert ((code - start) <= size);
453 mono_arch_flush_icache (start, size);
457 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
458 start = code = mono_global_codeman_reserve (size);
460 code = mono_ppc_create_pre_code_ftnptr (code);
462 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
463 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
464 /* it's a function descriptor */
465 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
467 ppc_mtctr (code, ppc_r0);
468 /* slide down the arguments */
469 for (i = 0; i < param_count; ++i) {
470 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
472 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
474 g_assert ((code - start) <= size);
476 mono_arch_flush_icache (start, size);
480 *code_len = code - start;
486 mono_arch_get_delegate_invoke_impls (void)
493 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
494 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
496 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
497 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
498 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
505 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
507 guint8 *code, *start;
509 /* FIXME: Support more cases */
510 if (MONO_TYPE_ISSTRUCT (sig->ret))
514 static guint8* cached = NULL;
520 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
522 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
524 mono_memory_barrier ();
528 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
531 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
533 for (i = 0; i < sig->param_count; ++i)
534 if (!mono_is_regsize_var (sig->params [i]))
538 code = cache [sig->param_count];
543 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
544 start = mono_aot_get_trampoline (name);
547 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
550 mono_memory_barrier ();
552 cache [sig->param_count] = start;
558 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
560 mgreg_t *r = (mgreg_t*)regs;
562 /* FIXME: handle returning a struct */
563 if (MONO_TYPE_ISSTRUCT (sig->ret))
564 return (gpointer)(gsize)r [ppc_r4];
565 return (gpointer)(gsize)r [ppc_r3];
573 #ifdef USE_ENVIRON_HACK
575 linux_find_auxv (int *count)
579 char **result = __environ;
580 /* Scan over the env vector looking for the ending NULL */
581 for (; *result != NULL; ++result) {
583 /* Bump the pointer one more step, which should be the auxv. */
585 vec = (AuxVec *)result;
586 if (vec->type != 22 /*AT_IGNOREPPC*/) {
590 while (vec->type != 0 /*AT_NULL*/) {
595 return (AuxVec *)result;
599 #define MAX_AUX_ENTRIES 128
601 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
602 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
604 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
606 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
607 #define ISA_64 0x40000000
609 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
610 #define ISA_MOVE_FPR_GPR 0x00000200
612 * Initialize the cpu to execute managed code.
615 mono_arch_cpu_init (void)
621 mib [1] = HW_CACHELINE;
622 len = sizeof (cachelinesize);
623 if (sysctl (mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
627 cachelineinc = cachelinesize;
629 #elif defined(__linux__)
630 AuxVec vec [MAX_AUX_ENTRIES];
631 int i, vec_entries = 0;
632 /* sadly this will work only with 2.6 kernels... */
633 FILE* f = fopen ("/proc/self/auxv", "rb");
635 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
637 #ifdef USE_ENVIRON_HACK
639 AuxVec *evec = linux_find_auxv (&vec_entries);
641 memcpy (&vec, evec, sizeof (AuxVec) * MIN (vec_entries, MAX_AUX_ENTRIES));
644 for (i = 0; i < vec_entries; i++) {
645 int type = vec [i].type;
646 if (type == 19) { /* AT_DCACHEBSIZE */
647 cachelinesize = vec [i].value;
649 } else if (type == 16) { /* AT_HWCAP */
650 if (vec [i].value & 0x00002000 /*PPC_FEATURE_ICACHE_SNOOP*/)
651 cpu_hw_caps |= PPC_ICACHE_SNOOP;
652 if (vec [i].value & ISA_2X)
653 cpu_hw_caps |= PPC_ISA_2X;
654 if (vec [i].value & ISA_64)
655 cpu_hw_caps |= PPC_ISA_64;
656 if (vec [i].value & ISA_MOVE_FPR_GPR)
657 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
659 } else if (type == 15) { /* AT_PLATFORM */
660 const char *arch = (char*)vec [i].value;
661 if (strcmp (arch, "ppc970") == 0 ||
662 (strncmp (arch, "power", 5) == 0 && arch [5] >= '4' && arch [5] <= '7'))
663 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
664 /*printf ("cpu: %s\n", (char*)vec [i].value);*/
668 #elif defined(G_COMPILER_CODEWARRIOR)
671 #elif defined(MONO_CROSS_COMPILE)
673 //#error Need a way to get cache line size
678 cachelineinc = cachelinesize;
680 if (mono_cpu_count () > 1)
681 cpu_hw_caps |= PPC_SMP_CAPABLE;
685 * Initialize architecture specific code.
688 mono_arch_init (void)
690 InitializeCriticalSection (&mini_arch_mutex);
692 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
693 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
694 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
696 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
700 * Cleanup architecture specific code.
703 mono_arch_cleanup (void)
705 DeleteCriticalSection (&mini_arch_mutex);
709 * This function returns the optimizations supported on this cpu.
712 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
716 /* no ppc-specific optimizations yet */
721 #ifdef __mono_ppc64__
722 #define CASE_PPC32(c)
723 #define CASE_PPC64(c) case c:
725 #define CASE_PPC32(c) case c:
726 #define CASE_PPC64(c)
730 is_regsize_var (MonoType *t) {
733 t = mini_type_get_underlying_type (NULL, t);
737 CASE_PPC64 (MONO_TYPE_I8)
738 CASE_PPC64 (MONO_TYPE_U8)
742 case MONO_TYPE_FNPTR:
744 case MONO_TYPE_OBJECT:
745 case MONO_TYPE_STRING:
746 case MONO_TYPE_CLASS:
747 case MONO_TYPE_SZARRAY:
748 case MONO_TYPE_ARRAY:
750 case MONO_TYPE_GENERICINST:
751 if (!mono_type_generic_inst_is_valuetype (t))
754 case MONO_TYPE_VALUETYPE:
762 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
767 for (i = 0; i < cfg->num_varinfo; i++) {
768 MonoInst *ins = cfg->varinfo [i];
769 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
772 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
775 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
778 /* we can only allocate 32 bit values */
779 if (is_regsize_var (ins->inst_vtype)) {
780 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
781 g_assert (i == vmv->idx);
782 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
788 #endif /* ifndef DISABLE_JIT */
791 mono_arch_get_global_int_regs (MonoCompile *cfg)
795 if (cfg->frame_reg != ppc_sp)
797 /* ppc_r13 is used by the system on PPC EABI */
798 for (i = 14; i < top; ++i) {
800 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
801 * since the trampolines can clobber r11.
803 if (!(cfg->compile_aot && i == 29))
804 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
811 * mono_arch_regalloc_cost:
813 * Return the cost, in number of memory references, of the action of
814 * allocating the variable VMV into a register during global register
818 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
825 mono_arch_flush_icache (guint8 *code, gint size)
827 #ifdef MONO_CROSS_COMPILE
830 guint8 *endp, *start;
834 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
835 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
836 #if defined(G_COMPILER_CODEWARRIOR)
837 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
838 for (p = start; p < endp; p += cachelineinc) {
842 for (p = start; p < endp; p += cachelineinc) {
848 for (p = start; p < endp; p += cachelineinc) {
859 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
860 * The sync is required to insure that the store queue is completely empty.
861 * While the icbi performs no cache operations, icbi/isync is required to
862 * kill local prefetch.
864 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
866 asm ("icbi 0,%0;" : : "r"(code) : "memory");
870 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
871 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
872 for (p = start; p < endp; p += cachelineinc) {
873 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
876 for (p = start; p < endp; p += cachelineinc) {
877 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
882 for (p = start; p < endp; p += cachelineinc) {
883 /* for ISA2.0+ implementations we should not need any extra sync between the
884 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
885 * So I am not sure which chip had this problem but its not an issue on
886 * of the ISA V2 chips.
888 if (cpu_hw_caps & PPC_ISA_2X)
889 asm ("icbi 0,%0;" : : "r"(p) : "memory");
891 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
893 if (!(cpu_hw_caps & PPC_ISA_2X))
901 mono_arch_flush_register_windows (void)
906 #define ALWAYS_ON_STACK(s) s
907 #define FP_ALSO_IN_REG(s) s
909 #ifdef __mono_ppc64__
910 #define ALWAYS_ON_STACK(s) s
911 #define FP_ALSO_IN_REG(s) s
913 #define ALWAYS_ON_STACK(s)
914 #define FP_ALSO_IN_REG(s)
916 #define ALIGN_DOUBLES
929 guint32 vtsize; /* in param area */
931 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
932 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
933 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
934 guint8 bytes : 4; /* size in bytes - only valid for
935 RegTypeStructByVal if the struct fits
936 in one word, otherwise it's 0*/
951 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
953 #ifdef __mono_ppc64__
958 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
959 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
960 ainfo->reg = ppc_sp; /* in the caller */
961 ainfo->regtype = RegTypeBase;
962 *stack_size += sizeof (gpointer);
964 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
968 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
970 //*stack_size += (*stack_size % 8);
972 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
973 ainfo->reg = ppc_sp; /* in the caller */
974 ainfo->regtype = RegTypeBase;
981 ALWAYS_ON_STACK (*stack_size += 8);
989 #if defined(__APPLE__) || defined(__mono_ppc64__)
991 has_only_a_r48_field (MonoClass *klass)
995 gboolean have_field = FALSE;
997 while ((f = mono_class_get_fields (klass, &iter))) {
998 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1001 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
1012 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
1015 int n = sig->hasthis + sig->param_count;
1016 MonoType *simpletype;
1017 guint32 stack_size = 0;
1018 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
1020 fr = PPC_FIRST_FPARG_REG;
1021 gr = PPC_FIRST_ARG_REG;
1023 /* FIXME: handle returning a struct */
1024 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1025 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1026 cinfo->struct_ret = PPC_FIRST_ARG_REG;
1031 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1034 DEBUG(printf("params: %d\n", sig->param_count));
1035 for (i = 0; i < sig->param_count; ++i) {
1036 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1037 /* Prevent implicit arguments and sig_cookie from
1038 being passed in registers */
1039 gr = PPC_LAST_ARG_REG + 1;
1040 /* FIXME: don't we have to set fr, too? */
1041 /* Emit the signature cookie just before the implicit arguments */
1042 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1044 DEBUG(printf("param %d: ", i));
1045 if (sig->params [i]->byref) {
1046 DEBUG(printf("byref\n"));
1047 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1051 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1052 switch (simpletype->type) {
1053 case MONO_TYPE_BOOLEAN:
1056 cinfo->args [n].size = 1;
1057 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1060 case MONO_TYPE_CHAR:
1063 cinfo->args [n].size = 2;
1064 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1069 cinfo->args [n].size = 4;
1070 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1076 case MONO_TYPE_FNPTR:
1077 case MONO_TYPE_CLASS:
1078 case MONO_TYPE_OBJECT:
1079 case MONO_TYPE_STRING:
1080 case MONO_TYPE_SZARRAY:
1081 case MONO_TYPE_ARRAY:
1082 cinfo->args [n].size = sizeof (gpointer);
1083 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1086 case MONO_TYPE_GENERICINST:
1087 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1088 cinfo->args [n].size = sizeof (gpointer);
1089 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1094 case MONO_TYPE_VALUETYPE:
1095 case MONO_TYPE_TYPEDBYREF: {
1099 klass = mono_class_from_mono_type (sig->params [i]);
1100 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1101 size = sizeof (MonoTypedRef);
1102 else if (is_pinvoke)
1103 size = mono_class_native_size (klass, NULL);
1105 size = mono_class_value_size (klass, NULL);
1107 #if defined(__APPLE__) || defined(__mono_ppc64__)
1108 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1109 cinfo->args [n].size = size;
1111 /* It was 7, now it is 8 in LinuxPPC */
1112 if (fr <= PPC_LAST_FPARG_REG) {
1113 cinfo->args [n].regtype = RegTypeFP;
1114 cinfo->args [n].reg = fr;
1116 FP_ALSO_IN_REG (gr ++);
1118 FP_ALSO_IN_REG (gr ++);
1119 ALWAYS_ON_STACK (stack_size += size);
1121 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1122 cinfo->args [n].regtype = RegTypeBase;
1123 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1130 DEBUG(printf ("load %d bytes struct\n",
1131 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1133 #if PPC_PASS_STRUCTS_BY_VALUE
1135 int align_size = size;
1137 int rest = PPC_LAST_ARG_REG - gr + 1;
1140 align_size += (sizeof (gpointer) - 1);
1141 align_size &= ~(sizeof (gpointer) - 1);
1142 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1143 n_in_regs = MIN (rest, nregs);
1147 /* FIXME: check this */
1148 if (size >= 3 && size % 4 != 0)
1151 cinfo->args [n].regtype = RegTypeStructByVal;
1152 cinfo->args [n].vtregs = n_in_regs;
1153 cinfo->args [n].size = n_in_regs;
1154 cinfo->args [n].vtsize = nregs - n_in_regs;
1155 cinfo->args [n].reg = gr;
1157 #ifdef __mono_ppc64__
1158 if (nregs == 1 && is_pinvoke)
1159 cinfo->args [n].bytes = size;
1162 cinfo->args [n].bytes = 0;
1164 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1165 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1166 stack_size += nregs * sizeof (gpointer);
1169 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1170 cinfo->args [n].regtype = RegTypeStructByAddr;
1171 cinfo->args [n].vtsize = size;
1178 cinfo->args [n].size = 8;
1179 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1183 cinfo->args [n].size = 4;
1185 /* It was 7, now it is 8 in LinuxPPC */
1186 if (fr <= PPC_LAST_FPARG_REG) {
1187 cinfo->args [n].regtype = RegTypeFP;
1188 cinfo->args [n].reg = fr;
1190 FP_ALSO_IN_REG (gr ++);
1191 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1193 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1194 cinfo->args [n].regtype = RegTypeBase;
1195 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1196 stack_size += SIZEOF_REGISTER;
1201 cinfo->args [n].size = 8;
1202 /* It was 7, now it is 8 in LinuxPPC */
1203 if (fr <= PPC_LAST_FPARG_REG) {
1204 cinfo->args [n].regtype = RegTypeFP;
1205 cinfo->args [n].reg = fr;
1207 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1208 ALWAYS_ON_STACK (stack_size += 8);
1210 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1211 cinfo->args [n].regtype = RegTypeBase;
1212 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1218 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1222 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1223 /* Prevent implicit arguments and sig_cookie from
1224 being passed in registers */
1225 gr = PPC_LAST_ARG_REG + 1;
1226 /* Emit the signature cookie just before the implicit arguments */
1227 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1231 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1232 switch (simpletype->type) {
1233 case MONO_TYPE_BOOLEAN:
1238 case MONO_TYPE_CHAR:
1244 case MONO_TYPE_FNPTR:
1245 case MONO_TYPE_CLASS:
1246 case MONO_TYPE_OBJECT:
1247 case MONO_TYPE_SZARRAY:
1248 case MONO_TYPE_ARRAY:
1249 case MONO_TYPE_STRING:
1250 cinfo->ret.reg = ppc_r3;
1254 cinfo->ret.reg = ppc_r3;
1258 cinfo->ret.reg = ppc_f1;
1259 cinfo->ret.regtype = RegTypeFP;
1261 case MONO_TYPE_GENERICINST:
1262 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1263 cinfo->ret.reg = ppc_r3;
1267 case MONO_TYPE_VALUETYPE:
1269 case MONO_TYPE_TYPEDBYREF:
1270 case MONO_TYPE_VOID:
1273 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1277 /* align stack size to 16 */
1278 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1279 stack_size = (stack_size + 15) & ~15;
1281 cinfo->stack_usage = stack_size;
1286 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1288 #if !PPC_PASS_STRUCTS_BY_VALUE
1289 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1290 int num_structs = 0;
1293 if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1296 for (i = 0; i < sig->param_count; ++i) {
1297 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1298 if (type->type == MONO_TYPE_VALUETYPE)
1303 cfg->tailcall_valuetype_addrs =
1304 mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1305 for (i = 0; i < num_structs; ++i) {
1306 cfg->tailcall_valuetype_addrs [i] =
1307 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1308 cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1315 * Set var information according to the calling convention. ppc version.
1316 * The locals var stuff should most likely be split in another method.
1319 mono_arch_allocate_vars (MonoCompile *m)
1321 MonoMethodSignature *sig;
1322 MonoMethodHeader *header;
1324 int i, offset, size, align, curinst;
1325 int frame_reg = ppc_sp;
1327 guint32 locals_stack_size, locals_stack_align;
1329 allocate_tailcall_valuetype_addrs (m);
1331 m->flags |= MONO_CFG_HAS_SPILLUP;
1333 /* allow room for the vararg method args: void* and long/double */
1334 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1335 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1336 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1337 * call convs needs to be handled this way.
1339 if (m->flags & MONO_CFG_HAS_VARARGS)
1340 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1341 /* gtk-sharp and other broken code will dllimport vararg functions even with
1342 * non-varargs signatures. Since there is little hope people will get this right
1343 * we assume they won't.
1345 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1346 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1351 * We use the frame register also for any method that has
1352 * exception clauses. This way, when the handlers are called,
1353 * the code will reference local variables using the frame reg instead of
1354 * the stack pointer: if we had to restore the stack pointer, we'd
1355 * corrupt the method frames that are already on the stack (since
1356 * filters get called before stack unwinding happens) when the filter
1357 * code would call any method (this also applies to finally etc.).
1359 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1360 frame_reg = ppc_r31;
1361 m->frame_reg = frame_reg;
1362 if (frame_reg != ppc_sp) {
1363 m->used_int_regs |= 1 << frame_reg;
1366 sig = mono_method_signature (m->method);
1370 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1371 m->ret->opcode = OP_REGVAR;
1372 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1374 /* FIXME: handle long values? */
1375 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1376 case MONO_TYPE_VOID:
1380 m->ret->opcode = OP_REGVAR;
1381 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1384 m->ret->opcode = OP_REGVAR;
1385 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1389 /* local vars are at a positive offset from the stack pointer */
1391 * also note that if the function uses alloca, we use ppc_r31
1392 * to point at the local variables.
1394 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1395 /* align the offset to 16 bytes: not sure this is needed here */
1397 //offset &= ~(16 - 1);
1399 /* add parameter area size for called functions */
1400 offset += m->param_area;
1402 offset &= ~(16 - 1);
1404 /* allow room to save the return value */
1405 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1408 /* the MonoLMF structure is stored just below the stack pointer */
1411 /* this stuff should not be needed on ppc and the new jit,
1412 * because a call on ppc to the handlers doesn't change the
1413 * stack pointer and the jist doesn't manipulate the stack pointer
1414 * for operations involving valuetypes.
1416 /* reserve space to store the esp */
1417 offset += sizeof (gpointer);
1419 /* this is a global constant */
1420 mono_exc_esp_offset = offset;
1423 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1424 offset += sizeof(gpointer) - 1;
1425 offset &= ~(sizeof(gpointer) - 1);
1427 m->vret_addr->opcode = OP_REGOFFSET;
1428 m->vret_addr->inst_basereg = frame_reg;
1429 m->vret_addr->inst_offset = offset;
1431 if (G_UNLIKELY (m->verbose_level > 1)) {
1432 printf ("vret_addr =");
1433 mono_print_ins (m->vret_addr);
1436 offset += sizeof(gpointer);
1439 offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1440 if (locals_stack_align) {
1441 offset += (locals_stack_align - 1);
1442 offset &= ~(locals_stack_align - 1);
1444 for (i = m->locals_start; i < m->num_varinfo; i++) {
1445 if (offsets [i] != -1) {
1446 MonoInst *inst = m->varinfo [i];
1447 inst->opcode = OP_REGOFFSET;
1448 inst->inst_basereg = frame_reg;
1449 inst->inst_offset = offset + offsets [i];
1451 g_print ("allocating local %d (%s) to %d\n",
1452 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1456 offset += locals_stack_size;
1460 inst = m->args [curinst];
1461 if (inst->opcode != OP_REGVAR) {
1462 inst->opcode = OP_REGOFFSET;
1463 inst->inst_basereg = frame_reg;
1464 offset += sizeof (gpointer) - 1;
1465 offset &= ~(sizeof (gpointer) - 1);
1466 inst->inst_offset = offset;
1467 offset += sizeof (gpointer);
1472 for (i = 0; i < sig->param_count; ++i) {
1473 inst = m->args [curinst];
1474 if (inst->opcode != OP_REGVAR) {
1475 inst->opcode = OP_REGOFFSET;
1476 inst->inst_basereg = frame_reg;
1478 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1479 inst->backend.is_pinvoke = 1;
1481 size = mono_type_size (sig->params [i], &align);
1483 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1484 size = align = sizeof (gpointer);
1485 offset += align - 1;
1486 offset &= ~(align - 1);
1487 inst->inst_offset = offset;
1493 /* some storage for fp conversions */
1496 m->arch.fp_conv_var_offset = offset;
1499 /* align the offset to 16 bytes */
1501 offset &= ~(16 - 1);
1504 m->stack_offset = offset;
1506 if (sig->call_convention == MONO_CALL_VARARG) {
1507 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1509 m->sig_cookie = cinfo->sig_cookie.offset;
1516 mono_arch_create_vars (MonoCompile *cfg)
1518 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1520 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1521 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1525 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1526 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1530 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1532 int sig_reg = mono_alloc_ireg (cfg);
1534 /* FIXME: Add support for signature tokens to AOT */
1535 cfg->disable_aot = TRUE;
1537 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1538 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1539 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1543 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1546 MonoMethodSignature *sig;
1550 sig = call->signature;
1551 n = sig->param_count + sig->hasthis;
1553 cinfo = calculate_sizes (sig, sig->pinvoke);
1555 for (i = 0; i < n; ++i) {
1556 ArgInfo *ainfo = cinfo->args + i;
1559 if (i >= sig->hasthis)
1560 t = sig->params [i - sig->hasthis];
1562 t = &mono_defaults.int_class->byval_arg;
1563 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1565 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1566 emit_sig_cookie (cfg, call, cinfo);
1568 in = call->args [i];
1570 if (ainfo->regtype == RegTypeGeneral) {
1571 #ifndef __mono_ppc64__
1572 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1573 MONO_INST_NEW (cfg, ins, OP_MOVE);
1574 ins->dreg = mono_alloc_ireg (cfg);
1575 ins->sreg1 = in->dreg + 1;
1576 MONO_ADD_INS (cfg->cbb, ins);
1577 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1579 MONO_INST_NEW (cfg, ins, OP_MOVE);
1580 ins->dreg = mono_alloc_ireg (cfg);
1581 ins->sreg1 = in->dreg + 2;
1582 MONO_ADD_INS (cfg->cbb, ins);
1583 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1587 MONO_INST_NEW (cfg, ins, OP_MOVE);
1588 ins->dreg = mono_alloc_ireg (cfg);
1589 ins->sreg1 = in->dreg;
1590 MONO_ADD_INS (cfg->cbb, ins);
1592 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1594 } else if (ainfo->regtype == RegTypeStructByAddr) {
1595 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1596 ins->opcode = OP_OUTARG_VT;
1597 ins->sreg1 = in->dreg;
1598 ins->klass = in->klass;
1599 ins->inst_p0 = call;
1600 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1601 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1602 MONO_ADD_INS (cfg->cbb, ins);
1603 } else if (ainfo->regtype == RegTypeStructByVal) {
1604 /* this is further handled in mono_arch_emit_outarg_vt () */
1605 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1606 ins->opcode = OP_OUTARG_VT;
1607 ins->sreg1 = in->dreg;
1608 ins->klass = in->klass;
1609 ins->inst_p0 = call;
1610 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1611 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1612 MONO_ADD_INS (cfg->cbb, ins);
1613 } else if (ainfo->regtype == RegTypeBase) {
1614 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1615 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1616 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1617 if (t->type == MONO_TYPE_R8)
1618 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1620 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1622 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1624 } else if (ainfo->regtype == RegTypeFP) {
1625 if (t->type == MONO_TYPE_VALUETYPE) {
1626 /* this is further handled in mono_arch_emit_outarg_vt () */
1627 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1628 ins->opcode = OP_OUTARG_VT;
1629 ins->sreg1 = in->dreg;
1630 ins->klass = in->klass;
1631 ins->inst_p0 = call;
1632 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1633 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1634 MONO_ADD_INS (cfg->cbb, ins);
1636 cfg->flags |= MONO_CFG_HAS_FPOUT;
1638 int dreg = mono_alloc_freg (cfg);
1640 if (ainfo->size == 4) {
1641 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1643 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1645 ins->sreg1 = in->dreg;
1646 MONO_ADD_INS (cfg->cbb, ins);
1649 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1650 cfg->flags |= MONO_CFG_HAS_FPOUT;
1653 g_assert_not_reached ();
1657 /* Emit the signature cookie in the case that there is no
1658 additional argument */
1659 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1660 emit_sig_cookie (cfg, call, cinfo);
1662 if (cinfo->struct_ret) {
1665 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1666 vtarg->sreg1 = call->vret_var->dreg;
1667 vtarg->dreg = mono_alloc_preg (cfg);
1668 MONO_ADD_INS (cfg->cbb, vtarg);
1670 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1673 call->stack_usage = cinfo->stack_usage;
1674 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1675 cfg->flags |= MONO_CFG_HAS_CALLS;
1683 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1685 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1686 ArgInfo *ainfo = ins->inst_p1;
1687 int ovf_size = ainfo->vtsize;
1688 int doffset = ainfo->offset;
1689 int i, soffset, dreg;
1691 if (ainfo->regtype == RegTypeStructByVal) {
1698 * Darwin pinvokes needs some special handling for 1
1699 * and 2 byte arguments
1701 g_assert (ins->klass);
1702 if (call->signature->pinvoke)
1703 size = mono_class_native_size (ins->klass, NULL);
1704 if (size == 2 || size == 1) {
1705 int tmpr = mono_alloc_ireg (cfg);
1707 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1709 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1710 dreg = mono_alloc_ireg (cfg);
1711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1712 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1715 for (i = 0; i < ainfo->vtregs; ++i) {
1716 int antipadding = 0;
1719 antipadding = sizeof (gpointer) - ainfo->bytes;
1721 dreg = mono_alloc_ireg (cfg);
1722 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1724 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1725 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1726 soffset += sizeof (gpointer);
1729 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1730 } else if (ainfo->regtype == RegTypeFP) {
1731 int tmpr = mono_alloc_freg (cfg);
1732 if (ainfo->size == 4)
1733 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1735 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1736 dreg = mono_alloc_freg (cfg);
1737 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1738 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1740 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1744 /* FIXME: alignment? */
1745 if (call->signature->pinvoke) {
1746 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1747 vtcopy->backend.is_pinvoke = 1;
1749 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1752 g_assert (ovf_size > 0);
1754 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1755 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1758 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1760 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1765 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1767 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1768 mono_method_signature (method)->ret);
1771 #ifndef __mono_ppc64__
1772 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1775 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1776 ins->sreg1 = val->dreg + 1;
1777 ins->sreg2 = val->dreg + 2;
1778 MONO_ADD_INS (cfg->cbb, ins);
1782 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1783 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1787 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1790 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1792 mono_arch_is_inst_imm (gint64 imm)
1797 #endif /* DISABLE_JIT */
1800 * Allow tracing to work with this interface (with an optional argument)
1804 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1808 ppc_load_ptr (code, ppc_r3, cfg->method);
1809 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1810 ppc_load_func (code, ppc_r0, func);
1811 ppc_mtlr (code, ppc_r0);
1825 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1828 int save_mode = SAVE_NONE;
1830 MonoMethod *method = cfg->method;
1831 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1832 mono_method_signature (method)->ret)->type;
1833 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1837 offset = code - cfg->native_code;
1838 /* we need about 16 instructions */
1839 if (offset > (cfg->code_size - 16 * 4)) {
1840 cfg->code_size *= 2;
1841 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1842 code = cfg->native_code + offset;
1846 case MONO_TYPE_VOID:
1847 /* special case string .ctor icall */
1848 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1849 save_mode = SAVE_ONE;
1851 save_mode = SAVE_NONE;
1853 #ifndef __mono_ppc64__
1856 save_mode = SAVE_TWO;
1861 save_mode = SAVE_FP;
1863 case MONO_TYPE_VALUETYPE:
1864 save_mode = SAVE_STRUCT;
1867 save_mode = SAVE_ONE;
1871 switch (save_mode) {
1873 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1874 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1875 if (enable_arguments) {
1876 ppc_mr (code, ppc_r5, ppc_r4);
1877 ppc_mr (code, ppc_r4, ppc_r3);
1881 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1882 if (enable_arguments) {
1883 ppc_mr (code, ppc_r4, ppc_r3);
1887 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1888 if (enable_arguments) {
1889 /* FIXME: what reg? */
1890 ppc_fmr (code, ppc_f3, ppc_f1);
1891 /* FIXME: use 8 byte load on PPC64 */
1892 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1893 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1897 if (enable_arguments) {
1898 /* FIXME: get the actual address */
1899 ppc_mr (code, ppc_r4, ppc_r3);
1907 ppc_load_ptr (code, ppc_r3, cfg->method);
1908 ppc_load_func (code, ppc_r0, func);
1909 ppc_mtlr (code, ppc_r0);
1912 switch (save_mode) {
1914 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1915 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1918 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1921 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1931 * Conditional branches have a small offset, so if it is likely overflowed,
1932 * we do a branch to the end of the method (uncond branches have much larger
1933 * offsets) where we perform the conditional and jump back unconditionally.
1934 * It's slightly slower, since we add two uncond branches, but it's very simple
1935 * with the current patch implementation and such large methods are likely not
1936 * going to be perf critical anyway.
1941 const char *exception;
1948 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1949 if (0 && ins->inst_true_bb->native_offset) { \
1950 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1952 int br_disp = ins->inst_true_bb->max_offset - offset; \
1953 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1954 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1955 ovfj->data.bb = ins->inst_true_bb; \
1956 ovfj->ip_offset = 0; \
1957 ovfj->b0_cond = (b0); \
1958 ovfj->b1_cond = (b1); \
1959 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1962 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1963 ppc_bc (code, (b0), (b1), 0); \
1967 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1969 /* emit an exception if condition is fail
1971 * We assign the extra code used to throw the implicit exceptions
1972 * to cfg->bb_exit as far as the big branch handling is concerned
1974 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1976 int br_disp = cfg->bb_exit->max_offset - offset; \
1977 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1978 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1979 ovfj->data.exception = (exc_name); \
1980 ovfj->ip_offset = code - cfg->native_code; \
1981 ovfj->b0_cond = (b0); \
1982 ovfj->b1_cond = (b1); \
1983 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1985 cfg->bb_exit->max_offset += 24; \
1987 mono_add_patch_info (cfg, code - cfg->native_code, \
1988 MONO_PATCH_INFO_EXC, exc_name); \
1989 ppc_bcl (code, (b0), (b1), 0); \
1993 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1996 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2001 normalize_opcode (int opcode)
2004 #ifndef __mono_ilp32__
2005 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
2006 return OP_LOAD_MEMBASE;
2007 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
2008 return OP_LOAD_MEMINDEX;
2009 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
2010 return OP_STORE_MEMBASE_REG;
2011 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
2012 return OP_STORE_MEMBASE_IMM;
2013 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
2014 return OP_STORE_MEMINDEX;
2016 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
2018 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
2019 return OP_SHR_UN_IMM;
2026 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2028 MonoInst *ins, *n, *last_ins = NULL;
2030 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2031 switch (normalize_opcode (ins->opcode)) {
2033 /* remove unnecessary multiplication with 1 */
2034 if (ins->inst_imm == 1) {
2035 if (ins->dreg != ins->sreg1) {
2036 ins->opcode = OP_MOVE;
2038 MONO_DELETE_INS (bb, ins);
2042 int power2 = mono_is_power_of_two (ins->inst_imm);
2044 ins->opcode = OP_SHL_IMM;
2045 ins->inst_imm = power2;
2049 case OP_LOAD_MEMBASE:
2051 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2052 * OP_LOAD_MEMBASE offset(basereg), reg
2054 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2055 ins->inst_basereg == last_ins->inst_destbasereg &&
2056 ins->inst_offset == last_ins->inst_offset) {
2057 if (ins->dreg == last_ins->sreg1) {
2058 MONO_DELETE_INS (bb, ins);
2061 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2062 ins->opcode = OP_MOVE;
2063 ins->sreg1 = last_ins->sreg1;
2067 * Note: reg1 must be different from the basereg in the second load
2068 * OP_LOAD_MEMBASE offset(basereg), reg1
2069 * OP_LOAD_MEMBASE offset(basereg), reg2
2071 * OP_LOAD_MEMBASE offset(basereg), reg1
2072 * OP_MOVE reg1, reg2
2074 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2075 ins->inst_basereg != last_ins->dreg &&
2076 ins->inst_basereg == last_ins->inst_basereg &&
2077 ins->inst_offset == last_ins->inst_offset) {
2079 if (ins->dreg == last_ins->dreg) {
2080 MONO_DELETE_INS (bb, ins);
2083 ins->opcode = OP_MOVE;
2084 ins->sreg1 = last_ins->dreg;
2087 //g_assert_not_reached ();
2091 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2092 * OP_LOAD_MEMBASE offset(basereg), reg
2094 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2095 * OP_ICONST reg, imm
2097 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2098 ins->inst_basereg == last_ins->inst_destbasereg &&
2099 ins->inst_offset == last_ins->inst_offset) {
2100 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2101 ins->opcode = OP_ICONST;
2102 ins->inst_c0 = last_ins->inst_imm;
2103 g_assert_not_reached (); // check this rule
2107 case OP_LOADU1_MEMBASE:
2108 case OP_LOADI1_MEMBASE:
2109 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2110 ins->inst_basereg == last_ins->inst_destbasereg &&
2111 ins->inst_offset == last_ins->inst_offset) {
2112 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2113 ins->sreg1 = last_ins->sreg1;
2116 case OP_LOADU2_MEMBASE:
2117 case OP_LOADI2_MEMBASE:
2118 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2119 ins->inst_basereg == last_ins->inst_destbasereg &&
2120 ins->inst_offset == last_ins->inst_offset) {
2121 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2122 ins->sreg1 = last_ins->sreg1;
2125 #ifdef __mono_ppc64__
2126 case OP_LOADU4_MEMBASE:
2127 case OP_LOADI4_MEMBASE:
2128 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2129 ins->inst_basereg == last_ins->inst_destbasereg &&
2130 ins->inst_offset == last_ins->inst_offset) {
2131 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2132 ins->sreg1 = last_ins->sreg1;
2137 ins->opcode = OP_MOVE;
2141 if (ins->dreg == ins->sreg1) {
2142 MONO_DELETE_INS (bb, ins);
2146 * OP_MOVE sreg, dreg
2147 * OP_MOVE dreg, sreg
2149 if (last_ins && last_ins->opcode == OP_MOVE &&
2150 ins->sreg1 == last_ins->dreg &&
2151 ins->dreg == last_ins->sreg1) {
2152 MONO_DELETE_INS (bb, ins);
2160 bb->last_ins = last_ins;
2164 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2166 switch (ins->opcode) {
2167 case OP_ICONV_TO_R_UN: {
2168 #if G_BYTE_ORDER == G_BIG_ENDIAN
2169 static const guint64 adjust_val = 0x4330000000000000ULL;
2171 static const guint64 adjust_val = 0x0000000000003043ULL;
2173 int msw_reg = mono_alloc_ireg (cfg);
2174 int adj_reg = mono_alloc_freg (cfg);
2175 int tmp_reg = mono_alloc_freg (cfg);
2176 int basereg = ppc_sp;
2178 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2179 if (!ppc_is_imm16 (offset + 4)) {
2180 basereg = mono_alloc_ireg (cfg);
2181 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2184 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2185 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2186 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2187 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2188 ins->opcode = OP_NOP;
2191 #ifndef __mono_ppc64__
2192 case OP_ICONV_TO_R4:
2193 case OP_ICONV_TO_R8: {
2194 /* If we have a PPC_FEATURE_64 machine we can avoid
2195 this and use the fcfid instruction. Otherwise
2196 on an old 32-bit chip and we have to do this the
2198 if (!(cpu_hw_caps & PPC_ISA_64)) {
2199 /* FIXME: change precision for CEE_CONV_R4 */
2200 static const guint64 adjust_val = 0x4330000080000000ULL;
2201 int msw_reg = mono_alloc_ireg (cfg);
2202 int xored = mono_alloc_ireg (cfg);
2203 int adj_reg = mono_alloc_freg (cfg);
2204 int tmp_reg = mono_alloc_freg (cfg);
2205 int basereg = ppc_sp;
2207 if (!ppc_is_imm16 (offset + 4)) {
2208 basereg = mono_alloc_ireg (cfg);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2211 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2212 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2213 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2214 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2215 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2216 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2217 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2218 if (ins->opcode == OP_ICONV_TO_R4)
2219 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2220 ins->opcode = OP_NOP;
2226 int msw_reg = mono_alloc_ireg (cfg);
2227 int basereg = ppc_sp;
2229 if (!ppc_is_imm16 (offset + 4)) {
2230 basereg = mono_alloc_ireg (cfg);
2231 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2233 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2234 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2235 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2236 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2237 ins->opcode = OP_NOP;
2240 #ifdef __mono_ppc64__
2242 case OP_IADD_OVF_UN:
2244 int shifted1_reg = mono_alloc_ireg (cfg);
2245 int shifted2_reg = mono_alloc_ireg (cfg);
2246 int result_shifted_reg = mono_alloc_ireg (cfg);
2248 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2249 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2250 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2251 if (ins->opcode == OP_IADD_OVF_UN)
2252 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2254 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2255 ins->opcode = OP_NOP;
2262 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2264 switch (ins->opcode) {
2266 /* ADC sets the condition code */
2267 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2271 case OP_LADD_OVF_UN:
2272 /* ADC sets the condition code */
2273 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2274 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2278 /* SBB sets the condition code */
2279 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2280 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2283 case OP_LSUB_OVF_UN:
2284 /* SBB sets the condition code */
2285 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2286 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2290 /* From gcc generated code */
2291 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2292 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2301 * the branch_b0_table should maintain the order of these
2315 branch_b0_table [] = {
2330 branch_b1_table [] = {
2344 #define NEW_INS(cfg,dest,op) do { \
2345 MONO_INST_NEW((cfg), (dest), (op)); \
2346 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2350 map_to_reg_reg_op (int op)
2359 case OP_COMPARE_IMM:
2361 case OP_ICOMPARE_IMM:
2363 case OP_LCOMPARE_IMM:
2379 case OP_LOAD_MEMBASE:
2380 return OP_LOAD_MEMINDEX;
2381 case OP_LOADI4_MEMBASE:
2382 return OP_LOADI4_MEMINDEX;
2383 case OP_LOADU4_MEMBASE:
2384 return OP_LOADU4_MEMINDEX;
2385 case OP_LOADI8_MEMBASE:
2386 return OP_LOADI8_MEMINDEX;
2387 case OP_LOADU1_MEMBASE:
2388 return OP_LOADU1_MEMINDEX;
2389 case OP_LOADI2_MEMBASE:
2390 return OP_LOADI2_MEMINDEX;
2391 case OP_LOADU2_MEMBASE:
2392 return OP_LOADU2_MEMINDEX;
2393 case OP_LOADI1_MEMBASE:
2394 return OP_LOADI1_MEMINDEX;
2395 case OP_LOADR4_MEMBASE:
2396 return OP_LOADR4_MEMINDEX;
2397 case OP_LOADR8_MEMBASE:
2398 return OP_LOADR8_MEMINDEX;
2399 case OP_STOREI1_MEMBASE_REG:
2400 return OP_STOREI1_MEMINDEX;
2401 case OP_STOREI2_MEMBASE_REG:
2402 return OP_STOREI2_MEMINDEX;
2403 case OP_STOREI4_MEMBASE_REG:
2404 return OP_STOREI4_MEMINDEX;
2405 case OP_STOREI8_MEMBASE_REG:
2406 return OP_STOREI8_MEMINDEX;
2407 case OP_STORE_MEMBASE_REG:
2408 return OP_STORE_MEMINDEX;
2409 case OP_STORER4_MEMBASE_REG:
2410 return OP_STORER4_MEMINDEX;
2411 case OP_STORER8_MEMBASE_REG:
2412 return OP_STORER8_MEMINDEX;
2413 case OP_STORE_MEMBASE_IMM:
2414 return OP_STORE_MEMBASE_REG;
2415 case OP_STOREI1_MEMBASE_IMM:
2416 return OP_STOREI1_MEMBASE_REG;
2417 case OP_STOREI2_MEMBASE_IMM:
2418 return OP_STOREI2_MEMBASE_REG;
2419 case OP_STOREI4_MEMBASE_IMM:
2420 return OP_STOREI4_MEMBASE_REG;
2421 case OP_STOREI8_MEMBASE_IMM:
2422 return OP_STOREI8_MEMBASE_REG;
2424 return mono_op_imm_to_op (op);
2427 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2429 #define compare_opcode_is_unsigned(opcode) \
2430 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2431 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2432 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2433 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2434 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2435 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2436 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2437 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2440 * Remove from the instruction list the instructions that can't be
2441 * represented with very simple instructions with no register
2445 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2447 MonoInst *ins, *next, *temp, *last_ins = NULL;
2450 MONO_BB_FOR_EACH_INS (bb, ins) {
2452 switch (ins->opcode) {
2453 case OP_IDIV_UN_IMM:
2456 case OP_IREM_UN_IMM:
2457 NEW_INS (cfg, temp, OP_ICONST);
2458 temp->inst_c0 = ins->inst_imm;
2459 temp->dreg = mono_alloc_ireg (cfg);
2460 ins->sreg2 = temp->dreg;
2461 if (ins->opcode == OP_IDIV_IMM)
2462 ins->opcode = OP_IDIV;
2463 else if (ins->opcode == OP_IREM_IMM)
2464 ins->opcode = OP_IREM;
2465 else if (ins->opcode == OP_IDIV_UN_IMM)
2466 ins->opcode = OP_IDIV_UN;
2467 else if (ins->opcode == OP_IREM_UN_IMM)
2468 ins->opcode = OP_IREM_UN;
2470 /* handle rem separately */
2474 CASE_PPC64 (OP_LREM)
2475 CASE_PPC64 (OP_LREM_UN) {
2477 /* we change a rem dest, src1, src2 to
2478 * div temp1, src1, src2
2479 * mul temp2, temp1, src2
2480 * sub dest, src1, temp2
2482 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2483 NEW_INS (cfg, mul, OP_IMUL);
2484 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2485 ins->opcode = OP_ISUB;
2487 NEW_INS (cfg, mul, OP_LMUL);
2488 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2489 ins->opcode = OP_LSUB;
2491 temp->sreg1 = ins->sreg1;
2492 temp->sreg2 = ins->sreg2;
2493 temp->dreg = mono_alloc_ireg (cfg);
2494 mul->sreg1 = temp->dreg;
2495 mul->sreg2 = ins->sreg2;
2496 mul->dreg = mono_alloc_ireg (cfg);
2497 ins->sreg2 = mul->dreg;
2501 CASE_PPC64 (OP_LADD_IMM)
2504 if (!ppc_is_imm16 (ins->inst_imm)) {
2505 NEW_INS (cfg, temp, OP_ICONST);
2506 temp->inst_c0 = ins->inst_imm;
2507 temp->dreg = mono_alloc_ireg (cfg);
2508 ins->sreg2 = temp->dreg;
2509 ins->opcode = map_to_reg_reg_op (ins->opcode);
2513 CASE_PPC64 (OP_LSUB_IMM)
2515 if (!ppc_is_imm16 (-ins->inst_imm)) {
2516 NEW_INS (cfg, temp, OP_ICONST);
2517 temp->inst_c0 = ins->inst_imm;
2518 temp->dreg = mono_alloc_ireg (cfg);
2519 ins->sreg2 = temp->dreg;
2520 ins->opcode = map_to_reg_reg_op (ins->opcode);
2532 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2533 #ifdef __mono_ppc64__
2534 if (ins->inst_imm & 0xffffffff00000000ULL)
2538 NEW_INS (cfg, temp, OP_ICONST);
2539 temp->inst_c0 = ins->inst_imm;
2540 temp->dreg = mono_alloc_ireg (cfg);
2541 ins->sreg2 = temp->dreg;
2542 ins->opcode = map_to_reg_reg_op (ins->opcode);
2551 NEW_INS (cfg, temp, OP_ICONST);
2552 temp->inst_c0 = ins->inst_imm;
2553 temp->dreg = mono_alloc_ireg (cfg);
2554 ins->sreg2 = temp->dreg;
2555 ins->opcode = map_to_reg_reg_op (ins->opcode);
2557 case OP_COMPARE_IMM:
2558 case OP_ICOMPARE_IMM:
2559 CASE_PPC64 (OP_LCOMPARE_IMM)
2561 /* Branch opts can eliminate the branch */
2562 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2563 ins->opcode = OP_NOP;
2567 if (compare_opcode_is_unsigned (next->opcode)) {
2568 if (!ppc_is_uimm16 (ins->inst_imm)) {
2569 NEW_INS (cfg, temp, OP_ICONST);
2570 temp->inst_c0 = ins->inst_imm;
2571 temp->dreg = mono_alloc_ireg (cfg);
2572 ins->sreg2 = temp->dreg;
2573 ins->opcode = map_to_reg_reg_op (ins->opcode);
2576 if (!ppc_is_imm16 (ins->inst_imm)) {
2577 NEW_INS (cfg, temp, OP_ICONST);
2578 temp->inst_c0 = ins->inst_imm;
2579 temp->dreg = mono_alloc_ireg (cfg);
2580 ins->sreg2 = temp->dreg;
2581 ins->opcode = map_to_reg_reg_op (ins->opcode);
2587 if (ins->inst_imm == 1) {
2588 ins->opcode = OP_MOVE;
2591 if (ins->inst_imm == 0) {
2592 ins->opcode = OP_ICONST;
2596 imm = mono_is_power_of_two (ins->inst_imm);
2598 ins->opcode = OP_SHL_IMM;
2599 ins->inst_imm = imm;
2602 if (!ppc_is_imm16 (ins->inst_imm)) {
2603 NEW_INS (cfg, temp, OP_ICONST);
2604 temp->inst_c0 = ins->inst_imm;
2605 temp->dreg = mono_alloc_ireg (cfg);
2606 ins->sreg2 = temp->dreg;
2607 ins->opcode = map_to_reg_reg_op (ins->opcode);
2610 case OP_LOCALLOC_IMM:
2611 NEW_INS (cfg, temp, OP_ICONST);
2612 temp->inst_c0 = ins->inst_imm;
2613 temp->dreg = mono_alloc_ireg (cfg);
2614 ins->sreg1 = temp->dreg;
2615 ins->opcode = OP_LOCALLOC;
2617 case OP_LOAD_MEMBASE:
2618 case OP_LOADI4_MEMBASE:
2619 CASE_PPC64 (OP_LOADI8_MEMBASE)
2620 case OP_LOADU4_MEMBASE:
2621 case OP_LOADI2_MEMBASE:
2622 case OP_LOADU2_MEMBASE:
2623 case OP_LOADI1_MEMBASE:
2624 case OP_LOADU1_MEMBASE:
2625 case OP_LOADR4_MEMBASE:
2626 case OP_LOADR8_MEMBASE:
2627 case OP_STORE_MEMBASE_REG:
2628 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2629 case OP_STOREI4_MEMBASE_REG:
2630 case OP_STOREI2_MEMBASE_REG:
2631 case OP_STOREI1_MEMBASE_REG:
2632 case OP_STORER4_MEMBASE_REG:
2633 case OP_STORER8_MEMBASE_REG:
2634 /* we can do two things: load the immed in a register
2635 * and use an indexed load, or see if the immed can be
2636 * represented as an ad_imm + a load with a smaller offset
2637 * that fits. We just do the first for now, optimize later.
2639 if (ppc_is_imm16 (ins->inst_offset))
2641 NEW_INS (cfg, temp, OP_ICONST);
2642 temp->inst_c0 = ins->inst_offset;
2643 temp->dreg = mono_alloc_ireg (cfg);
2644 ins->sreg2 = temp->dreg;
2645 ins->opcode = map_to_reg_reg_op (ins->opcode);
2647 case OP_STORE_MEMBASE_IMM:
2648 case OP_STOREI1_MEMBASE_IMM:
2649 case OP_STOREI2_MEMBASE_IMM:
2650 case OP_STOREI4_MEMBASE_IMM:
2651 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2652 NEW_INS (cfg, temp, OP_ICONST);
2653 temp->inst_c0 = ins->inst_imm;
2654 temp->dreg = mono_alloc_ireg (cfg);
2655 ins->sreg1 = temp->dreg;
2656 ins->opcode = map_to_reg_reg_op (ins->opcode);
2658 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2661 if (cfg->compile_aot) {
2662 /* Keep these in the aot case */
2665 NEW_INS (cfg, temp, OP_ICONST);
2666 temp->inst_c0 = (gulong)ins->inst_p0;
2667 temp->dreg = mono_alloc_ireg (cfg);
2668 ins->inst_basereg = temp->dreg;
2669 ins->inst_offset = 0;
2670 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2672 /* make it handle the possibly big ins->inst_offset
2673 * later optimize to use lis + load_membase
2679 bb->last_ins = last_ins;
2680 bb->max_vreg = cfg->next_vreg;
2684 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2686 long offset = cfg->arch.fp_conv_var_offset;
2688 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2689 #ifdef __mono_ppc64__
2691 ppc_fctidz (code, ppc_f0, sreg);
2696 ppc_fctiwz (code, ppc_f0, sreg);
2699 if (ppc_is_imm16 (offset + sub_offset)) {
2700 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2702 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2704 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2706 ppc_load (code, dreg, offset);
2707 ppc_add (code, dreg, dreg, cfg->frame_reg);
2708 ppc_stfd (code, ppc_f0, 0, dreg);
2710 ppc_ldr (code, dreg, sub_offset, dreg);
2712 ppc_lwz (code, dreg, sub_offset, dreg);
2716 ppc_andid (code, dreg, dreg, 0xff);
2718 ppc_andid (code, dreg, dreg, 0xffff);
2719 #ifdef __mono_ppc64__
2721 ppc_clrldi (code, dreg, dreg, 32);
2725 ppc_extsb (code, dreg, dreg);
2727 ppc_extsh (code, dreg, dreg);
2728 #ifdef __mono_ppc64__
2730 ppc_extsw (code, dreg, dreg);
2738 const guchar *target;
2743 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2746 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2747 #ifdef __mono_ppc64__
2748 g_assert_not_reached ();
2750 PatchData *pdata = (PatchData*)user_data;
2751 guchar *code = data;
2752 guint32 *thunks = data;
2753 guint32 *endthunks = (guint32*)(code + bsize);
2757 int difflow, diffhigh;
2759 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2760 difflow = (char*)pdata->code - (char*)thunks;
2761 diffhigh = (char*)pdata->code - (char*)endthunks;
2762 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2765 templ = (guchar*)load;
2766 ppc_load_sequence (templ, ppc_r0, pdata->target);
2768 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2769 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2770 while (thunks < endthunks) {
2771 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2772 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2773 ppc_patch (pdata->code, (guchar*)thunks);
2776 static int num_thunks = 0;
2778 if ((num_thunks % 20) == 0)
2779 g_print ("num_thunks lookup: %d\n", num_thunks);
2782 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2783 /* found a free slot instead: emit thunk */
2784 code = (guchar*)thunks;
2785 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2786 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2787 ppc_mtctr (code, ppc_r0);
2788 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2789 mono_arch_flush_icache ((guchar*)thunks, 16);
2791 ppc_patch (pdata->code, (guchar*)thunks);
2794 static int num_thunks = 0;
2796 if ((num_thunks % 20) == 0)
2797 g_print ("num_thunks: %d\n", num_thunks);
2801 /* skip 16 bytes, the size of the thunk */
2805 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2812 handle_thunk (int absolute, guchar *code, const guchar *target) {
2813 MonoDomain *domain = mono_domain_get ();
2817 pdata.target = target;
2818 pdata.absolute = absolute;
2821 mono_domain_lock (domain);
2822 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2825 /* this uses the first available slot */
2827 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2829 mono_domain_unlock (domain);
2831 if (pdata.found != 1)
2832 g_print ("thunk failed for %p from %p\n", target, code);
2833 g_assert (pdata.found == 1);
2837 patch_ins (guint8 *code, guint32 ins)
2839 *(guint32*)code = GUINT32_TO_BE (ins);
2840 mono_arch_flush_icache (code, 4);
2844 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2846 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2847 guint32 prim = ins >> 26;
2850 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2852 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2853 gint diff = target - code;
2856 if (diff <= 33554431){
2857 ins = (18 << 26) | (diff) | (ins & 1);
2858 patch_ins (code, ins);
2862 /* diff between 0 and -33554432 */
2863 if (diff >= -33554432){
2864 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2865 patch_ins (code, ins);
2870 if ((glong)target >= 0){
2871 if ((glong)target <= 33554431){
2872 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2873 patch_ins (code, ins);
2877 if ((glong)target >= -33554432){
2878 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2879 patch_ins (code, ins);
2884 handle_thunk (TRUE, code, target);
2887 g_assert_not_reached ();
2895 guint32 li = (gulong)target;
2896 ins = (ins & 0xffff0000) | (ins & 3);
2897 ovf = li & 0xffff0000;
2898 if (ovf != 0 && ovf != 0xffff0000)
2899 g_assert_not_reached ();
2902 // FIXME: assert the top bits of li are 0
2904 gint diff = target - code;
2905 ins = (ins & 0xffff0000) | (ins & 3);
2906 ovf = diff & 0xffff0000;
2907 if (ovf != 0 && ovf != 0xffff0000)
2908 g_assert_not_reached ();
2912 patch_ins (code, ins);
2916 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2917 #ifdef __mono_ppc64__
2918 guint32 *seq = (guint32*)code;
2919 guint32 *branch_ins;
2921 /* the trampoline code will try to patch the blrl, blr, bcctr */
2922 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2924 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2929 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2930 branch_ins = seq + 8;
2932 branch_ins = seq + 6;
2935 seq = (guint32*)code;
2936 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2937 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2939 if (ppc_is_load_op (seq [5])) {
2940 g_assert (ppc_is_load_op (seq [6]));
2943 guint8 *buf = (guint8*)&seq [5];
2944 ppc_mr (buf, ppc_r0, ppc_r11);
2949 target = mono_get_addr_from_ftnptr ((gpointer)target);
2952 /* FIXME: make this thread safe */
2953 /* FIXME: we're assuming we're using r11 here */
2954 ppc_load_ptr_sequence (code, ppc_r11, target);
2955 mono_arch_flush_icache ((guint8*)seq, 28);
2958 /* the trampoline code will try to patch the blrl, blr, bcctr */
2959 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2962 /* this is the lis/ori/mtlr/blrl sequence */
2963 seq = (guint32*)code;
2964 g_assert ((seq [0] >> 26) == 15);
2965 g_assert ((seq [1] >> 26) == 24);
2966 g_assert ((seq [2] >> 26) == 31);
2967 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2968 /* FIXME: make this thread safe */
2969 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2970 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2971 mono_arch_flush_icache (code - 8, 8);
2974 g_assert_not_reached ();
2976 // g_print ("patched with 0x%08x\n", ins);
2980 ppc_patch (guchar *code, const guchar *target)
2982 ppc_patch_full (code, target, FALSE);
2986 mono_ppc_patch (guchar *code, const guchar *target)
2988 ppc_patch (code, target);
2992 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2994 switch (ins->opcode) {
2997 case OP_FCALL_MEMBASE:
2998 if (ins->dreg != ppc_f1)
2999 ppc_fmr (code, ins->dreg, ppc_f1);
3007 * emit_load_volatile_arguments:
3009 * Load volatile arguments from the stack to the original input registers.
3010 * Required before a tail call.
3013 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
3015 MonoMethod *method = cfg->method;
3016 MonoMethodSignature *sig;
3020 int struct_index = 0;
3022 sig = mono_method_signature (method);
3024 /* This is the opposite of the code in emit_prolog */
3028 cinfo = calculate_sizes (sig, sig->pinvoke);
3030 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3031 ArgInfo *ainfo = &cinfo->ret;
3032 inst = cfg->vret_addr;
3033 g_assert (ppc_is_imm16 (inst->inst_offset));
3034 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3036 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3037 ArgInfo *ainfo = cinfo->args + i;
3038 inst = cfg->args [pos];
3040 g_assert (inst->opcode != OP_REGVAR);
3041 g_assert (ppc_is_imm16 (inst->inst_offset));
3043 switch (ainfo->regtype) {
3044 case RegTypeGeneral:
3045 switch (ainfo->size) {
3047 ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3050 ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3052 #ifdef __mono_ppc64__
3054 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3058 ppc_ldptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3064 switch (ainfo->size) {
3066 ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3069 ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3072 g_assert_not_reached ();
3077 MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
3078 &inst->klass->byval_arg);
3080 #ifndef __mono_ppc64__
3081 if (type->type == MONO_TYPE_I8)
3085 if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_I8) {
3086 ppc_ldptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3087 ppc_stptr (code, ppc_r0, ainfo->offset, ainfo->reg);
3088 } else if (type->type == MONO_TYPE_I4) {
3089 ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3090 ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
3098 case RegTypeStructByVal: {
3109 * Darwin pinvokes needs some special handling
3110 * for 1 and 2 byte arguments
3112 if (method->signature->pinvoke)
3113 size = mono_class_native_size (inst->klass, NULL);
3114 if (size == 1 || size == 2) {
3119 for (j = 0; j < ainfo->vtregs; ++j) {
3120 ppc_ldptr (code, ainfo->reg + j,
3121 inst->inst_offset + j * sizeof (gpointer),
3122 inst->inst_basereg);
3123 /* FIXME: shift to the right */
3130 case RegTypeStructByAddr: {
3131 MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
3133 g_assert (ppc_is_imm16 (addr->inst_offset));
3134 g_assert (!ainfo->offset);
3135 ppc_ldptr (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
3142 g_assert_not_reached ();
3153 /* This must be kept in sync with emit_load_volatile_arguments(). */
3155 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3157 int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3158 MonoMethodSignature *sig;
3163 if (ins->opcode != OP_JMP)
3166 call = (MonoCallInst*)ins;
3167 sig = mono_method_signature (cfg->method);
3168 cinfo = calculate_sizes (sig, sig->pinvoke);
3170 if (MONO_TYPE_ISSTRUCT (sig->ret))
3172 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3173 ArgInfo *ainfo = cinfo->args + i;
3175 switch (ainfo->regtype) {
3176 case RegTypeGeneral:
3185 case RegTypeStructByVal:
3186 len += 4 * ainfo->size;
3189 case RegTypeStructByAddr:
3194 g_assert_not_reached ();
3204 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3206 long size = cfg->param_area;
3208 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3209 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3214 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3215 if (ppc_is_imm16 (-size)) {
3216 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3218 ppc_load (code, ppc_r11, -size);
3219 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3226 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3228 long size = cfg->param_area;
3230 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3231 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3236 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3237 if (ppc_is_imm16 (size)) {
3238 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3240 ppc_load (code, ppc_r11, size);
3241 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3247 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3251 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3253 MonoInst *ins, *next;
3256 guint8 *code = cfg->native_code + cfg->code_len;
3257 MonoInst *last_ins = NULL;
3258 guint last_offset = 0;
3262 /* we don't align basic blocks of loops on ppc */
3264 if (cfg->verbose_level > 2)
3265 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3267 cpos = bb->max_offset;
3269 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3270 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3271 //g_assert (!mono_compile_aot);
3274 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3275 /* this is not thread save, but good enough */
3276 /* fixme: howto handle overflows? */
3277 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3280 MONO_BB_FOR_EACH_INS (bb, ins) {
3281 offset = code - cfg->native_code;
3283 max_len = ins_native_length (cfg, ins);
3285 if (offset > (cfg->code_size - max_len - 16)) {
3286 cfg->code_size *= 2;
3287 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3288 code = cfg->native_code + offset;
3290 // if (ins->cil_code)
3291 // g_print ("cil code\n");
3292 mono_debug_record_line_number (cfg, ins, offset);
3294 switch (normalize_opcode (ins->opcode)) {
3295 case OP_RELAXED_NOP:
3298 case OP_DUMMY_STORE:
3299 case OP_NOT_REACHED:
3302 case OP_SEQ_POINT: {
3305 if (cfg->compile_aot)
3309 * Read from the single stepping trigger page. This will cause a
3310 * SIGSEGV when single stepping is enabled.
3311 * We do this _before_ the breakpoint, so single stepping after
3312 * a breakpoint is hit will step to the next IL offset.
3314 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3315 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3316 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3319 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3322 * A placeholder for a possible breakpoint inserted by
3323 * mono_arch_set_breakpoint ().
3325 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3330 emit_tls_access (code, ins->dreg, ins->inst_offset);
3333 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3334 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3335 ppc_mr (code, ppc_r4, ppc_r0);
3338 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3339 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3340 ppc_mr (code, ppc_r4, ppc_r0);
3342 case OP_MEMORY_BARRIER:
3345 case OP_STOREI1_MEMBASE_REG:
3346 if (ppc_is_imm16 (ins->inst_offset)) {
3347 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3349 if (ppc_is_imm32 (ins->inst_offset)) {
3350 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3351 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3353 ppc_load (code, ppc_r0, ins->inst_offset);
3354 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3358 case OP_STOREI2_MEMBASE_REG:
3359 if (ppc_is_imm16 (ins->inst_offset)) {
3360 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3362 if (ppc_is_imm32 (ins->inst_offset)) {
3363 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3364 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3366 ppc_load (code, ppc_r0, ins->inst_offset);
3367 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3371 case OP_STORE_MEMBASE_REG:
3372 if (ppc_is_imm16 (ins->inst_offset)) {
3373 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3375 if (ppc_is_imm32 (ins->inst_offset)) {
3376 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3377 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3379 ppc_load (code, ppc_r0, ins->inst_offset);
3380 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3384 #ifdef __mono_ilp32__
3385 case OP_STOREI8_MEMBASE_REG:
3386 if (ppc_is_imm16 (ins->inst_offset)) {
3387 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3389 ppc_load (code, ppc_r0, ins->inst_offset);
3390 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3394 case OP_STOREI1_MEMINDEX:
3395 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3397 case OP_STOREI2_MEMINDEX:
3398 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3400 case OP_STORE_MEMINDEX:
3401 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3404 g_assert_not_reached ();
3406 case OP_LOAD_MEMBASE:
3407 if (ppc_is_imm16 (ins->inst_offset)) {
3408 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3410 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3411 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3412 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3414 ppc_load (code, ppc_r0, ins->inst_offset);
3415 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3419 case OP_LOADI4_MEMBASE:
3420 #ifdef __mono_ppc64__
3421 if (ppc_is_imm16 (ins->inst_offset)) {
3422 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3424 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3425 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3426 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3428 ppc_load (code, ppc_r0, ins->inst_offset);
3429 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3434 case OP_LOADU4_MEMBASE:
3435 if (ppc_is_imm16 (ins->inst_offset)) {
3436 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3438 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3439 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3440 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3442 ppc_load (code, ppc_r0, ins->inst_offset);
3443 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3447 case OP_LOADI1_MEMBASE:
3448 case OP_LOADU1_MEMBASE:
3449 if (ppc_is_imm16 (ins->inst_offset)) {
3450 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3452 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3453 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3454 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3456 ppc_load (code, ppc_r0, ins->inst_offset);
3457 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3460 if (ins->opcode == OP_LOADI1_MEMBASE)
3461 ppc_extsb (code, ins->dreg, ins->dreg);
3463 case OP_LOADU2_MEMBASE:
3464 if (ppc_is_imm16 (ins->inst_offset)) {
3465 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3467 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3468 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3469 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3471 ppc_load (code, ppc_r0, ins->inst_offset);
3472 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3476 case OP_LOADI2_MEMBASE:
3477 if (ppc_is_imm16 (ins->inst_offset)) {
3478 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3480 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3481 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3482 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3484 ppc_load (code, ppc_r0, ins->inst_offset);
3485 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3489 #ifdef __mono_ilp32__
3490 case OP_LOADI8_MEMBASE:
3491 if (ppc_is_imm16 (ins->inst_offset)) {
3492 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3494 ppc_load (code, ppc_r0, ins->inst_offset);
3495 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3499 case OP_LOAD_MEMINDEX:
3500 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3502 case OP_LOADI4_MEMINDEX:
3503 #ifdef __mono_ppc64__
3504 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3507 case OP_LOADU4_MEMINDEX:
3508 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3510 case OP_LOADU2_MEMINDEX:
3511 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3513 case OP_LOADI2_MEMINDEX:
3514 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3516 case OP_LOADU1_MEMINDEX:
3517 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3519 case OP_LOADI1_MEMINDEX:
3520 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3521 ppc_extsb (code, ins->dreg, ins->dreg);
3523 case OP_ICONV_TO_I1:
3524 CASE_PPC64 (OP_LCONV_TO_I1)
3525 ppc_extsb (code, ins->dreg, ins->sreg1);
3527 case OP_ICONV_TO_I2:
3528 CASE_PPC64 (OP_LCONV_TO_I2)
3529 ppc_extsh (code, ins->dreg, ins->sreg1);
3531 case OP_ICONV_TO_U1:
3532 CASE_PPC64 (OP_LCONV_TO_U1)
3533 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3535 case OP_ICONV_TO_U2:
3536 CASE_PPC64 (OP_LCONV_TO_U2)
3537 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3541 CASE_PPC64 (OP_LCOMPARE)
3542 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3544 if (next && compare_opcode_is_unsigned (next->opcode))
3545 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3547 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3549 case OP_COMPARE_IMM:
3550 case OP_ICOMPARE_IMM:
3551 CASE_PPC64 (OP_LCOMPARE_IMM)
3552 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3554 if (next && compare_opcode_is_unsigned (next->opcode)) {
3555 if (ppc_is_uimm16 (ins->inst_imm)) {
3556 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3558 g_assert_not_reached ();
3561 if (ppc_is_imm16 (ins->inst_imm)) {
3562 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3564 g_assert_not_reached ();
3573 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3576 CASE_PPC64 (OP_LADD)
3577 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3581 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3584 if (ppc_is_imm16 (ins->inst_imm)) {
3585 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3587 g_assert_not_reached ();
3592 CASE_PPC64 (OP_LADD_IMM)
3593 if (ppc_is_imm16 (ins->inst_imm)) {
3594 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3596 g_assert_not_reached ();
3600 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3602 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3603 ppc_mfspr (code, ppc_r0, ppc_xer);
3604 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3605 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3607 case OP_IADD_OVF_UN:
3608 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3610 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3611 ppc_mfspr (code, ppc_r0, ppc_xer);
3612 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3613 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3616 CASE_PPC64 (OP_LSUB_OVF)
3617 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3619 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3620 ppc_mfspr (code, ppc_r0, ppc_xer);
3621 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3622 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3624 case OP_ISUB_OVF_UN:
3625 CASE_PPC64 (OP_LSUB_OVF_UN)
3626 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3628 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3629 ppc_mfspr (code, ppc_r0, ppc_xer);
3630 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3631 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3633 case OP_ADD_OVF_CARRY:
3634 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3636 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 ppc_mfspr (code, ppc_r0, ppc_xer);
3638 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3639 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3641 case OP_ADD_OVF_UN_CARRY:
3642 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3644 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3645 ppc_mfspr (code, ppc_r0, ppc_xer);
3646 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3647 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3649 case OP_SUB_OVF_CARRY:
3650 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3652 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3653 ppc_mfspr (code, ppc_r0, ppc_xer);
3654 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3655 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3657 case OP_SUB_OVF_UN_CARRY:
3658 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3660 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3661 ppc_mfspr (code, ppc_r0, ppc_xer);
3662 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3663 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3667 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3670 CASE_PPC64 (OP_LSUB)
3671 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3675 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3679 CASE_PPC64 (OP_LSUB_IMM)
3680 // we add the negated value
3681 if (ppc_is_imm16 (-ins->inst_imm))
3682 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3684 g_assert_not_reached ();
3688 g_assert (ppc_is_imm16 (ins->inst_imm));
3689 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3692 ppc_subfze (code, ins->dreg, ins->sreg1);
3695 CASE_PPC64 (OP_LAND)
3696 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3697 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3701 CASE_PPC64 (OP_LAND_IMM)
3702 if (!(ins->inst_imm & 0xffff0000)) {
3703 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3704 } else if (!(ins->inst_imm & 0xffff)) {
3705 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3707 g_assert_not_reached ();
3711 CASE_PPC64 (OP_LDIV) {
3712 guint8 *divisor_is_m1;
3713 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3715 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3716 divisor_is_m1 = code;
3717 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3718 ppc_lis (code, ppc_r0, 0x8000);
3719 #ifdef __mono_ppc64__
3720 if (ins->opcode == OP_LDIV)
3721 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3723 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3724 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3725 ppc_patch (divisor_is_m1, code);
3726 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3728 if (ins->opcode == OP_IDIV)
3729 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3730 #ifdef __mono_ppc64__
3732 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3734 ppc_mfspr (code, ppc_r0, ppc_xer);
3735 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3736 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3740 CASE_PPC64 (OP_LDIV_UN)
3741 if (ins->opcode == OP_IDIV_UN)
3742 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3743 #ifdef __mono_ppc64__
3745 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3747 ppc_mfspr (code, ppc_r0, ppc_xer);
3748 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3749 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3755 g_assert_not_reached ();
3758 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3762 CASE_PPC64 (OP_LOR_IMM)
3763 if (!(ins->inst_imm & 0xffff0000)) {
3764 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3765 } else if (!(ins->inst_imm & 0xffff)) {
3766 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3768 g_assert_not_reached ();
3772 CASE_PPC64 (OP_LXOR)
3773 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3777 CASE_PPC64 (OP_LXOR_IMM)
3778 if (!(ins->inst_imm & 0xffff0000)) {
3779 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3780 } else if (!(ins->inst_imm & 0xffff)) {
3781 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3783 g_assert_not_reached ();
3787 CASE_PPC64 (OP_LSHL)
3788 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3792 CASE_PPC64 (OP_LSHL_IMM)
3793 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3796 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3799 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3802 if (MASK_SHIFT_IMM (ins->inst_imm))
3803 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3805 ppc_mr (code, ins->dreg, ins->sreg1);
3808 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3811 CASE_PPC64 (OP_LNOT)
3812 ppc_not (code, ins->dreg, ins->sreg1);
3815 CASE_PPC64 (OP_LNEG)
3816 ppc_neg (code, ins->dreg, ins->sreg1);
3819 CASE_PPC64 (OP_LMUL)
3820 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3824 CASE_PPC64 (OP_LMUL_IMM)
3825 if (ppc_is_imm16 (ins->inst_imm)) {
3826 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3828 g_assert_not_reached ();
3832 CASE_PPC64 (OP_LMUL_OVF)
3833 /* we annot use mcrxr, since it's not implemented on some processors
3834 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3836 if (ins->opcode == OP_IMUL_OVF)
3837 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3838 #ifdef __mono_ppc64__
3840 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3842 ppc_mfspr (code, ppc_r0, ppc_xer);
3843 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3844 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3846 case OP_IMUL_OVF_UN:
3847 CASE_PPC64 (OP_LMUL_OVF_UN)
3848 /* we first multiply to get the high word and compare to 0
3849 * to set the flags, then the result is discarded and then
3850 * we multiply to get the lower * bits result
3852 if (ins->opcode == OP_IMUL_OVF_UN)
3853 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3854 #ifdef __mono_ppc64__
3856 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3858 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3859 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3860 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3863 ppc_load (code, ins->dreg, ins->inst_c0);
3866 ppc_load (code, ins->dreg, ins->inst_l);
3869 case OP_LOAD_GOTADDR:
3870 /* The PLT implementation depends on this */
3871 g_assert (ins->dreg == ppc_r30);
3873 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3876 // FIXME: Fix max instruction length
3877 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3878 /* arch_emit_got_access () patches this */
3879 ppc_load32 (code, ppc_r0, 0);
3880 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3883 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3884 ppc_load_sequence (code, ins->dreg, 0);
3886 CASE_PPC32 (OP_ICONV_TO_I4)
3887 CASE_PPC32 (OP_ICONV_TO_U4)
3889 ppc_mr (code, ins->dreg, ins->sreg1);
3892 int saved = ins->sreg1;
3893 if (ins->sreg1 == ppc_r3) {
3894 ppc_mr (code, ppc_r0, ins->sreg1);
3897 if (ins->sreg2 != ppc_r3)
3898 ppc_mr (code, ppc_r3, ins->sreg2);
3899 if (saved != ppc_r4)
3900 ppc_mr (code, ppc_r4, saved);
3904 ppc_fmr (code, ins->dreg, ins->sreg1);
3906 case OP_FCONV_TO_R4:
3907 ppc_frsp (code, ins->dreg, ins->sreg1);
3913 * Keep in sync with mono_arch_emit_epilog
3915 g_assert (!cfg->method->save_lmf);
3917 * Note: we can use ppc_r11 here because it is dead anyway:
3918 * we're leaving the method.
3920 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3921 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3922 if (ppc_is_imm16 (ret_offset)) {
3923 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3925 ppc_load (code, ppc_r11, ret_offset);
3926 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3928 ppc_mtlr (code, ppc_r0);
3931 code = emit_load_volatile_arguments (cfg, code);
3933 if (ppc_is_imm16 (cfg->stack_usage)) {
3934 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3936 /* cfg->stack_usage is an int, so we can use
3937 * an addis/addi sequence here even in 64-bit. */
3938 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3939 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3941 if (!cfg->method->save_lmf) {
3942 /*for (i = 31; i >= 14; --i) {
3943 if (cfg->used_float_regs & (1 << i)) {
3944 pos += sizeof (double);
3945 ppc_lfd (code, i, -pos, cfg->frame_reg);
3949 for (i = 31; i >= 13; --i) {
3950 if (cfg->used_int_regs & (1 << i)) {
3951 pos += sizeof (gpointer);
3952 ppc_ldptr (code, i, -pos, ppc_r11);
3956 /* FIXME restore from MonoLMF: though this can't happen yet */
3958 ppc_mr (code, ppc_sp, ppc_r11);
3959 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3960 if (cfg->compile_aot) {
3961 /* arch_emit_got_access () patches this */
3962 ppc_load32 (code, ppc_r0, 0);
3963 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3964 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3965 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3967 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3969 ppc_mtctr (code, ppc_r0);
3970 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3977 /* ensure ins->sreg1 is not NULL */
3978 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3981 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3982 if (ppc_is_imm16 (cookie_offset)) {
3983 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3985 ppc_load (code, ppc_r0, cookie_offset);
3986 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3988 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3997 call = (MonoCallInst*)ins;
3998 if (ins->flags & MONO_INST_HAS_METHOD)
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4001 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4002 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4003 ppc_load_func (code, ppc_r0, 0);
4004 ppc_mtlr (code, ppc_r0);
4009 /* FIXME: this should be handled somewhere else in the new jit */
4010 code = emit_move_return_value (cfg, ins, code);
4016 case OP_VOIDCALL_REG:
4018 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4019 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4020 /* FIXME: if we know that this is a method, we
4021 can omit this load */
4022 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4023 ppc_mtlr (code, ppc_r0);
4025 ppc_mtlr (code, ins->sreg1);
4028 /* FIXME: this should be handled somewhere else in the new jit */
4029 code = emit_move_return_value (cfg, ins, code);
4031 case OP_FCALL_MEMBASE:
4032 case OP_LCALL_MEMBASE:
4033 case OP_VCALL_MEMBASE:
4034 case OP_VCALL2_MEMBASE:
4035 case OP_VOIDCALL_MEMBASE:
4036 case OP_CALL_MEMBASE:
4037 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
4038 /* The trampolines clobber this */
4039 ppc_mr (code, ppc_r29, ins->sreg1);
4040 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4042 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4044 ppc_mtlr (code, ppc_r0);
4046 /* FIXME: this should be handled somewhere else in the new jit */
4047 code = emit_move_return_value (cfg, ins, code);
4050 guint8 * zero_loop_jump, * zero_loop_start;
4051 /* keep alignment */
4052 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4053 int area_offset = alloca_waste;
4055 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
4056 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4057 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
4058 /* use ctr to store the number of words to 0 if needed */
4059 if (ins->flags & MONO_INST_INIT) {
4060 /* we zero 4 bytes at a time:
4061 * we add 7 instead of 3 so that we set the counter to
4062 * at least 1, otherwise the bdnz instruction will make
4063 * it negative and iterate billions of times.
4065 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4066 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4067 ppc_mtctr (code, ppc_r0);
4069 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4070 ppc_neg (code, ppc_r11, ppc_r11);
4071 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
4073 /* FIXME: make this loop work in 8 byte
4074 increments on PPC64 */
4075 if (ins->flags & MONO_INST_INIT) {
4076 /* adjust the dest reg by -4 so we can use stwu */
4077 /* we actually adjust -8 because we let the loop
4080 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4081 ppc_li (code, ppc_r11, 0);
4082 zero_loop_start = code;
4083 ppc_stwu (code, ppc_r11, 4, ins->dreg);
4084 zero_loop_jump = code;
4085 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4086 ppc_patch (zero_loop_jump, zero_loop_start);
4088 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4093 ppc_mr (code, ppc_r3, ins->sreg1);
4094 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4095 (gpointer)"mono_arch_throw_exception");
4096 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4097 ppc_load_func (code, ppc_r0, 0);
4098 ppc_mtlr (code, ppc_r0);
4107 ppc_mr (code, ppc_r3, ins->sreg1);
4108 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
4109 (gpointer)"mono_arch_rethrow_exception");
4110 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4111 ppc_load_func (code, ppc_r0, 0);
4112 ppc_mtlr (code, ppc_r0);
4119 case OP_START_HANDLER: {
4120 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4121 g_assert (spvar->inst_basereg != ppc_sp);
4122 code = emit_reserve_param_area (cfg, code);
4123 ppc_mflr (code, ppc_r0);
4124 if (ppc_is_imm16 (spvar->inst_offset)) {
4125 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4127 ppc_load (code, ppc_r11, spvar->inst_offset);
4128 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
4132 case OP_ENDFILTER: {
4133 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4134 g_assert (spvar->inst_basereg != ppc_sp);
4135 code = emit_unreserve_param_area (cfg, code);
4136 if (ins->sreg1 != ppc_r3)
4137 ppc_mr (code, ppc_r3, ins->sreg1);
4138 if (ppc_is_imm16 (spvar->inst_offset)) {
4139 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4141 ppc_load (code, ppc_r11, spvar->inst_offset);
4142 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
4144 ppc_mtlr (code, ppc_r0);
4148 case OP_ENDFINALLY: {
4149 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4150 g_assert (spvar->inst_basereg != ppc_sp);
4151 code = emit_unreserve_param_area (cfg, code);
4152 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4153 ppc_mtlr (code, ppc_r0);
4157 case OP_CALL_HANDLER:
4158 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4160 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4163 ins->inst_c0 = code - cfg->native_code;
4166 /*if (ins->inst_target_bb->native_offset) {
4168 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
4170 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4175 ppc_mtctr (code, ins->sreg1);
4176 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4180 CASE_PPC64 (OP_LCEQ)
4181 ppc_li (code, ins->dreg, 0);
4182 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4183 ppc_li (code, ins->dreg, 1);
4189 CASE_PPC64 (OP_LCLT)
4190 CASE_PPC64 (OP_LCLT_UN)
4191 ppc_li (code, ins->dreg, 1);
4192 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4193 ppc_li (code, ins->dreg, 0);
4199 CASE_PPC64 (OP_LCGT)
4200 CASE_PPC64 (OP_LCGT_UN)
4201 ppc_li (code, ins->dreg, 1);
4202 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4203 ppc_li (code, ins->dreg, 0);
4205 case OP_COND_EXC_EQ:
4206 case OP_COND_EXC_NE_UN:
4207 case OP_COND_EXC_LT:
4208 case OP_COND_EXC_LT_UN:
4209 case OP_COND_EXC_GT:
4210 case OP_COND_EXC_GT_UN:
4211 case OP_COND_EXC_GE:
4212 case OP_COND_EXC_GE_UN:
4213 case OP_COND_EXC_LE:
4214 case OP_COND_EXC_LE_UN:
4215 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4217 case OP_COND_EXC_IEQ:
4218 case OP_COND_EXC_INE_UN:
4219 case OP_COND_EXC_ILT:
4220 case OP_COND_EXC_ILT_UN:
4221 case OP_COND_EXC_IGT:
4222 case OP_COND_EXC_IGT_UN:
4223 case OP_COND_EXC_IGE:
4224 case OP_COND_EXC_IGE_UN:
4225 case OP_COND_EXC_ILE:
4226 case OP_COND_EXC_ILE_UN:
4227 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4239 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4242 /* floating point opcodes */
4244 g_assert (cfg->compile_aot);
4246 /* FIXME: Optimize this */
4248 ppc_mflr (code, ppc_r11);
4250 *(double*)code = *(double*)ins->inst_p0;
4252 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4255 g_assert_not_reached ();
4257 case OP_STORER8_MEMBASE_REG:
4258 if (ppc_is_imm16 (ins->inst_offset)) {
4259 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4261 if (ppc_is_imm32 (ins->inst_offset)) {
4262 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4263 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4265 ppc_load (code, ppc_r0, ins->inst_offset);
4266 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4270 case OP_LOADR8_MEMBASE:
4271 if (ppc_is_imm16 (ins->inst_offset)) {
4272 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4274 if (ppc_is_imm32 (ins->inst_offset)) {
4275 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4276 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4278 ppc_load (code, ppc_r0, ins->inst_offset);
4279 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4283 case OP_STORER4_MEMBASE_REG:
4284 ppc_frsp (code, ins->sreg1, ins->sreg1);
4285 if (ppc_is_imm16 (ins->inst_offset)) {
4286 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4288 if (ppc_is_imm32 (ins->inst_offset)) {
4289 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4290 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4292 ppc_load (code, ppc_r0, ins->inst_offset);
4293 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4297 case OP_LOADR4_MEMBASE:
4298 if (ppc_is_imm16 (ins->inst_offset)) {
4299 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4301 if (ppc_is_imm32 (ins->inst_offset)) {
4302 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4303 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4305 ppc_load (code, ppc_r0, ins->inst_offset);
4306 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4310 case OP_LOADR4_MEMINDEX:
4311 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4313 case OP_LOADR8_MEMINDEX:
4314 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4316 case OP_STORER4_MEMINDEX:
4317 ppc_frsp (code, ins->sreg1, ins->sreg1);
4318 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4320 case OP_STORER8_MEMINDEX:
4321 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4324 case CEE_CONV_R4: /* FIXME: change precision */
4326 g_assert_not_reached ();
4327 case OP_FCONV_TO_I1:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4330 case OP_FCONV_TO_U1:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4333 case OP_FCONV_TO_I2:
4334 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4336 case OP_FCONV_TO_U2:
4337 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4339 case OP_FCONV_TO_I4:
4341 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4343 case OP_FCONV_TO_U4:
4345 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4347 case OP_LCONV_TO_R_UN:
4348 g_assert_not_reached ();
4349 /* Implemented as helper calls */
4351 case OP_LCONV_TO_OVF_I4_2:
4352 case OP_LCONV_TO_OVF_I: {
4353 #ifdef __mono_ppc64__
4356 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4357 // Check if its negative
4358 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4359 negative_branch = code;
4360 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4361 // Its positive msword == 0
4362 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4363 msword_positive_branch = code;
4364 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4366 ovf_ex_target = code;
4367 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4369 ppc_patch (negative_branch, code);
4370 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4371 msword_negative_branch = code;
4372 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4373 ppc_patch (msword_negative_branch, ovf_ex_target);
4375 ppc_patch (msword_positive_branch, code);
4376 if (ins->dreg != ins->sreg1)
4377 ppc_mr (code, ins->dreg, ins->sreg1);
4382 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4385 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4388 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4391 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4394 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4397 ppc_fneg (code, ins->dreg, ins->sreg1);
4401 g_assert_not_reached ();
4404 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4407 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4408 ppc_li (code, ins->dreg, 0);
4409 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4410 ppc_li (code, ins->dreg, 1);
4413 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4414 ppc_li (code, ins->dreg, 1);
4415 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4416 ppc_li (code, ins->dreg, 0);
4419 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4420 ppc_li (code, ins->dreg, 1);
4421 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4422 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4423 ppc_li (code, ins->dreg, 0);
4426 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4427 ppc_li (code, ins->dreg, 1);
4428 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4429 ppc_li (code, ins->dreg, 0);
4432 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4433 ppc_li (code, ins->dreg, 1);
4434 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4435 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4436 ppc_li (code, ins->dreg, 0);
4439 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4442 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4445 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4446 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4449 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4450 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4453 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4454 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4457 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4458 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4461 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4462 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4465 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4468 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4469 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4472 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4475 g_assert_not_reached ();
4476 case OP_CHECK_FINITE: {
4477 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4478 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4479 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4480 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4483 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4484 #ifdef __mono_ppc64__
4485 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4487 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4492 #ifdef __mono_ppc64__
4493 case OP_ICONV_TO_I4:
4495 ppc_extsw (code, ins->dreg, ins->sreg1);
4497 case OP_ICONV_TO_U4:
4499 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4501 case OP_ICONV_TO_R4:
4502 case OP_ICONV_TO_R8:
4503 case OP_LCONV_TO_R4:
4504 case OP_LCONV_TO_R8: {
4506 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4507 ppc_extsw (code, ppc_r0, ins->sreg1);
4512 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4513 ppc_mffgpr (code, ins->dreg, tmp);
4515 ppc_str (code, tmp, -8, ppc_r1);
4516 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4518 ppc_fcfid (code, ins->dreg, ins->dreg);
4519 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4520 ppc_frsp (code, ins->dreg, ins->dreg);
4524 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4527 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4530 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4532 ppc_mfspr (code, ppc_r0, ppc_xer);
4533 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4534 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4536 case OP_COND_EXC_OV:
4537 ppc_mfspr (code, ppc_r0, ppc_xer);
4538 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4539 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4551 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4553 case OP_FCONV_TO_I8:
4554 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4556 case OP_FCONV_TO_U8:
4557 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4559 case OP_STOREI4_MEMBASE_REG:
4560 if (ppc_is_imm16 (ins->inst_offset)) {
4561 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4563 ppc_load (code, ppc_r0, ins->inst_offset);
4564 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4567 case OP_STOREI4_MEMINDEX:
4568 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4571 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4573 case OP_ISHR_UN_IMM:
4574 if (ins->inst_imm & 0x1f)
4575 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4577 ppc_mr (code, ins->dreg, ins->sreg1);
4579 case OP_ATOMIC_ADD_NEW_I4:
4580 case OP_ATOMIC_ADD_NEW_I8: {
4581 guint8 *loop = code, *branch;
4582 g_assert (ins->inst_offset == 0);
4583 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4584 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4586 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4587 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4588 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4589 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4591 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4593 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4594 ppc_patch (branch, loop);
4595 ppc_mr (code, ins->dreg, ppc_r0);
4599 case OP_ICONV_TO_R4:
4600 case OP_ICONV_TO_R8: {
4601 if (cpu_hw_caps & PPC_ISA_64) {
4602 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4603 ppc_stw (code, ppc_r0, -8, ppc_r1);
4604 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4605 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4606 ppc_fcfid (code, ins->dreg, ins->dreg);
4607 if (ins->opcode == OP_ICONV_TO_R4)
4608 ppc_frsp (code, ins->dreg, ins->dreg);
4613 case OP_ATOMIC_CAS_I4:
4614 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4615 int location = ins->sreg1;
4616 int value = ins->sreg2;
4617 int comparand = ins->sreg3;
4618 guint8 *start, *not_equal, *lost_reservation;
4621 if (ins->opcode == OP_ATOMIC_CAS_I4)
4622 ppc_lwarx (code, ppc_r0, 0, location);
4623 #ifdef __mono_ppc64__
4625 ppc_ldarx (code, ppc_r0, 0, location);
4627 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4630 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4631 if (ins->opcode == OP_ATOMIC_CAS_I4)
4632 ppc_stwcxd (code, value, 0, location);
4633 #ifdef __mono_ppc64__
4635 ppc_stdcxd (code, value, 0, location);
4638 lost_reservation = code;
4639 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4640 ppc_patch (lost_reservation, start);
4642 ppc_patch (not_equal, code);
4643 ppc_mr (code, ins->dreg, ppc_r0);
4648 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4649 g_assert_not_reached ();
4652 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4653 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4654 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4655 g_assert_not_reached ();
4661 last_offset = offset;
4664 cfg->code_len = code - cfg->native_code;
4666 #endif /* !DISABLE_JIT */
4669 mono_arch_register_lowlevel_calls (void)
4671 /* The signature doesn't matter */
4672 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4675 #ifdef __mono_ppc64__
4676 #define patch_load_sequence(ip,val) do {\
4677 guint16 *__load = (guint16*)(ip); \
4678 g_assert (sizeof (val) == sizeof (gsize)); \
4679 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4680 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4681 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4682 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4685 #define patch_load_sequence(ip,val) do {\
4686 guint16 *__lis_ori = (guint16*)(ip); \
4687 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4688 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4694 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4696 MonoJumpInfo *patch_info;
4697 gboolean compile_aot = !run_cctors;
4699 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4700 unsigned char *ip = patch_info->ip.i + code;
4701 unsigned char *target;
4702 gboolean is_fd = FALSE;
4704 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4707 switch (patch_info->type) {
4708 case MONO_PATCH_INFO_BB:
4709 case MONO_PATCH_INFO_LABEL:
4712 /* No need to patch these */
4717 switch (patch_info->type) {
4718 case MONO_PATCH_INFO_IP:
4719 patch_load_sequence (ip, ip);
4721 case MONO_PATCH_INFO_METHOD_REL:
4722 g_assert_not_reached ();
4723 *((gpointer *)(ip)) = code + patch_info->data.offset;
4725 case MONO_PATCH_INFO_SWITCH: {
4726 gpointer *table = (gpointer *)patch_info->data.table->table;
4729 patch_load_sequence (ip, table);
4731 for (i = 0; i < patch_info->data.table->table_size; i++) {
4732 table [i] = (glong)patch_info->data.table->table [i] + code;
4734 /* we put into the table the absolute address, no need for ppc_patch in this case */
4737 case MONO_PATCH_INFO_METHODCONST:
4738 case MONO_PATCH_INFO_CLASS:
4739 case MONO_PATCH_INFO_IMAGE:
4740 case MONO_PATCH_INFO_FIELD:
4741 case MONO_PATCH_INFO_VTABLE:
4742 case MONO_PATCH_INFO_IID:
4743 case MONO_PATCH_INFO_SFLDA:
4744 case MONO_PATCH_INFO_LDSTR:
4745 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4746 case MONO_PATCH_INFO_LDTOKEN:
4747 /* from OP_AOTCONST : lis + ori */
4748 patch_load_sequence (ip, target);
4750 case MONO_PATCH_INFO_R4:
4751 case MONO_PATCH_INFO_R8:
4752 g_assert_not_reached ();
4753 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4755 case MONO_PATCH_INFO_EXC_NAME:
4756 g_assert_not_reached ();
4757 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4759 case MONO_PATCH_INFO_NONE:
4760 case MONO_PATCH_INFO_BB_OVF:
4761 case MONO_PATCH_INFO_EXC_OVF:
4762 /* everything is dealt with at epilog output time */
4764 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4765 case MONO_PATCH_INFO_INTERNAL_METHOD:
4766 case MONO_PATCH_INFO_ABS:
4767 case MONO_PATCH_INFO_CLASS_INIT:
4768 case MONO_PATCH_INFO_RGCTX_FETCH:
4775 ppc_patch_full (ip, target, is_fd);
4780 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4781 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4782 * the instruction offset immediate for all the registers.
4785 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4789 for (i = 13; i <= 31; i++) {
4790 if (used_int_regs & (1 << i)) {
4791 ppc_str (code, i, pos, base_reg);
4792 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4793 pos += sizeof (mgreg_t);
4797 /* pos is the start of the MonoLMF structure */
4798 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4799 for (i = 13; i <= 31; i++) {
4800 ppc_str (code, i, offset, base_reg);
4801 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4802 offset += sizeof (mgreg_t);
4804 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4805 for (i = 14; i < 32; i++) {
4806 ppc_stfd (code, i, offset, base_reg);
4807 offset += sizeof (gdouble);
4814 * Stack frame layout:
4816 * ------------------- sp
4817 * MonoLMF structure or saved registers
4818 * -------------------
4820 * -------------------
4822 * -------------------
4823 * optional 8 bytes for tracing
4824 * -------------------
4825 * param area size is cfg->param_area
4826 * -------------------
4827 * linkage area size is PPC_STACK_PARAM_OFFSET
4828 * ------------------- sp
4832 mono_arch_emit_prolog (MonoCompile *cfg)
4834 MonoMethod *method = cfg->method;
4836 MonoMethodSignature *sig;
4838 long alloc_size, pos, max_offset, cfa_offset;
4844 int tailcall_struct_index;
4846 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4849 sig = mono_method_signature (method);
4850 cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4851 code = cfg->native_code = g_malloc (cfg->code_size);
4855 /* We currently emit unwind info for aot, but don't use it */
4856 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4858 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4859 ppc_mflr (code, ppc_r0);
4860 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4861 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4864 alloc_size = cfg->stack_offset;
4867 if (!method->save_lmf) {
4868 for (i = 31; i >= 13; --i) {
4869 if (cfg->used_int_regs & (1 << i)) {
4870 pos += sizeof (mgreg_t);
4874 pos += sizeof (MonoLMF);
4878 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4879 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4880 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4881 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4884 cfg->stack_usage = alloc_size;
4885 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4887 if (ppc_is_imm16 (-alloc_size)) {
4888 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4889 cfa_offset = alloc_size;
4890 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4891 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4894 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4895 ppc_load (code, ppc_r0, -alloc_size);
4896 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4897 cfa_offset = alloc_size;
4898 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4899 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4902 if (cfg->frame_reg != ppc_sp) {
4903 ppc_mr (code, cfg->frame_reg, ppc_sp);
4904 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4907 /* store runtime generic context */
4908 if (cfg->rgctx_var) {
4909 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4910 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4912 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4915 /* compute max_offset in order to use short forward jumps
4916 * we always do it on ppc because the immediate displacement
4917 * for jumps is too small
4920 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4922 bb->max_offset = max_offset;
4924 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4927 MONO_BB_FOR_EACH_INS (bb, ins)
4928 max_offset += ins_native_length (cfg, ins);
4931 /* load arguments allocated to register from the stack */
4934 cinfo = calculate_sizes (sig, sig->pinvoke);
4936 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4937 ArgInfo *ainfo = &cinfo->ret;
4939 inst = cfg->vret_addr;
4942 if (ppc_is_imm16 (inst->inst_offset)) {
4943 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4945 ppc_load (code, ppc_r11, inst->inst_offset);
4946 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4950 tailcall_struct_index = 0;
4951 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4952 ArgInfo *ainfo = cinfo->args + i;
4953 inst = cfg->args [pos];
4955 if (cfg->verbose_level > 2)
4956 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4957 if (inst->opcode == OP_REGVAR) {
4958 if (ainfo->regtype == RegTypeGeneral)
4959 ppc_mr (code, inst->dreg, ainfo->reg);
4960 else if (ainfo->regtype == RegTypeFP)
4961 ppc_fmr (code, inst->dreg, ainfo->reg);
4962 else if (ainfo->regtype == RegTypeBase) {
4963 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4964 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4966 g_assert_not_reached ();
4968 if (cfg->verbose_level > 2)
4969 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4971 /* the argument should be put on the stack: FIXME handle size != word */
4972 if (ainfo->regtype == RegTypeGeneral) {
4973 switch (ainfo->size) {
4975 if (ppc_is_imm16 (inst->inst_offset)) {
4976 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4978 if (ppc_is_imm32 (inst->inst_offset)) {
4979 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4980 ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
4982 ppc_load (code, ppc_r11, inst->inst_offset);
4983 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4988 if (ppc_is_imm16 (inst->inst_offset)) {
4989 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4991 if (ppc_is_imm32 (inst->inst_offset)) {
4992 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4993 ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
4995 ppc_load (code, ppc_r11, inst->inst_offset);
4996 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5000 #ifdef __mono_ppc64__
5002 if (ppc_is_imm16 (inst->inst_offset)) {
5003 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5005 if (ppc_is_imm32 (inst->inst_offset)) {
5006 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5007 ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
5009 ppc_load (code, ppc_r11, inst->inst_offset);
5010 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5015 if (ppc_is_imm16 (inst->inst_offset)) {
5016 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5018 ppc_load (code, ppc_r11, inst->inst_offset);
5019 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
5024 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5025 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5026 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5028 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5029 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5030 ppc_stw (code, ainfo->reg, 0, ppc_r11);
5031 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
5036 if (ppc_is_imm16 (inst->inst_offset)) {
5037 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5039 if (ppc_is_imm32 (inst->inst_offset)) {
5040 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5041 ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
5043 ppc_load (code, ppc_r11, inst->inst_offset);
5044 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
5049 } else if (ainfo->regtype == RegTypeBase) {
5050 g_assert (ppc_is_imm16 (ainfo->offset));
5051 /* load the previous stack pointer in r11 */
5052 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5053 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
5054 switch (ainfo->size) {
5056 if (ppc_is_imm16 (inst->inst_offset)) {
5057 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5059 if (ppc_is_imm32 (inst->inst_offset)) {
5060 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5061 ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
5063 ppc_load (code, ppc_r11, inst->inst_offset);
5064 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5069 if (ppc_is_imm16 (inst->inst_offset)) {
5070 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5072 if (ppc_is_imm32 (inst->inst_offset)) {
5073 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5074 ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
5076 ppc_load (code, ppc_r11, inst->inst_offset);
5077 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5081 #ifdef __mono_ppc64__
5083 if (ppc_is_imm16 (inst->inst_offset)) {
5084 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5086 if (ppc_is_imm32 (inst->inst_offset)) {
5087 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5088 ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
5090 ppc_load (code, ppc_r11, inst->inst_offset);
5091 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
5096 if (ppc_is_imm16 (inst->inst_offset)) {
5097 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5099 ppc_load (code, ppc_r11, inst->inst_offset);
5100 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
5105 g_assert (ppc_is_imm16 (ainfo->offset + 4));
5106 if (ppc_is_imm16 (inst->inst_offset + 4)) {
5107 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5108 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
5109 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5111 /* use r12 to load the 2nd half of the long before we clobber r11. */
5112 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
5113 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5114 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
5115 ppc_stw (code, ppc_r0, 0, ppc_r11);
5116 ppc_stw (code, ppc_r12, 4, ppc_r11);
5121 if (ppc_is_imm16 (inst->inst_offset)) {
5122 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5124 if (ppc_is_imm32 (inst->inst_offset)) {
5125 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
5126 ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
5128 ppc_load (code, ppc_r11, inst->inst_offset);
5129 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
5134 } else if (ainfo->regtype == RegTypeFP) {
5135 g_assert (ppc_is_imm16 (inst->inst_offset));
5136 if (ainfo->size == 8)
5137 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5138 else if (ainfo->size == 4)
5139 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5141 g_assert_not_reached ();
5142 } else if (ainfo->regtype == RegTypeStructByVal) {
5143 int doffset = inst->inst_offset;
5147 g_assert (ppc_is_imm16 (inst->inst_offset));
5148 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5149 /* FIXME: what if there is no class? */
5150 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5151 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5152 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5155 * Darwin handles 1 and 2 byte
5156 * structs specially by
5157 * loading h/b into the arg
5158 * register. Only done for
5162 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5164 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5168 #ifdef __mono_ppc64__
5170 g_assert (cur_reg == 0);
5171 ppc_sldi (code, ppc_r0, ainfo->reg,
5172 (sizeof (gpointer) - ainfo->bytes) * 8);
5173 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5177 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5178 inst->inst_basereg);
5181 soffset += sizeof (gpointer);
5182 doffset += sizeof (gpointer);
5184 if (ainfo->vtsize) {
5185 /* FIXME: we need to do the shifting here, too */
5188 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5189 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5190 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5191 code = emit_memcpy (code, size - soffset,
5192 inst->inst_basereg, doffset,
5193 ppc_r11, ainfo->offset + soffset);
5195 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5196 inst->inst_basereg, doffset,
5197 ppc_r11, ainfo->offset + soffset);
5200 } else if (ainfo->regtype == RegTypeStructByAddr) {
5201 /* if it was originally a RegTypeBase */
5202 if (ainfo->offset) {
5203 /* load the previous stack pointer in r11 */
5204 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5205 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5207 ppc_mr (code, ppc_r11, ainfo->reg);
5210 if (cfg->tailcall_valuetype_addrs) {
5211 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5213 g_assert (ppc_is_imm16 (addr->inst_offset));
5214 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5216 tailcall_struct_index++;
5219 g_assert (ppc_is_imm16 (inst->inst_offset));
5220 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5221 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5223 g_assert_not_reached ();
5228 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5229 if (cfg->compile_aot)
5230 /* AOT code is only used in the root domain */
5231 ppc_load_ptr (code, ppc_r3, 0);
5233 ppc_load_ptr (code, ppc_r3, cfg->domain);
5234 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
5235 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5236 ppc_load_func (code, ppc_r0, 0);
5237 ppc_mtlr (code, ppc_r0);
5244 if (method->save_lmf) {
5245 if (lmf_pthread_key != -1) {
5246 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5247 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5248 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5250 if (cfg->compile_aot) {
5251 /* Compute the got address which is needed by the PLT entry */
5252 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5254 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5255 (gpointer)"mono_get_lmf_addr");
5256 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5257 ppc_load_func (code, ppc_r0, 0);
5258 ppc_mtlr (code, ppc_r0);
5264 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5265 /* lmf_offset is the offset from the previous stack pointer,
5266 * alloc_size is the total stack space allocated, so the offset
5267 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5268 * The pointer to the struct is put in ppc_r11 (new_lmf).
5269 * The callee-saved registers are already in the MonoLMF structure
5271 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5272 /* ppc_r3 is the result from mono_get_lmf_addr () */
5273 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5274 /* new_lmf->previous_lmf = *lmf_addr */
5275 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5276 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5277 /* *(lmf_addr) = r11 */
5278 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5279 /* save method info */
5280 if (cfg->compile_aot)
5282 ppc_load (code, ppc_r0, 0);
5284 ppc_load_ptr (code, ppc_r0, method);
5285 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5286 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5287 /* save the current IP */
5288 if (cfg->compile_aot) {
5290 ppc_mflr (code, ppc_r0);
5292 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5293 #ifdef __mono_ppc64__
5294 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5296 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5299 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5303 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5305 cfg->code_len = code - cfg->native_code;
5306 g_assert (cfg->code_len <= cfg->code_size);
5313 mono_arch_emit_epilog (MonoCompile *cfg)
5315 MonoMethod *method = cfg->method;
5317 int max_epilog_size = 16 + 20*4;
5320 if (cfg->method->save_lmf)
5321 max_epilog_size += 128;
5323 if (mono_jit_trace_calls != NULL)
5324 max_epilog_size += 50;
5326 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5327 max_epilog_size += 50;
5329 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5330 cfg->code_size *= 2;
5331 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5332 mono_jit_stats.code_reallocs++;
5336 * Keep in sync with OP_JMP
5338 code = cfg->native_code + cfg->code_len;
5340 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5341 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5345 if (method->save_lmf) {
5347 pos += sizeof (MonoLMF);
5349 /* save the frame reg in r8 */
5350 ppc_mr (code, ppc_r8, cfg->frame_reg);
5351 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5352 /* r5 = previous_lmf */
5353 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5355 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5356 /* *(lmf_addr) = previous_lmf */
5357 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5358 /* FIXME: speedup: there is no actual need to restore the registers if
5359 * we didn't actually change them (idea from Zoltan).
5362 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5364 /*for (i = 14; i < 32; i++) {
5365 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5367 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5368 /* use the saved copy of the frame reg in r8 */
5369 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5370 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5371 ppc_mtlr (code, ppc_r0);
5373 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5375 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5376 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5377 if (ppc_is_imm16 (return_offset)) {
5378 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5380 ppc_load (code, ppc_r11, return_offset);
5381 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5383 ppc_mtlr (code, ppc_r0);
5385 if (ppc_is_imm16 (cfg->stack_usage)) {
5386 int offset = cfg->stack_usage;
5387 for (i = 13; i <= 31; i++) {
5388 if (cfg->used_int_regs & (1 << i))
5389 offset -= sizeof (mgreg_t);
5391 if (cfg->frame_reg != ppc_sp)
5392 ppc_mr (code, ppc_r11, cfg->frame_reg);
5393 /* note r31 (possibly the frame register) is restored last */
5394 for (i = 13; i <= 31; i++) {
5395 if (cfg->used_int_regs & (1 << i)) {
5396 ppc_ldr (code, i, offset, cfg->frame_reg);
5397 offset += sizeof (mgreg_t);
5400 if (cfg->frame_reg != ppc_sp)
5401 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5403 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5405 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5406 if (cfg->used_int_regs) {
5407 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5408 for (i = 31; i >= 13; --i) {
5409 if (cfg->used_int_regs & (1 << i)) {
5410 pos += sizeof (mgreg_t);
5411 ppc_ldr (code, i, -pos, ppc_r11);
5414 ppc_mr (code, ppc_sp, ppc_r11);
5416 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5423 cfg->code_len = code - cfg->native_code;
5425 g_assert (cfg->code_len < cfg->code_size);
5428 #endif /* ifndef DISABLE_JIT */
5430 /* remove once throw_exception_by_name is eliminated */
5432 exception_id_by_name (const char *name)
5434 if (strcmp (name, "IndexOutOfRangeException") == 0)
5435 return MONO_EXC_INDEX_OUT_OF_RANGE;
5436 if (strcmp (name, "OverflowException") == 0)
5437 return MONO_EXC_OVERFLOW;
5438 if (strcmp (name, "ArithmeticException") == 0)
5439 return MONO_EXC_ARITHMETIC;
5440 if (strcmp (name, "DivideByZeroException") == 0)
5441 return MONO_EXC_DIVIDE_BY_ZERO;
5442 if (strcmp (name, "InvalidCastException") == 0)
5443 return MONO_EXC_INVALID_CAST;
5444 if (strcmp (name, "NullReferenceException") == 0)
5445 return MONO_EXC_NULL_REF;
5446 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5447 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5448 g_error ("Unknown intrinsic exception %s\n", name);
5454 mono_arch_emit_exceptions (MonoCompile *cfg)
5456 MonoJumpInfo *patch_info;
5459 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5460 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5461 int max_epilog_size = 50;
5463 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5464 exc_throw_pos [i] = NULL;
5465 exc_throw_found [i] = 0;
5468 /* count the number of exception infos */
5471 * make sure we have enough space for exceptions
5473 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5474 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5475 i = exception_id_by_name (patch_info->data.target);
5476 if (!exc_throw_found [i]) {
5477 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5478 exc_throw_found [i] = TRUE;
5480 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5481 max_epilog_size += 12;
5482 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5483 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5484 i = exception_id_by_name (ovfj->data.exception);
5485 if (!exc_throw_found [i]) {
5486 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5487 exc_throw_found [i] = TRUE;
5489 max_epilog_size += 8;
5493 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5494 cfg->code_size *= 2;
5495 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5496 mono_jit_stats.code_reallocs++;
5499 code = cfg->native_code + cfg->code_len;
5501 /* add code to raise exceptions */
5502 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5503 switch (patch_info->type) {
5504 case MONO_PATCH_INFO_BB_OVF: {
5505 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5506 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5507 /* patch the initial jump */
5508 ppc_patch (ip, code);
5509 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5511 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5512 /* jump back to the true target */
5514 ip = ovfj->data.bb->native_offset + cfg->native_code;
5515 ppc_patch (code - 4, ip);
5516 patch_info->type = MONO_PATCH_INFO_NONE;
5519 case MONO_PATCH_INFO_EXC_OVF: {
5520 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5521 MonoJumpInfo *newji;
5522 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5523 unsigned char *bcl = code;
5524 /* patch the initial jump: we arrived here with a call */
5525 ppc_patch (ip, code);
5526 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5528 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5529 /* patch the conditional jump to the right handler */
5530 /* make it processed next */
5531 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5532 newji->type = MONO_PATCH_INFO_EXC;
5533 newji->ip.i = bcl - cfg->native_code;
5534 newji->data.target = ovfj->data.exception;
5535 newji->next = patch_info->next;
5536 patch_info->next = newji;
5537 patch_info->type = MONO_PATCH_INFO_NONE;
5540 case MONO_PATCH_INFO_EXC: {
5541 MonoClass *exc_class;
5543 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5544 i = exception_id_by_name (patch_info->data.target);
5545 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5546 ppc_patch (ip, exc_throw_pos [i]);
5547 patch_info->type = MONO_PATCH_INFO_NONE;
5550 exc_throw_pos [i] = code;
5553 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5554 g_assert (exc_class);
5556 ppc_patch (ip, code);
5557 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5558 ppc_load (code, ppc_r3, exc_class->type_token);
5559 /* we got here from a conditional call, so the calling ip is set in lr */
5560 ppc_mflr (code, ppc_r4);
5561 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5562 patch_info->data.name = "mono_arch_throw_corlib_exception";
5563 patch_info->ip.i = code - cfg->native_code;
5564 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5565 ppc_load_func (code, ppc_r0, 0);
5566 ppc_mtctr (code, ppc_r0);
5567 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5579 cfg->code_len = code - cfg->native_code;
5581 g_assert (cfg->code_len <= cfg->code_size);
5587 try_offset_access (void *value, guint32 idx)
5589 register void* me __asm__ ("r2");
5590 void ***p = (void***)((char*)me + 284);
5591 int idx1 = idx / 32;
5592 int idx2 = idx % 32;
5595 if (value != p[idx1][idx2])
5602 setup_tls_access (void)
5606 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5607 size_t conf_size = 0;
5610 /* FIXME for darwin */
5611 guint32 *ins, *code;
5612 guint32 cmplwi_1023, li_0x48, blr_ins;
5616 tls_mode = TLS_MODE_FAILED;
5619 if (tls_mode == TLS_MODE_FAILED)
5621 if (g_getenv ("MONO_NO_TLS")) {
5622 tls_mode = TLS_MODE_FAILED;
5626 if (tls_mode == TLS_MODE_DETECT) {
5627 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5628 tls_mode = TLS_MODE_DARWIN_G4;
5629 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5630 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5631 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5632 tls_mode = TLS_MODE_NPTL;
5633 #elif !defined(TARGET_PS3)
5634 ins = (guint32*)pthread_getspecific;
5635 /* uncond branch to the real method */
5636 if ((*ins >> 26) == 18) {
5638 val = (*ins & ~3) << 6;
5642 ins = (guint32*)(long)val;
5644 ins = (guint32*) ((char*)ins + val);
5647 code = &cmplwi_1023;
5648 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5650 ppc_li (code, ppc_r4, 0x48);
5653 if (*ins == cmplwi_1023) {
5654 int found_lwz_284 = 0;
5655 for (ptk = 0; ptk < 20; ++ptk) {
5657 if (!*ins || *ins == blr_ins)
5659 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5664 if (!found_lwz_284) {
5665 tls_mode = TLS_MODE_FAILED;
5668 tls_mode = TLS_MODE_LTHREADS;
5669 } else if (*ins == li_0x48) {
5671 /* uncond branch to the real method */
5672 if ((*ins >> 26) == 18) {
5674 val = (*ins & ~3) << 6;
5678 ins = (guint32*)(long)val;
5680 ins = (guint32*) ((char*)ins + val);
5682 code = (guint32*)&val;
5683 ppc_li (code, ppc_r0, 0x7FF2);
5684 if (ins [1] == val) {
5685 /* Darwin on G4, implement */
5686 tls_mode = TLS_MODE_FAILED;
5689 code = (guint32*)&val;
5690 ppc_mfspr (code, ppc_r3, 104);
5691 if (ins [1] != val) {
5692 tls_mode = TLS_MODE_FAILED;
5695 tls_mode = TLS_MODE_DARWIN_G5;
5698 tls_mode = TLS_MODE_FAILED;
5702 tls_mode = TLS_MODE_FAILED;
5708 if (tls_mode == TLS_MODE_DETECT)
5709 tls_mode = TLS_MODE_FAILED;
5710 if (tls_mode == TLS_MODE_FAILED)
5712 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5713 monodomain_key = mono_domain_get_tls_offset();
5715 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5716 mono_domain_get_tls_offset returning -1) then use keyed access. */
5717 if (monodomain_key == -1) {
5718 ptk = mono_domain_get_tls_key ();
5720 ptk = mono_pthread_key_for_tls (ptk);
5722 monodomain_key = ptk;
5727 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5728 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5730 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5731 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5732 if (lmf_pthread_key == -1) {
5733 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5735 /*g_print ("MonoLMF at: %d\n", ptk);*/
5736 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5737 init_tls_failed = 1;
5740 lmf_pthread_key = ptk;
5747 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5749 setup_tls_access ();
5753 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5757 #ifdef MONO_ARCH_HAVE_IMT
5759 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5761 #define LOADSTORE_SIZE 4
5762 #define JUMP_IMM_SIZE 12
5763 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5764 #define ENABLE_WRONG_METHOD_CHECK 0
5767 * LOCKING: called with the domain lock held
5770 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5771 gpointer fail_tramp)
5775 guint8 *code, *start;
5777 for (i = 0; i < count; ++i) {
5778 MonoIMTCheckItem *item = imt_entries [i];
5779 if (item->is_equals) {
5780 if (item->check_target_idx) {
5781 if (!item->compare_done)
5782 item->chunk_size += CMP_SIZE;
5783 if (item->has_target_code)
5784 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5786 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5789 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5790 if (!item->has_target_code)
5791 item->chunk_size += LOADSTORE_SIZE;
5793 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5794 #if ENABLE_WRONG_METHOD_CHECK
5795 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5800 item->chunk_size += CMP_SIZE + BR_SIZE;
5801 imt_entries [item->check_target_idx]->compare_done = TRUE;
5803 size += item->chunk_size;
5805 /* the initial load of the vtable address */
5806 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5808 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5810 code = mono_domain_code_reserve (domain, size);
5815 * We need to save and restore r11 because it might be
5816 * used by the caller as the vtable register, so
5817 * clobbering it will trip up the magic trampoline.
5819 * FIXME: Get rid of this by making sure that r11 is
5820 * not used as the vtable register in interface calls.
5822 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5823 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5825 for (i = 0; i < count; ++i) {
5826 MonoIMTCheckItem *item = imt_entries [i];
5827 item->code_target = code;
5828 if (item->is_equals) {
5829 if (item->check_target_idx) {
5830 if (!item->compare_done) {
5831 ppc_load (code, ppc_r0, (gsize)item->key);
5832 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5834 item->jmp_code = code;
5835 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5836 if (item->has_target_code) {
5837 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5839 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5840 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5842 ppc_mtctr (code, ppc_r0);
5843 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5846 ppc_load (code, ppc_r0, (gulong)item->key);
5847 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5848 item->jmp_code = code;
5849 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5850 if (item->has_target_code) {
5851 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5854 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5855 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5857 ppc_mtctr (code, ppc_r0);
5858 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5859 ppc_patch (item->jmp_code, code);
5860 ppc_load_ptr (code, ppc_r0, fail_tramp);
5861 ppc_mtctr (code, ppc_r0);
5862 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5863 item->jmp_code = NULL;
5865 /* enable the commented code to assert on wrong method */
5866 #if ENABLE_WRONG_METHOD_CHECK
5867 ppc_load (code, ppc_r0, (guint32)item->key);
5868 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5869 item->jmp_code = code;
5870 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5872 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5873 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5874 ppc_mtctr (code, ppc_r0);
5875 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5876 #if ENABLE_WRONG_METHOD_CHECK
5877 ppc_patch (item->jmp_code, code);
5879 item->jmp_code = NULL;
5884 ppc_load (code, ppc_r0, (gulong)item->key);
5885 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5886 item->jmp_code = code;
5887 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5890 /* patch the branches to get to the target items */
5891 for (i = 0; i < count; ++i) {
5892 MonoIMTCheckItem *item = imt_entries [i];
5893 if (item->jmp_code) {
5894 if (item->check_target_idx) {
5895 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5901 mono_stats.imt_thunks_size += code - start;
5902 g_assert (code - start <= size);
5903 mono_arch_flush_icache (start, size);
5908 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5910 mgreg_t *r = (mgreg_t*)regs;
5912 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5917 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5919 mgreg_t *r = (mgreg_t*)regs;
5921 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5925 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5932 mono_arch_print_tree (MonoInst *tree, int arity)
5937 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5941 setup_tls_access ();
5942 if (monodomain_key == -1)
5945 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5946 ins->inst_offset = monodomain_key;
5951 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5954 return MONO_CONTEXT_GET_SP (ctx);
5956 g_assert (reg >= ppc_r13);
5958 return (gpointer)(gsize)ctx->regs [reg - ppc_r13];
5962 mono_arch_get_patch_offset (guint8 *code)
5968 * mono_aot_emit_load_got_addr:
5970 * Emit code to load the got address.
5971 * On PPC, the result is placed into r30.
5974 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5977 ppc_mflr (code, ppc_r30);
5979 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5981 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5982 /* arch_emit_got_address () patches this */
5983 #if defined(TARGET_POWERPC64)
5989 ppc_load32 (code, ppc_r0, 0);
5990 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5997 * mono_ppc_emit_load_aotconst:
5999 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6000 * TARGET from the mscorlib GOT in full-aot code.
6001 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
6005 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6007 /* Load the mscorlib got address */
6008 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
6009 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6010 /* arch_emit_got_access () patches this */
6011 ppc_load32 (code, ppc_r0, 0);
6012 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
6017 /* Soft Debug support */
6018 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6025 * mono_arch_set_breakpoint:
6027 * See mini-amd64.c for docs.
6030 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6033 guint8 *orig_code = code;
6035 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
6036 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
6038 g_assert (code - orig_code == BREAKPOINT_SIZE);
6040 mono_arch_flush_icache (orig_code, code - orig_code);
6044 * mono_arch_clear_breakpoint:
6046 * See mini-amd64.c for docs.
6049 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6054 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6057 mono_arch_flush_icache (ip, code - ip);
6061 * mono_arch_is_breakpoint_event:
6063 * See mini-amd64.c for docs.
6066 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6068 siginfo_t* sinfo = (siginfo_t*) info;
6069 /* Sometimes the address is off by 4 */
6070 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6077 * mono_arch_get_ip_for_breakpoint:
6079 * See mini-amd64.c for docs.
6082 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
6084 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6086 /* ip points at the ldptr instruction */
6087 ip -= PPC_LOAD_SEQUENCE_LENGTH;
6093 * mono_arch_skip_breakpoint:
6095 * See mini-amd64.c for docs.
6098 mono_arch_skip_breakpoint (MonoContext *ctx)
6100 /* skip the ldptr */
6101 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6109 * mono_arch_start_single_stepping:
6111 * See mini-amd64.c for docs.
6114 mono_arch_start_single_stepping (void)
6116 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6120 * mono_arch_stop_single_stepping:
6122 * See mini-amd64.c for docs.
6125 mono_arch_stop_single_stepping (void)
6127 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6131 * mono_arch_is_single_step_event:
6133 * See mini-amd64.c for docs.
6136 mono_arch_is_single_step_event (void *info, void *sigctx)
6138 siginfo_t* sinfo = (siginfo_t*) info;
6139 /* Sometimes the address is off by 4 */
6140 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6147 * mono_arch_get_ip_for_single_step:
6149 * See mini-amd64.c for docs.
6152 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
6154 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
6156 /* ip points after the ldptr instruction */
6161 * mono_arch_skip_single_step:
6163 * See mini-amd64.c for docs.
6166 mono_arch_skip_single_step (MonoContext *ctx)
6168 /* skip the ldptr */
6169 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6173 * mono_arch_create_seq_point_info:
6175 * See mini-amd64.c for docs.
6178 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)