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>
19 #include <mono/utils/mono-hwcap-ppc.h>
22 #ifdef TARGET_POWERPC64
23 #include "cpu-ppc64.h"
30 #include <sys/sysctl.h>
36 #define FORCE_INDIR_CALL 1
47 /* cpu_hw_caps contains the flags defined below */
48 static int cpu_hw_caps = 0;
49 static int cachelinesize = 0;
50 static int cachelineinc = 0;
52 PPC_ICACHE_SNOOP = 1 << 0,
53 PPC_MULTIPLE_LS_UNITS = 1 << 1,
54 PPC_SMP_CAPABLE = 1 << 2,
57 PPC_MOVE_FPR_GPR = 1 << 5,
61 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
63 /* This mutex protects architecture specific caches */
64 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
65 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
66 static CRITICAL_SECTION mini_arch_mutex;
68 int mono_exc_esp_offset = 0;
69 static int tls_mode = TLS_MODE_DETECT;
70 static int lmf_pthread_key = -1;
71 static int monodomain_key = -1;
74 * The code generated for sequence points reads from this location, which is
75 * made read-only when single stepping is enabled.
77 static gpointer ss_trigger_page;
79 /* Enabled breakpoints read from this trigger page */
80 static gpointer bp_trigger_page;
83 offsets_from_pthread_key (guint32 key, int *offset2)
87 *offset2 = idx2 * sizeof (gpointer);
88 return 284 + idx1 * sizeof (gpointer);
91 #define emit_linuxthreads_tls(code,dreg,key) do {\
93 off1 = offsets_from_pthread_key ((key), &off2); \
94 ppc_ldptr ((code), (dreg), off1, ppc_r2); \
95 ppc_ldptr ((code), (dreg), off2, (dreg)); \
98 #define emit_darwing5_tls(code,dreg,key) do {\
99 int off1 = 0x48 + key * sizeof (gpointer); \
100 ppc_mfspr ((code), (dreg), 104); \
101 ppc_ldptr ((code), (dreg), off1, (dreg)); \
104 /* FIXME: ensure the sc call preserves all but r3 */
105 #define emit_darwing4_tls(code,dreg,key) do {\
106 int off1 = 0x48 + key * sizeof (gpointer); \
107 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
108 ppc_li ((code), ppc_r0, 0x7FF2); \
110 ppc_lwz ((code), (dreg), off1, ppc_r3); \
111 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
114 #ifdef PPC_THREAD_PTR_REG
115 #define emit_nptl_tls(code,dreg,key) do { \
117 int off2 = key >> 15; \
118 if ((off2 == 0) || (off2 == -1)) { \
119 ppc_ldptr ((code), (dreg), off1, PPC_THREAD_PTR_REG); \
121 int off3 = (off2 + 1) > 1; \
122 ppc_addis ((code), ppc_r11, PPC_THREAD_PTR_REG, off3); \
123 ppc_ldptr ((code), (dreg), off1, ppc_r11); \
127 #define emit_nptl_tls(code,dreg,key) do { \
128 g_assert_not_reached (); \
132 #define emit_tls_access(code,dreg,key) do { \
133 switch (tls_mode) { \
134 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
135 case TLS_MODE_NPTL: emit_nptl_tls(code,dreg,key); break; \
136 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break; \
137 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break; \
138 default: g_assert_not_reached (); \
142 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
144 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
145 inst->type = STACK_R8; \
147 inst->inst_p0 = (void*)(addr); \
148 mono_bblock_add_inst (cfg->cbb, inst); \
152 mono_arch_regname (int reg) {
153 static const char rnames[][4] = {
154 "r0", "sp", "r2", "r3", "r4",
155 "r5", "r6", "r7", "r8", "r9",
156 "r10", "r11", "r12", "r13", "r14",
157 "r15", "r16", "r17", "r18", "r19",
158 "r20", "r21", "r22", "r23", "r24",
159 "r25", "r26", "r27", "r28", "r29",
162 if (reg >= 0 && reg < 32)
168 mono_arch_fregname (int reg) {
169 static const char rnames[][4] = {
170 "f0", "f1", "f2", "f3", "f4",
171 "f5", "f6", "f7", "f8", "f9",
172 "f10", "f11", "f12", "f13", "f14",
173 "f15", "f16", "f17", "f18", "f19",
174 "f20", "f21", "f22", "f23", "f24",
175 "f25", "f26", "f27", "f28", "f29",
178 if (reg >= 0 && reg < 32)
183 /* this function overwrites r0, r11, r12 */
185 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
187 /* unrolled, use the counter in big */
188 if (size > sizeof (gpointer) * 5) {
189 long shifted = size / SIZEOF_VOID_P;
190 guint8 *copy_loop_start, *copy_loop_jump;
192 ppc_load (code, ppc_r0, shifted);
193 ppc_mtctr (code, ppc_r0);
194 //g_assert (sreg == ppc_r11);
195 ppc_addi (code, ppc_r12, dreg, (doffset - sizeof (gpointer)));
196 ppc_addi (code, ppc_r11, sreg, (soffset - sizeof (gpointer)));
197 copy_loop_start = code;
198 ppc_ldptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
199 ppc_stptr_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r12);
200 copy_loop_jump = code;
201 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
202 ppc_patch (copy_loop_jump, copy_loop_start);
203 size -= shifted * sizeof (gpointer);
204 doffset = soffset = 0;
207 #ifdef __mono_ppc64__
208 /* the hardware has multiple load/store units and the move is long
209 enough to use more then one regiester, then use load/load/store/store
210 to execute 2 instructions per cycle. */
211 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
213 ppc_ldptr (code, ppc_r0, soffset, sreg);
214 ppc_ldptr (code, ppc_r12, soffset+8, sreg);
215 ppc_stptr (code, ppc_r0, doffset, dreg);
216 ppc_stptr (code, ppc_r12, doffset+8, dreg);
223 ppc_ldr (code, ppc_r0, soffset, sreg);
224 ppc_str (code, ppc_r0, doffset, dreg);
230 if ((cpu_hw_caps & PPC_MULTIPLE_LS_UNITS) && (dreg != ppc_r12) && (sreg != ppc_r12)) {
232 ppc_lwz (code, ppc_r0, soffset, sreg);
233 ppc_lwz (code, ppc_r12, soffset+4, sreg);
234 ppc_stw (code, ppc_r0, doffset, dreg);
235 ppc_stw (code, ppc_r12, doffset+4, dreg);
243 ppc_lwz (code, ppc_r0, soffset, sreg);
244 ppc_stw (code, ppc_r0, doffset, dreg);
250 ppc_lhz (code, ppc_r0, soffset, sreg);
251 ppc_sth (code, ppc_r0, doffset, dreg);
257 ppc_lbz (code, ppc_r0, soffset, sreg);
258 ppc_stb (code, ppc_r0, doffset, dreg);
267 * mono_arch_get_argument_info:
268 * @csig: a method signature
269 * @param_count: the number of parameters to consider
270 * @arg_info: an array to store the result infos
272 * Gathers information on parameters such as size, alignment and
273 * padding. arg_info should be large enought to hold param_count + 1 entries.
275 * Returns the size of the activation frame.
278 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
280 #ifdef __mono_ppc64__
284 int k, frame_size = 0;
285 int size, align, pad;
288 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
289 frame_size += sizeof (gpointer);
293 arg_info [0].offset = offset;
296 frame_size += sizeof (gpointer);
300 arg_info [0].size = frame_size;
302 for (k = 0; k < param_count; k++) {
305 size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
307 size = mini_type_stack_size (NULL, csig->params [k], &align);
309 /* ignore alignment for now */
312 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
313 arg_info [k].pad = pad;
315 arg_info [k + 1].pad = 0;
316 arg_info [k + 1].size = size;
318 arg_info [k + 1].offset = offset;
322 align = MONO_ARCH_FRAME_ALIGNMENT;
323 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
324 arg_info [k].pad = pad;
330 #ifdef __mono_ppc64__
332 is_load_sequence (guint32 *seq)
334 return ppc_opcode (seq [0]) == 15 && /* lis */
335 ppc_opcode (seq [1]) == 24 && /* ori */
336 ppc_opcode (seq [2]) == 30 && /* sldi */
337 ppc_opcode (seq [3]) == 25 && /* oris */
338 ppc_opcode (seq [4]) == 24; /* ori */
341 #define ppc_load_get_dest(l) (((l)>>21) & 0x1f)
342 #define ppc_load_get_off(l) ((gint16)((l) & 0xffff))
346 #define ppc_is_load_op(opcode) (ppc_opcode ((opcode)) == 58 || ppc_opcode ((opcode)) == 32)
348 /* code must point to the blrl */
350 mono_ppc_is_direct_call_sequence (guint32 *code)
352 #ifdef __mono_ppc64__
353 g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420);
355 /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */
356 if (ppc_opcode (code [-1]) == 31) { /* mtlr */
357 if (ppc_is_load_op (code [-2]) && ppc_is_load_op (code [-3])) { /* ld/ld */
358 if (!is_load_sequence (&code [-8]))
360 /* one of the loads must be "ld r2,8(rX)" or "ld r2,4(rX) for ilp32 */
361 return (ppc_load_get_dest (code [-2]) == ppc_r2 && ppc_load_get_off (code [-2]) == sizeof (gpointer)) ||
362 (ppc_load_get_dest (code [-3]) == ppc_r2 && ppc_load_get_off (code [-3]) == sizeof (gpointer));
364 if (ppc_opcode (code [-2]) == 24 && ppc_opcode (code [-3]) == 31) /* mr/nop */
365 return is_load_sequence (&code [-8]);
367 return is_load_sequence (&code [-6]);
371 g_assert(*code == 0x4e800021);
373 /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
374 return ppc_opcode (code [-1]) == 31 &&
375 ppc_opcode (code [-2]) == 24 &&
376 ppc_opcode (code [-3]) == 15;
380 #define MAX_ARCH_DELEGATE_PARAMS 7
383 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len, gboolean aot)
385 guint8 *code, *start;
388 int size = MONO_PPC_32_64_CASE (32, 32) + PPC_FTNPTR_SIZE;
390 start = code = mono_global_codeman_reserve (size);
392 code = mono_ppc_create_pre_code_ftnptr (code);
394 /* Replace the this argument with the target */
395 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
396 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
397 /* it's a function descriptor */
398 /* Can't use ldptr as it doesn't work with r0 */
399 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
401 ppc_mtctr (code, ppc_r0);
402 ppc_ldptr (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
403 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
405 g_assert ((code - start) <= size);
407 mono_arch_flush_icache (start, size);
411 size = MONO_PPC_32_64_CASE (32, 32) + param_count * 4 + PPC_FTNPTR_SIZE;
412 start = code = mono_global_codeman_reserve (size);
414 code = mono_ppc_create_pre_code_ftnptr (code);
416 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
417 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
418 /* it's a function descriptor */
419 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
421 ppc_mtctr (code, ppc_r0);
422 /* slide down the arguments */
423 for (i = 0; i < param_count; ++i) {
424 ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
426 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
428 g_assert ((code - start) <= size);
430 mono_arch_flush_icache (start, size);
434 *code_len = code - start;
440 mono_arch_get_delegate_invoke_impls (void)
448 code = get_delegate_invoke_impl (TRUE, 0, &code_len, TRUE);
449 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
451 for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
452 code = get_delegate_invoke_impl (FALSE, i, &code_len, TRUE);
453 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
454 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
462 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
464 guint8 *code, *start;
466 /* FIXME: Support more cases */
467 if (MONO_TYPE_ISSTRUCT (sig->ret))
471 static guint8* cached = NULL;
477 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
479 start = get_delegate_invoke_impl (TRUE, 0, NULL, FALSE);
481 mono_memory_barrier ();
485 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
488 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
490 for (i = 0; i < sig->param_count; ++i)
491 if (!mono_is_regsize_var (sig->params [i]))
495 code = cache [sig->param_count];
500 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
501 start = mono_aot_get_trampoline (name);
504 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL, FALSE);
507 mono_memory_barrier ();
509 cache [sig->param_count] = start;
515 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
517 mgreg_t *r = (mgreg_t*)regs;
519 return (gpointer)(gsize)r [ppc_r3];
527 #define MAX_AUX_ENTRIES 128
529 * PPC_FEATURE_POWER4, PPC_FEATURE_POWER5, PPC_FEATURE_POWER5_PLUS, PPC_FEATURE_CELL,
530 * PPC_FEATURE_PA6T, PPC_FEATURE_ARCH_2_05 are considered supporting 2X ISA features
532 #define ISA_2X (0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 | 0x00000800 | 0x00001000)
534 /* define PPC_FEATURE_64 HWCAP for 64-bit category. */
535 #define ISA_64 0x40000000
537 /* define PPC_FEATURE_POWER6_EXT HWCAP for power6x mffgpr/mftgpr instructions. */
538 #define ISA_MOVE_FPR_GPR 0x00000200
540 * Initialize the cpu to execute managed code.
543 mono_arch_cpu_init (void)
548 * Initialize architecture specific code.
551 mono_arch_init (void)
553 #if defined(MONO_CROSS_COMPILE)
554 #elif defined(__APPLE__)
556 size_t len = sizeof (cachelinesize);
559 mib [1] = HW_CACHELINE;
561 if (sysctl (mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
565 cachelineinc = cachelinesize;
567 #elif defined(__linux__)
568 AuxVec vec [MAX_AUX_ENTRIES];
569 int i, vec_entries = 0;
570 /* sadly this will work only with 2.6 kernels... */
571 FILE* f = fopen ("/proc/self/auxv", "rb");
574 vec_entries = fread (&vec, sizeof (AuxVec), MAX_AUX_ENTRIES, f);
578 for (i = 0; i < vec_entries; i++) {
579 int type = vec [i].type;
581 if (type == 19) { /* AT_DCACHEBSIZE */
582 cachelinesize = vec [i].value;
586 #elif defined(G_COMPILER_CODEWARRIOR)
590 //#error Need a way to get cache line size
593 if (mono_hwcap_ppc_has_icache_snoop)
594 cpu_hw_caps |= PPC_ICACHE_SNOOP;
596 if (mono_hwcap_ppc_is_isa_2x)
597 cpu_hw_caps |= PPC_ISA_2X;
599 if (mono_hwcap_ppc_is_isa_64)
600 cpu_hw_caps |= PPC_ISA_64;
602 if (mono_hwcap_ppc_has_move_fpr_gpr)
603 cpu_hw_caps |= PPC_MOVE_FPR_GPR;
605 if (mono_hwcap_ppc_has_multiple_ls_units)
606 cpu_hw_caps |= PPC_MULTIPLE_LS_UNITS;
612 cachelineinc = cachelinesize;
614 if (mono_cpu_count () > 1)
615 cpu_hw_caps |= PPC_SMP_CAPABLE;
617 InitializeCriticalSection (&mini_arch_mutex);
619 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
620 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
621 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
623 mono_aot_register_jit_icall ("mono_ppc_throw_exception", mono_ppc_throw_exception);
627 * Cleanup architecture specific code.
630 mono_arch_cleanup (void)
632 DeleteCriticalSection (&mini_arch_mutex);
636 * This function returns the optimizations supported on this cpu.
639 mono_arch_cpu_optimizations (guint32 *exclude_mask)
643 /* no ppc-specific optimizations yet */
649 * This function test for all SIMD functions supported.
651 * Returns a bitmask corresponding to all supported versions.
655 mono_arch_cpu_enumerate_simd_versions (void)
657 /* SIMD is currently unimplemented */
661 #ifdef __mono_ppc64__
662 #define CASE_PPC32(c)
663 #define CASE_PPC64(c) case c:
665 #define CASE_PPC32(c) case c:
666 #define CASE_PPC64(c)
670 is_regsize_var (MonoType *t) {
673 t = mini_type_get_underlying_type (NULL, t);
677 CASE_PPC64 (MONO_TYPE_I8)
678 CASE_PPC64 (MONO_TYPE_U8)
682 case MONO_TYPE_FNPTR:
684 case MONO_TYPE_OBJECT:
685 case MONO_TYPE_STRING:
686 case MONO_TYPE_CLASS:
687 case MONO_TYPE_SZARRAY:
688 case MONO_TYPE_ARRAY:
690 case MONO_TYPE_GENERICINST:
691 if (!mono_type_generic_inst_is_valuetype (t))
694 case MONO_TYPE_VALUETYPE:
702 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
707 for (i = 0; i < cfg->num_varinfo; i++) {
708 MonoInst *ins = cfg->varinfo [i];
709 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
712 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
715 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
718 /* we can only allocate 32 bit values */
719 if (is_regsize_var (ins->inst_vtype)) {
720 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
721 g_assert (i == vmv->idx);
722 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
728 #endif /* ifndef DISABLE_JIT */
731 mono_arch_get_global_int_regs (MonoCompile *cfg)
735 if (cfg->frame_reg != ppc_sp)
737 /* ppc_r13 is used by the system on PPC EABI */
738 for (i = 14; i < top; ++i) {
740 * Reserve r29 for holding the vtable address for virtual calls in AOT mode,
741 * since the trampolines can clobber r11.
743 if (!(cfg->compile_aot && i == 29))
744 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
751 * mono_arch_regalloc_cost:
753 * Return the cost, in number of memory references, of the action of
754 * allocating the variable VMV into a register during global register
758 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
765 mono_arch_flush_icache (guint8 *code, gint size)
767 #ifdef MONO_CROSS_COMPILE
770 guint8 *endp, *start;
774 start = (guint8*)((gsize)start & ~(cachelinesize - 1));
775 /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
776 #if defined(G_COMPILER_CODEWARRIOR)
777 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
778 for (p = start; p < endp; p += cachelineinc) {
782 for (p = start; p < endp; p += cachelineinc) {
788 for (p = start; p < endp; p += cachelineinc) {
799 /* For POWER5/6 with ICACHE_SNOOPing only one icbi in the range is required.
800 * The sync is required to insure that the store queue is completely empty.
801 * While the icbi performs no cache operations, icbi/isync is required to
802 * kill local prefetch.
804 if (cpu_hw_caps & PPC_ICACHE_SNOOP) {
806 asm ("icbi 0,%0;" : : "r"(code) : "memory");
810 /* use dcbf for smp support, see pem._64bit.d20030611.pdf page 211 */
811 if (cpu_hw_caps & PPC_SMP_CAPABLE) {
812 for (p = start; p < endp; p += cachelineinc) {
813 asm ("dcbf 0,%0;" : : "r"(p) : "memory");
816 for (p = start; p < endp; p += cachelineinc) {
817 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
822 for (p = start; p < endp; p += cachelineinc) {
823 /* for ISA2.0+ implementations we should not need any extra sync between the
824 * icbi instructions. Both the 2.0 PEM and the PowerISA-2.05 say this.
825 * So I am not sure which chip had this problem but its not an issue on
826 * of the ISA V2 chips.
828 if (cpu_hw_caps & PPC_ISA_2X)
829 asm ("icbi 0,%0;" : : "r"(p) : "memory");
831 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
833 if (!(cpu_hw_caps & PPC_ISA_2X))
841 mono_arch_flush_register_windows (void)
846 #define ALWAYS_ON_STACK(s) s
847 #define FP_ALSO_IN_REG(s) s
849 #ifdef __mono_ppc64__
850 #define ALWAYS_ON_STACK(s) s
851 #define FP_ALSO_IN_REG(s) s
853 #define ALWAYS_ON_STACK(s)
854 #define FP_ALSO_IN_REG(s)
856 #define ALIGN_DOUBLES
869 guint32 vtsize; /* in param area */
871 guint8 vtregs; /* number of registers used to pass a RegTypeStructByVal */
872 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
873 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
874 guint8 bytes : 4; /* size in bytes - only valid for
875 RegTypeStructByVal if the struct fits
876 in one word, otherwise it's 0*/
885 gboolean vtype_retaddr;
893 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
895 #ifdef __mono_ppc64__
900 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
901 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
902 ainfo->reg = ppc_sp; /* in the caller */
903 ainfo->regtype = RegTypeBase;
904 *stack_size += sizeof (gpointer);
906 ALWAYS_ON_STACK (*stack_size += sizeof (gpointer));
910 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
912 //*stack_size += (*stack_size % 8);
914 ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
915 ainfo->reg = ppc_sp; /* in the caller */
916 ainfo->regtype = RegTypeBase;
923 ALWAYS_ON_STACK (*stack_size += 8);
931 #if defined(__APPLE__) || defined(__mono_ppc64__)
933 has_only_a_r48_field (MonoClass *klass)
937 gboolean have_field = FALSE;
939 while ((f = mono_class_get_fields (klass, &iter))) {
940 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
943 if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
954 get_call_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
956 guint i, fr, gr, pstart;
957 int n = sig->hasthis + sig->param_count;
958 MonoType *simpletype;
959 guint32 stack_size = 0;
960 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
961 gboolean is_pinvoke = sig->pinvoke;
963 fr = PPC_FIRST_FPARG_REG;
964 gr = PPC_FIRST_ARG_REG;
966 /* FIXME: handle returning a struct */
967 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
968 cinfo->vtype_retaddr = TRUE;
974 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
975 * the first argument, allowing 'this' to be always passed in the first arg reg.
976 * Also do this if the first argument is a reference type, since virtual calls
977 * are sometimes made using calli without sig->hasthis set, like in the delegate
980 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
982 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
985 add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
989 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
990 cinfo->struct_ret = cinfo->ret.reg;
991 cinfo->vret_arg_index = 1;
995 add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
999 if (cinfo->vtype_retaddr) {
1000 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
1001 cinfo->struct_ret = cinfo->ret.reg;
1005 DEBUG(printf("params: %d\n", sig->param_count));
1006 for (i = pstart; i < sig->param_count; ++i) {
1007 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1008 /* Prevent implicit arguments and sig_cookie from
1009 being passed in registers */
1010 gr = PPC_LAST_ARG_REG + 1;
1011 /* FIXME: don't we have to set fr, too? */
1012 /* Emit the signature cookie just before the implicit arguments */
1013 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1015 DEBUG(printf("param %d: ", i));
1016 if (sig->params [i]->byref) {
1017 DEBUG(printf("byref\n"));
1018 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1022 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
1023 switch (simpletype->type) {
1024 case MONO_TYPE_BOOLEAN:
1027 cinfo->args [n].size = 1;
1028 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1031 case MONO_TYPE_CHAR:
1034 cinfo->args [n].size = 2;
1035 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1040 cinfo->args [n].size = 4;
1041 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1047 case MONO_TYPE_FNPTR:
1048 case MONO_TYPE_CLASS:
1049 case MONO_TYPE_OBJECT:
1050 case MONO_TYPE_STRING:
1051 case MONO_TYPE_SZARRAY:
1052 case MONO_TYPE_ARRAY:
1053 cinfo->args [n].size = sizeof (gpointer);
1054 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1057 case MONO_TYPE_GENERICINST:
1058 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1059 cinfo->args [n].size = sizeof (gpointer);
1060 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1065 case MONO_TYPE_VALUETYPE:
1066 case MONO_TYPE_TYPEDBYREF: {
1070 klass = mono_class_from_mono_type (sig->params [i]);
1071 if (simpletype->type == MONO_TYPE_TYPEDBYREF)
1072 size = sizeof (MonoTypedRef);
1073 else if (is_pinvoke)
1074 size = mono_class_native_size (klass, NULL);
1076 size = mono_class_value_size (klass, NULL);
1078 #if defined(__APPLE__) || defined(__mono_ppc64__)
1079 if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
1080 cinfo->args [n].size = size;
1082 /* It was 7, now it is 8 in LinuxPPC */
1083 if (fr <= PPC_LAST_FPARG_REG) {
1084 cinfo->args [n].regtype = RegTypeFP;
1085 cinfo->args [n].reg = fr;
1087 FP_ALSO_IN_REG (gr ++);
1089 FP_ALSO_IN_REG (gr ++);
1090 ALWAYS_ON_STACK (stack_size += size);
1092 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1093 cinfo->args [n].regtype = RegTypeBase;
1094 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1101 DEBUG(printf ("load %d bytes struct\n",
1102 mono_class_native_size (sig->params [i]->data.klass, NULL)));
1104 #if PPC_PASS_STRUCTS_BY_VALUE
1106 int align_size = size;
1108 int rest = PPC_LAST_ARG_REG - gr + 1;
1111 align_size += (sizeof (gpointer) - 1);
1112 align_size &= ~(sizeof (gpointer) - 1);
1113 nregs = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1114 n_in_regs = MIN (rest, nregs);
1118 /* FIXME: check this */
1119 if (size >= 3 && size % 4 != 0)
1122 cinfo->args [n].regtype = RegTypeStructByVal;
1123 cinfo->args [n].vtregs = n_in_regs;
1124 cinfo->args [n].size = n_in_regs;
1125 cinfo->args [n].vtsize = nregs - n_in_regs;
1126 cinfo->args [n].reg = gr;
1128 #ifdef __mono_ppc64__
1129 if (nregs == 1 && is_pinvoke)
1130 cinfo->args [n].bytes = size;
1133 cinfo->args [n].bytes = 0;
1135 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1136 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
1137 stack_size += nregs * sizeof (gpointer);
1140 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
1141 cinfo->args [n].regtype = RegTypeStructByAddr;
1142 cinfo->args [n].vtsize = size;
1149 cinfo->args [n].size = 8;
1150 add_general (&gr, &stack_size, cinfo->args + n, SIZEOF_REGISTER == 8);
1154 cinfo->args [n].size = 4;
1156 /* It was 7, now it is 8 in LinuxPPC */
1157 if (fr <= PPC_LAST_FPARG_REG) {
1158 cinfo->args [n].regtype = RegTypeFP;
1159 cinfo->args [n].reg = fr;
1161 FP_ALSO_IN_REG (gr ++);
1162 ALWAYS_ON_STACK (stack_size += SIZEOF_REGISTER);
1164 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size + MONO_PPC_32_64_CASE (0, 4);
1165 cinfo->args [n].regtype = RegTypeBase;
1166 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1167 stack_size += SIZEOF_REGISTER;
1172 cinfo->args [n].size = 8;
1173 /* It was 7, now it is 8 in LinuxPPC */
1174 if (fr <= PPC_LAST_FPARG_REG) {
1175 cinfo->args [n].regtype = RegTypeFP;
1176 cinfo->args [n].reg = fr;
1178 FP_ALSO_IN_REG (gr += sizeof (double) / SIZEOF_REGISTER);
1179 ALWAYS_ON_STACK (stack_size += 8);
1181 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
1182 cinfo->args [n].regtype = RegTypeBase;
1183 cinfo->args [n].reg = ppc_sp; /* in the caller*/
1189 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1194 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1195 /* Prevent implicit arguments and sig_cookie from
1196 being passed in registers */
1197 gr = PPC_LAST_ARG_REG + 1;
1198 /* Emit the signature cookie just before the implicit arguments */
1199 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1203 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
1204 switch (simpletype->type) {
1205 case MONO_TYPE_BOOLEAN:
1210 case MONO_TYPE_CHAR:
1216 case MONO_TYPE_FNPTR:
1217 case MONO_TYPE_CLASS:
1218 case MONO_TYPE_OBJECT:
1219 case MONO_TYPE_SZARRAY:
1220 case MONO_TYPE_ARRAY:
1221 case MONO_TYPE_STRING:
1222 cinfo->ret.reg = ppc_r3;
1226 cinfo->ret.reg = ppc_r3;
1230 cinfo->ret.reg = ppc_f1;
1231 cinfo->ret.regtype = RegTypeFP;
1233 case MONO_TYPE_GENERICINST:
1234 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1235 cinfo->ret.reg = ppc_r3;
1239 case MONO_TYPE_VALUETYPE:
1241 case MONO_TYPE_TYPEDBYREF:
1242 case MONO_TYPE_VOID:
1245 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1249 /* align stack size to 16 */
1250 DEBUG (printf (" stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1251 stack_size = (stack_size + 15) & ~15;
1253 cinfo->stack_usage = stack_size;
1258 mono_ppc_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1264 c1 = get_call_info (NULL, caller_sig);
1265 c2 = get_call_info (NULL, callee_sig);
1266 res = c1->stack_usage >= c2->stack_usage;
1267 if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret))
1268 /* An address on the callee's stack is passed as the first argument */
1270 for (i = 0; i < c2->nargs; ++i) {
1271 if (c2->args [i].regtype == RegTypeStructByAddr)
1272 /* An address on the callee's stack is passed as the argument */
1277 if (!mono_debug_count ())
1288 * Set var information according to the calling convention. ppc version.
1289 * The locals var stuff should most likely be split in another method.
1292 mono_arch_allocate_vars (MonoCompile *m)
1294 MonoMethodSignature *sig;
1295 MonoMethodHeader *header;
1297 int i, offset, size, align, curinst;
1298 int frame_reg = ppc_sp;
1300 guint32 locals_stack_size, locals_stack_align;
1302 m->flags |= MONO_CFG_HAS_SPILLUP;
1304 /* allow room for the vararg method args: void* and long/double */
1305 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1306 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1307 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1308 * call convs needs to be handled this way.
1310 if (m->flags & MONO_CFG_HAS_VARARGS)
1311 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1312 /* gtk-sharp and other broken code will dllimport vararg functions even with
1313 * non-varargs signatures. Since there is little hope people will get this right
1314 * we assume they won't.
1316 if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1317 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1322 * We use the frame register also for any method that has
1323 * exception clauses. This way, when the handlers are called,
1324 * the code will reference local variables using the frame reg instead of
1325 * the stack pointer: if we had to restore the stack pointer, we'd
1326 * corrupt the method frames that are already on the stack (since
1327 * filters get called before stack unwinding happens) when the filter
1328 * code would call any method (this also applies to finally etc.).
1330 if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1331 frame_reg = ppc_r31;
1332 m->frame_reg = frame_reg;
1333 if (frame_reg != ppc_sp) {
1334 m->used_int_regs |= 1 << frame_reg;
1337 sig = mono_method_signature (m->method);
1341 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1342 m->ret->opcode = OP_REGVAR;
1343 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1345 /* FIXME: handle long values? */
1346 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1347 case MONO_TYPE_VOID:
1351 m->ret->opcode = OP_REGVAR;
1352 m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1355 m->ret->opcode = OP_REGVAR;
1356 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1360 /* local vars are at a positive offset from the stack pointer */
1362 * also note that if the function uses alloca, we use ppc_r31
1363 * to point at the local variables.
1365 offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1366 /* align the offset to 16 bytes: not sure this is needed here */
1368 //offset &= ~(16 - 1);
1370 /* add parameter area size for called functions */
1371 offset += m->param_area;
1373 offset &= ~(16 - 1);
1375 /* allow room to save the return value */
1376 if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1379 /* the MonoLMF structure is stored just below the stack pointer */
1382 /* this stuff should not be needed on ppc and the new jit,
1383 * because a call on ppc to the handlers doesn't change the
1384 * stack pointer and the jist doesn't manipulate the stack pointer
1385 * for operations involving valuetypes.
1387 /* reserve space to store the esp */
1388 offset += sizeof (gpointer);
1390 /* this is a global constant */
1391 mono_exc_esp_offset = offset;
1394 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1395 offset += sizeof(gpointer) - 1;
1396 offset &= ~(sizeof(gpointer) - 1);
1398 m->vret_addr->opcode = OP_REGOFFSET;
1399 m->vret_addr->inst_basereg = frame_reg;
1400 m->vret_addr->inst_offset = offset;
1402 if (G_UNLIKELY (m->verbose_level > 1)) {
1403 printf ("vret_addr =");
1404 mono_print_ins (m->vret_addr);
1407 offset += sizeof(gpointer);
1410 offsets = mono_allocate_stack_slots (m, FALSE, &locals_stack_size, &locals_stack_align);
1411 if (locals_stack_align) {
1412 offset += (locals_stack_align - 1);
1413 offset &= ~(locals_stack_align - 1);
1415 for (i = m->locals_start; i < m->num_varinfo; i++) {
1416 if (offsets [i] != -1) {
1417 MonoInst *inst = m->varinfo [i];
1418 inst->opcode = OP_REGOFFSET;
1419 inst->inst_basereg = frame_reg;
1420 inst->inst_offset = offset + offsets [i];
1422 g_print ("allocating local %d (%s) to %d\n",
1423 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1427 offset += locals_stack_size;
1431 inst = m->args [curinst];
1432 if (inst->opcode != OP_REGVAR) {
1433 inst->opcode = OP_REGOFFSET;
1434 inst->inst_basereg = frame_reg;
1435 offset += sizeof (gpointer) - 1;
1436 offset &= ~(sizeof (gpointer) - 1);
1437 inst->inst_offset = offset;
1438 offset += sizeof (gpointer);
1443 for (i = 0; i < sig->param_count; ++i) {
1444 inst = m->args [curinst];
1445 if (inst->opcode != OP_REGVAR) {
1446 inst->opcode = OP_REGOFFSET;
1447 inst->inst_basereg = frame_reg;
1449 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1450 inst->backend.is_pinvoke = 1;
1452 size = mono_type_size (sig->params [i], &align);
1454 if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
1455 size = align = sizeof (gpointer);
1457 * Use at least 4/8 byte alignment, since these might be passed in registers, and
1458 * they are saved using std in the prolog.
1460 align = sizeof (gpointer);
1461 offset += align - 1;
1462 offset &= ~(align - 1);
1463 inst->inst_offset = offset;
1469 /* some storage for fp conversions */
1472 m->arch.fp_conv_var_offset = offset;
1475 /* align the offset to 16 bytes */
1477 offset &= ~(16 - 1);
1480 m->stack_offset = offset;
1482 if (sig->call_convention == MONO_CALL_VARARG) {
1483 CallInfo *cinfo = get_call_info (m->generic_sharing_context, m->method->signature);
1485 m->sig_cookie = cinfo->sig_cookie.offset;
1492 mono_arch_create_vars (MonoCompile *cfg)
1494 MonoMethodSignature *sig = mono_method_signature (cfg->method);
1496 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1497 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1501 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1502 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1506 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1508 int sig_reg = mono_alloc_ireg (cfg);
1510 /* FIXME: Add support for signature tokens to AOT */
1511 cfg->disable_aot = TRUE;
1513 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (gulong)call->signature);
1514 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1515 ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1519 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1522 MonoMethodSignature *sig;
1526 sig = call->signature;
1527 n = sig->param_count + sig->hasthis;
1529 cinfo = get_call_info (cfg->generic_sharing_context, sig);
1531 for (i = 0; i < n; ++i) {
1532 ArgInfo *ainfo = cinfo->args + i;
1535 if (i >= sig->hasthis)
1536 t = sig->params [i - sig->hasthis];
1538 t = &mono_defaults.int_class->byval_arg;
1539 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1541 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1542 emit_sig_cookie (cfg, call, cinfo);
1544 in = call->args [i];
1546 if (ainfo->regtype == RegTypeGeneral) {
1547 #ifndef __mono_ppc64__
1548 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1549 MONO_INST_NEW (cfg, ins, OP_MOVE);
1550 ins->dreg = mono_alloc_ireg (cfg);
1551 ins->sreg1 = in->dreg + 1;
1552 MONO_ADD_INS (cfg->cbb, ins);
1553 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1555 MONO_INST_NEW (cfg, ins, OP_MOVE);
1556 ins->dreg = mono_alloc_ireg (cfg);
1557 ins->sreg1 = in->dreg + 2;
1558 MONO_ADD_INS (cfg->cbb, ins);
1559 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1563 MONO_INST_NEW (cfg, ins, OP_MOVE);
1564 ins->dreg = mono_alloc_ireg (cfg);
1565 ins->sreg1 = in->dreg;
1566 MONO_ADD_INS (cfg->cbb, ins);
1568 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1570 } else if (ainfo->regtype == RegTypeStructByAddr) {
1571 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1572 ins->opcode = OP_OUTARG_VT;
1573 ins->sreg1 = in->dreg;
1574 ins->klass = in->klass;
1575 ins->inst_p0 = call;
1576 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1577 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1578 MONO_ADD_INS (cfg->cbb, ins);
1579 } else if (ainfo->regtype == RegTypeStructByVal) {
1580 /* this is further handled in mono_arch_emit_outarg_vt () */
1581 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1582 ins->opcode = OP_OUTARG_VT;
1583 ins->sreg1 = in->dreg;
1584 ins->klass = in->klass;
1585 ins->inst_p0 = call;
1586 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1587 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1588 MONO_ADD_INS (cfg->cbb, ins);
1589 } else if (ainfo->regtype == RegTypeBase) {
1590 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1591 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1592 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1593 if (t->type == MONO_TYPE_R8)
1594 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1596 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1598 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1600 } else if (ainfo->regtype == RegTypeFP) {
1601 if (t->type == MONO_TYPE_VALUETYPE) {
1602 /* this is further handled in mono_arch_emit_outarg_vt () */
1603 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1604 ins->opcode = OP_OUTARG_VT;
1605 ins->sreg1 = in->dreg;
1606 ins->klass = in->klass;
1607 ins->inst_p0 = call;
1608 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1609 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1610 MONO_ADD_INS (cfg->cbb, ins);
1612 cfg->flags |= MONO_CFG_HAS_FPOUT;
1614 int dreg = mono_alloc_freg (cfg);
1616 if (ainfo->size == 4) {
1617 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1619 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1621 ins->sreg1 = in->dreg;
1622 MONO_ADD_INS (cfg->cbb, ins);
1625 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1626 cfg->flags |= MONO_CFG_HAS_FPOUT;
1629 g_assert_not_reached ();
1633 /* Emit the signature cookie in the case that there is no
1634 additional argument */
1635 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1636 emit_sig_cookie (cfg, call, cinfo);
1638 if (cinfo->struct_ret) {
1641 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1642 vtarg->sreg1 = call->vret_var->dreg;
1643 vtarg->dreg = mono_alloc_preg (cfg);
1644 MONO_ADD_INS (cfg->cbb, vtarg);
1646 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1649 call->stack_usage = cinfo->stack_usage;
1650 cfg->param_area = MAX (PPC_MINIMAL_PARAM_AREA_SIZE, MAX (cfg->param_area, cinfo->stack_usage));
1651 cfg->flags |= MONO_CFG_HAS_CALLS;
1659 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1661 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1662 ArgInfo *ainfo = ins->inst_p1;
1663 int ovf_size = ainfo->vtsize;
1664 int doffset = ainfo->offset;
1665 int i, soffset, dreg;
1667 if (ainfo->regtype == RegTypeStructByVal) {
1674 * Darwin pinvokes needs some special handling for 1
1675 * and 2 byte arguments
1677 g_assert (ins->klass);
1678 if (call->signature->pinvoke)
1679 size = mono_class_native_size (ins->klass, NULL);
1680 if (size == 2 || size == 1) {
1681 int tmpr = mono_alloc_ireg (cfg);
1683 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1685 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1686 dreg = mono_alloc_ireg (cfg);
1687 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1688 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1691 for (i = 0; i < ainfo->vtregs; ++i) {
1692 int antipadding = 0;
1695 antipadding = sizeof (gpointer) - ainfo->bytes;
1697 dreg = mono_alloc_ireg (cfg);
1698 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1700 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, dreg, dreg, antipadding * 8);
1701 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1702 soffset += sizeof (gpointer);
1705 mini_emit_memcpy (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1706 } else if (ainfo->regtype == RegTypeFP) {
1707 int tmpr = mono_alloc_freg (cfg);
1708 if (ainfo->size == 4)
1709 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1711 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1712 dreg = mono_alloc_freg (cfg);
1713 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1714 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1716 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1720 /* FIXME: alignment? */
1721 if (call->signature->pinvoke) {
1722 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1723 vtcopy->backend.is_pinvoke = 1;
1725 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1728 g_assert (ovf_size > 0);
1730 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1731 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1734 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1736 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1741 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1743 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1744 mono_method_signature (method)->ret);
1747 #ifndef __mono_ppc64__
1748 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1751 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1752 ins->sreg1 = val->dreg + 1;
1753 ins->sreg2 = val->dreg + 2;
1754 MONO_ADD_INS (cfg->cbb, ins);
1758 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1759 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1763 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1766 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1768 mono_arch_is_inst_imm (gint64 imm)
1773 #endif /* DISABLE_JIT */
1776 * Allow tracing to work with this interface (with an optional argument)
1780 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1784 ppc_load_ptr (code, ppc_r3, cfg->method);
1785 ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1786 ppc_load_func (code, ppc_r0, func);
1787 ppc_mtlr (code, ppc_r0);
1801 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1804 int save_mode = SAVE_NONE;
1806 MonoMethod *method = cfg->method;
1807 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1808 mono_method_signature (method)->ret)->type;
1809 int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1813 offset = code - cfg->native_code;
1814 /* we need about 16 instructions */
1815 if (offset > (cfg->code_size - 16 * 4)) {
1816 cfg->code_size *= 2;
1817 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1818 code = cfg->native_code + offset;
1822 case MONO_TYPE_VOID:
1823 /* special case string .ctor icall */
1824 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1825 save_mode = SAVE_ONE;
1827 save_mode = SAVE_NONE;
1829 #ifndef __mono_ppc64__
1832 save_mode = SAVE_TWO;
1837 save_mode = SAVE_FP;
1839 case MONO_TYPE_VALUETYPE:
1840 save_mode = SAVE_STRUCT;
1843 save_mode = SAVE_ONE;
1847 switch (save_mode) {
1849 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1850 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1851 if (enable_arguments) {
1852 ppc_mr (code, ppc_r5, ppc_r4);
1853 ppc_mr (code, ppc_r4, ppc_r3);
1857 ppc_stptr (code, ppc_r3, save_offset, cfg->frame_reg);
1858 if (enable_arguments) {
1859 ppc_mr (code, ppc_r4, ppc_r3);
1863 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1864 if (enable_arguments) {
1865 /* FIXME: what reg? */
1866 ppc_fmr (code, ppc_f3, ppc_f1);
1867 /* FIXME: use 8 byte load on PPC64 */
1868 ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1869 ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1873 if (enable_arguments) {
1874 /* FIXME: get the actual address */
1875 ppc_mr (code, ppc_r4, ppc_r3);
1883 ppc_load_ptr (code, ppc_r3, cfg->method);
1884 ppc_load_func (code, ppc_r0, func);
1885 ppc_mtlr (code, ppc_r0);
1888 switch (save_mode) {
1890 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1891 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1894 ppc_ldptr (code, ppc_r3, save_offset, cfg->frame_reg);
1897 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1907 * Conditional branches have a small offset, so if it is likely overflowed,
1908 * we do a branch to the end of the method (uncond branches have much larger
1909 * offsets) where we perform the conditional and jump back unconditionally.
1910 * It's slightly slower, since we add two uncond branches, but it's very simple
1911 * with the current patch implementation and such large methods are likely not
1912 * going to be perf critical anyway.
1917 const char *exception;
1924 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1925 if (0 && ins->inst_true_bb->native_offset) { \
1926 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1928 int br_disp = ins->inst_true_bb->max_offset - offset; \
1929 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1930 MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump)); \
1931 ovfj->data.bb = ins->inst_true_bb; \
1932 ovfj->ip_offset = 0; \
1933 ovfj->b0_cond = (b0); \
1934 ovfj->b1_cond = (b1); \
1935 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1938 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1939 ppc_bc (code, (b0), (b1), 0); \
1943 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1945 /* emit an exception if condition is fail
1947 * We assign the extra code used to throw the implicit exceptions
1948 * to cfg->bb_exit as far as the big branch handling is concerned
1950 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name) \
1952 int br_disp = cfg->bb_exit->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.exception = (exc_name); \
1956 ovfj->ip_offset = code - cfg->native_code; \
1957 ovfj->b0_cond = (b0); \
1958 ovfj->b1_cond = (b1); \
1959 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1961 cfg->bb_exit->max_offset += 24; \
1963 mono_add_patch_info (cfg, code - cfg->native_code, \
1964 MONO_PATCH_INFO_EXC, exc_name); \
1965 ppc_bcl (code, (b0), (b1), 0); \
1969 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1972 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1977 normalize_opcode (int opcode)
1980 #ifndef __mono_ilp32__
1981 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMBASE, OP_LOADI8_MEMBASE):
1982 return OP_LOAD_MEMBASE;
1983 case MONO_PPC_32_64_CASE (OP_LOADI4_MEMINDEX, OP_LOADI8_MEMINDEX):
1984 return OP_LOAD_MEMINDEX;
1985 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_REG, OP_STOREI8_MEMBASE_REG):
1986 return OP_STORE_MEMBASE_REG;
1987 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMBASE_IMM, OP_STOREI8_MEMBASE_IMM):
1988 return OP_STORE_MEMBASE_IMM;
1989 case MONO_PPC_32_64_CASE (OP_STOREI4_MEMINDEX, OP_STOREI8_MEMINDEX):
1990 return OP_STORE_MEMINDEX;
1992 case MONO_PPC_32_64_CASE (OP_ISHR_IMM, OP_LSHR_IMM):
1994 case MONO_PPC_32_64_CASE (OP_ISHR_UN_IMM, OP_LSHR_UN_IMM):
1995 return OP_SHR_UN_IMM;
2002 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2004 MonoInst *ins, *n, *last_ins = NULL;
2006 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2007 switch (normalize_opcode (ins->opcode)) {
2009 /* remove unnecessary multiplication with 1 */
2010 if (ins->inst_imm == 1) {
2011 if (ins->dreg != ins->sreg1) {
2012 ins->opcode = OP_MOVE;
2014 MONO_DELETE_INS (bb, ins);
2018 int power2 = mono_is_power_of_two (ins->inst_imm);
2020 ins->opcode = OP_SHL_IMM;
2021 ins->inst_imm = power2;
2025 case OP_LOAD_MEMBASE:
2027 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2028 * OP_LOAD_MEMBASE offset(basereg), reg
2030 if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_REG &&
2031 ins->inst_basereg == last_ins->inst_destbasereg &&
2032 ins->inst_offset == last_ins->inst_offset) {
2033 if (ins->dreg == last_ins->sreg1) {
2034 MONO_DELETE_INS (bb, ins);
2037 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2038 ins->opcode = OP_MOVE;
2039 ins->sreg1 = last_ins->sreg1;
2043 * Note: reg1 must be different from the basereg in the second load
2044 * OP_LOAD_MEMBASE offset(basereg), reg1
2045 * OP_LOAD_MEMBASE offset(basereg), reg2
2047 * OP_LOAD_MEMBASE offset(basereg), reg1
2048 * OP_MOVE reg1, reg2
2050 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_LOAD_MEMBASE &&
2051 ins->inst_basereg != last_ins->dreg &&
2052 ins->inst_basereg == last_ins->inst_basereg &&
2053 ins->inst_offset == last_ins->inst_offset) {
2055 if (ins->dreg == last_ins->dreg) {
2056 MONO_DELETE_INS (bb, ins);
2059 ins->opcode = OP_MOVE;
2060 ins->sreg1 = last_ins->dreg;
2063 //g_assert_not_reached ();
2067 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2068 * OP_LOAD_MEMBASE offset(basereg), reg
2070 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2071 * OP_ICONST reg, imm
2073 } else if (last_ins && normalize_opcode (last_ins->opcode) == OP_STORE_MEMBASE_IMM &&
2074 ins->inst_basereg == last_ins->inst_destbasereg &&
2075 ins->inst_offset == last_ins->inst_offset) {
2076 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2077 ins->opcode = OP_ICONST;
2078 ins->inst_c0 = last_ins->inst_imm;
2079 g_assert_not_reached (); // check this rule
2083 case OP_LOADU1_MEMBASE:
2084 case OP_LOADI1_MEMBASE:
2085 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2086 ins->inst_basereg == last_ins->inst_destbasereg &&
2087 ins->inst_offset == last_ins->inst_offset) {
2088 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2089 ins->sreg1 = last_ins->sreg1;
2092 case OP_LOADU2_MEMBASE:
2093 case OP_LOADI2_MEMBASE:
2094 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2095 ins->inst_basereg == last_ins->inst_destbasereg &&
2096 ins->inst_offset == last_ins->inst_offset) {
2097 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2098 ins->sreg1 = last_ins->sreg1;
2101 #ifdef __mono_ppc64__
2102 case OP_LOADU4_MEMBASE:
2103 case OP_LOADI4_MEMBASE:
2104 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2105 ins->inst_basereg == last_ins->inst_destbasereg &&
2106 ins->inst_offset == last_ins->inst_offset) {
2107 ins->opcode = (ins->opcode == OP_LOADI4_MEMBASE) ? OP_ICONV_TO_I4 : OP_ICONV_TO_U4;
2108 ins->sreg1 = last_ins->sreg1;
2113 ins->opcode = OP_MOVE;
2117 if (ins->dreg == ins->sreg1) {
2118 MONO_DELETE_INS (bb, ins);
2122 * OP_MOVE sreg, dreg
2123 * OP_MOVE dreg, sreg
2125 if (last_ins && last_ins->opcode == OP_MOVE &&
2126 ins->sreg1 == last_ins->dreg &&
2127 ins->dreg == last_ins->sreg1) {
2128 MONO_DELETE_INS (bb, ins);
2136 bb->last_ins = last_ins;
2140 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2142 switch (ins->opcode) {
2143 case OP_ICONV_TO_R_UN: {
2144 #if G_BYTE_ORDER == G_BIG_ENDIAN
2145 static const guint64 adjust_val = 0x4330000000000000ULL;
2147 static const guint64 adjust_val = 0x0000000000003043ULL;
2149 int msw_reg = mono_alloc_ireg (cfg);
2150 int adj_reg = mono_alloc_freg (cfg);
2151 int tmp_reg = mono_alloc_freg (cfg);
2152 int basereg = ppc_sp;
2154 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2155 if (!ppc_is_imm16 (offset + 4)) {
2156 basereg = mono_alloc_ireg (cfg);
2157 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2159 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2160 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, ins->sreg1);
2161 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2162 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2163 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2164 ins->opcode = OP_NOP;
2167 #ifndef __mono_ppc64__
2168 case OP_ICONV_TO_R4:
2169 case OP_ICONV_TO_R8: {
2170 /* If we have a PPC_FEATURE_64 machine we can avoid
2171 this and use the fcfid instruction. Otherwise
2172 on an old 32-bit chip and we have to do this the
2174 if (!(cpu_hw_caps & PPC_ISA_64)) {
2175 /* FIXME: change precision for CEE_CONV_R4 */
2176 static const guint64 adjust_val = 0x4330000080000000ULL;
2177 int msw_reg = mono_alloc_ireg (cfg);
2178 int xored = mono_alloc_ireg (cfg);
2179 int adj_reg = mono_alloc_freg (cfg);
2180 int tmp_reg = mono_alloc_freg (cfg);
2181 int basereg = ppc_sp;
2183 if (!ppc_is_imm16 (offset + 4)) {
2184 basereg = mono_alloc_ireg (cfg);
2185 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2187 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2188 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset, msw_reg);
2189 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2190 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, basereg, offset + 4, xored);
2191 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2192 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, basereg, offset);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2194 if (ins->opcode == OP_ICONV_TO_R4)
2195 MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2196 ins->opcode = OP_NOP;
2202 int msw_reg = mono_alloc_ireg (cfg);
2203 int basereg = ppc_sp;
2205 if (!ppc_is_imm16 (offset + 4)) {
2206 basereg = mono_alloc_ireg (cfg);
2207 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, basereg, cfg->frame_reg, offset);
2209 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, basereg, offset, ins->sreg1);
2210 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, basereg, offset);
2211 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2212 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2213 ins->opcode = OP_NOP;
2216 #ifdef __mono_ppc64__
2218 case OP_IADD_OVF_UN:
2220 int shifted1_reg = mono_alloc_ireg (cfg);
2221 int shifted2_reg = mono_alloc_ireg (cfg);
2222 int result_shifted_reg = mono_alloc_ireg (cfg);
2224 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted1_reg, ins->sreg1, 32);
2225 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, shifted2_reg, ins->sreg2, 32);
2226 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, result_shifted_reg, shifted1_reg, shifted2_reg);
2227 if (ins->opcode == OP_IADD_OVF_UN)
2228 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, ins->dreg, result_shifted_reg, 32);
2230 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, ins->dreg, result_shifted_reg, 32);
2231 ins->opcode = OP_NOP;
2238 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2240 switch (ins->opcode) {
2242 /* ADC sets the condition code */
2243 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2247 case OP_LADD_OVF_UN:
2248 /* ADC sets the condition code */
2249 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2250 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2254 /* SBB sets the condition code */
2255 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2256 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2259 case OP_LSUB_OVF_UN:
2260 /* SBB sets the condition code */
2261 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
2266 /* From gcc generated code */
2267 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PPC_SUBFIC, ins->dreg + 1, ins->sreg1 + 1, 0);
2268 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
2277 * the branch_b0_table should maintain the order of these
2291 branch_b0_table [] = {
2306 branch_b1_table [] = {
2320 #define NEW_INS(cfg,dest,op) do { \
2321 MONO_INST_NEW((cfg), (dest), (op)); \
2322 mono_bblock_insert_after_ins (bb, last_ins, (dest)); \
2326 map_to_reg_reg_op (int op)
2335 case OP_COMPARE_IMM:
2337 case OP_ICOMPARE_IMM:
2339 case OP_LCOMPARE_IMM:
2355 case OP_LOAD_MEMBASE:
2356 return OP_LOAD_MEMINDEX;
2357 case OP_LOADI4_MEMBASE:
2358 return OP_LOADI4_MEMINDEX;
2359 case OP_LOADU4_MEMBASE:
2360 return OP_LOADU4_MEMINDEX;
2361 case OP_LOADI8_MEMBASE:
2362 return OP_LOADI8_MEMINDEX;
2363 case OP_LOADU1_MEMBASE:
2364 return OP_LOADU1_MEMINDEX;
2365 case OP_LOADI2_MEMBASE:
2366 return OP_LOADI2_MEMINDEX;
2367 case OP_LOADU2_MEMBASE:
2368 return OP_LOADU2_MEMINDEX;
2369 case OP_LOADI1_MEMBASE:
2370 return OP_LOADI1_MEMINDEX;
2371 case OP_LOADR4_MEMBASE:
2372 return OP_LOADR4_MEMINDEX;
2373 case OP_LOADR8_MEMBASE:
2374 return OP_LOADR8_MEMINDEX;
2375 case OP_STOREI1_MEMBASE_REG:
2376 return OP_STOREI1_MEMINDEX;
2377 case OP_STOREI2_MEMBASE_REG:
2378 return OP_STOREI2_MEMINDEX;
2379 case OP_STOREI4_MEMBASE_REG:
2380 return OP_STOREI4_MEMINDEX;
2381 case OP_STOREI8_MEMBASE_REG:
2382 return OP_STOREI8_MEMINDEX;
2383 case OP_STORE_MEMBASE_REG:
2384 return OP_STORE_MEMINDEX;
2385 case OP_STORER4_MEMBASE_REG:
2386 return OP_STORER4_MEMINDEX;
2387 case OP_STORER8_MEMBASE_REG:
2388 return OP_STORER8_MEMINDEX;
2389 case OP_STORE_MEMBASE_IMM:
2390 return OP_STORE_MEMBASE_REG;
2391 case OP_STOREI1_MEMBASE_IMM:
2392 return OP_STOREI1_MEMBASE_REG;
2393 case OP_STOREI2_MEMBASE_IMM:
2394 return OP_STOREI2_MEMBASE_REG;
2395 case OP_STOREI4_MEMBASE_IMM:
2396 return OP_STOREI4_MEMBASE_REG;
2397 case OP_STOREI8_MEMBASE_IMM:
2398 return OP_STOREI8_MEMBASE_REG;
2400 return mono_op_imm_to_op (op);
2403 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2405 #define compare_opcode_is_unsigned(opcode) \
2406 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) || \
2407 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) || \
2408 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) || \
2409 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) || \
2410 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) || \
2411 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || \
2412 (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN || \
2413 (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2416 * Remove from the instruction list the instructions that can't be
2417 * represented with very simple instructions with no register
2421 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2423 MonoInst *ins, *next, *temp, *last_ins = NULL;
2426 MONO_BB_FOR_EACH_INS (bb, ins) {
2428 switch (ins->opcode) {
2429 case OP_IDIV_UN_IMM:
2432 case OP_IREM_UN_IMM:
2433 NEW_INS (cfg, temp, OP_ICONST);
2434 temp->inst_c0 = ins->inst_imm;
2435 temp->dreg = mono_alloc_ireg (cfg);
2436 ins->sreg2 = temp->dreg;
2437 if (ins->opcode == OP_IDIV_IMM)
2438 ins->opcode = OP_IDIV;
2439 else if (ins->opcode == OP_IREM_IMM)
2440 ins->opcode = OP_IREM;
2441 else if (ins->opcode == OP_IDIV_UN_IMM)
2442 ins->opcode = OP_IDIV_UN;
2443 else if (ins->opcode == OP_IREM_UN_IMM)
2444 ins->opcode = OP_IREM_UN;
2446 /* handle rem separately */
2450 CASE_PPC64 (OP_LREM)
2451 CASE_PPC64 (OP_LREM_UN) {
2453 /* we change a rem dest, src1, src2 to
2454 * div temp1, src1, src2
2455 * mul temp2, temp1, src2
2456 * sub dest, src1, temp2
2458 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2459 NEW_INS (cfg, mul, OP_IMUL);
2460 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2461 ins->opcode = OP_ISUB;
2463 NEW_INS (cfg, mul, OP_LMUL);
2464 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2465 ins->opcode = OP_LSUB;
2467 temp->sreg1 = ins->sreg1;
2468 temp->sreg2 = ins->sreg2;
2469 temp->dreg = mono_alloc_ireg (cfg);
2470 mul->sreg1 = temp->dreg;
2471 mul->sreg2 = ins->sreg2;
2472 mul->dreg = mono_alloc_ireg (cfg);
2473 ins->sreg2 = mul->dreg;
2477 CASE_PPC64 (OP_LADD_IMM)
2480 if (!ppc_is_imm16 (ins->inst_imm)) {
2481 NEW_INS (cfg, temp, OP_ICONST);
2482 temp->inst_c0 = ins->inst_imm;
2483 temp->dreg = mono_alloc_ireg (cfg);
2484 ins->sreg2 = temp->dreg;
2485 ins->opcode = map_to_reg_reg_op (ins->opcode);
2489 CASE_PPC64 (OP_LSUB_IMM)
2491 if (!ppc_is_imm16 (-ins->inst_imm)) {
2492 NEW_INS (cfg, temp, OP_ICONST);
2493 temp->inst_c0 = ins->inst_imm;
2494 temp->dreg = mono_alloc_ireg (cfg);
2495 ins->sreg2 = temp->dreg;
2496 ins->opcode = map_to_reg_reg_op (ins->opcode);
2508 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2509 #ifdef __mono_ppc64__
2510 if (ins->inst_imm & 0xffffffff00000000ULL)
2514 NEW_INS (cfg, temp, OP_ICONST);
2515 temp->inst_c0 = ins->inst_imm;
2516 temp->dreg = mono_alloc_ireg (cfg);
2517 ins->sreg2 = temp->dreg;
2518 ins->opcode = map_to_reg_reg_op (ins->opcode);
2527 NEW_INS (cfg, temp, OP_ICONST);
2528 temp->inst_c0 = ins->inst_imm;
2529 temp->dreg = mono_alloc_ireg (cfg);
2530 ins->sreg2 = temp->dreg;
2531 ins->opcode = map_to_reg_reg_op (ins->opcode);
2533 case OP_COMPARE_IMM:
2534 case OP_ICOMPARE_IMM:
2535 CASE_PPC64 (OP_LCOMPARE_IMM)
2537 /* Branch opts can eliminate the branch */
2538 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2539 ins->opcode = OP_NOP;
2543 if (compare_opcode_is_unsigned (next->opcode)) {
2544 if (!ppc_is_uimm16 (ins->inst_imm)) {
2545 NEW_INS (cfg, temp, OP_ICONST);
2546 temp->inst_c0 = ins->inst_imm;
2547 temp->dreg = mono_alloc_ireg (cfg);
2548 ins->sreg2 = temp->dreg;
2549 ins->opcode = map_to_reg_reg_op (ins->opcode);
2552 if (!ppc_is_imm16 (ins->inst_imm)) {
2553 NEW_INS (cfg, temp, OP_ICONST);
2554 temp->inst_c0 = ins->inst_imm;
2555 temp->dreg = mono_alloc_ireg (cfg);
2556 ins->sreg2 = temp->dreg;
2557 ins->opcode = map_to_reg_reg_op (ins->opcode);
2563 if (ins->inst_imm == 1) {
2564 ins->opcode = OP_MOVE;
2567 if (ins->inst_imm == 0) {
2568 ins->opcode = OP_ICONST;
2572 imm = mono_is_power_of_two (ins->inst_imm);
2574 ins->opcode = OP_SHL_IMM;
2575 ins->inst_imm = imm;
2578 if (!ppc_is_imm16 (ins->inst_imm)) {
2579 NEW_INS (cfg, temp, OP_ICONST);
2580 temp->inst_c0 = ins->inst_imm;
2581 temp->dreg = mono_alloc_ireg (cfg);
2582 ins->sreg2 = temp->dreg;
2583 ins->opcode = map_to_reg_reg_op (ins->opcode);
2586 case OP_LOCALLOC_IMM:
2587 NEW_INS (cfg, temp, OP_ICONST);
2588 temp->inst_c0 = ins->inst_imm;
2589 temp->dreg = mono_alloc_ireg (cfg);
2590 ins->sreg1 = temp->dreg;
2591 ins->opcode = OP_LOCALLOC;
2593 case OP_LOAD_MEMBASE:
2594 case OP_LOADI4_MEMBASE:
2595 CASE_PPC64 (OP_LOADI8_MEMBASE)
2596 case OP_LOADU4_MEMBASE:
2597 case OP_LOADI2_MEMBASE:
2598 case OP_LOADU2_MEMBASE:
2599 case OP_LOADI1_MEMBASE:
2600 case OP_LOADU1_MEMBASE:
2601 case OP_LOADR4_MEMBASE:
2602 case OP_LOADR8_MEMBASE:
2603 case OP_STORE_MEMBASE_REG:
2604 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2605 case OP_STOREI4_MEMBASE_REG:
2606 case OP_STOREI2_MEMBASE_REG:
2607 case OP_STOREI1_MEMBASE_REG:
2608 case OP_STORER4_MEMBASE_REG:
2609 case OP_STORER8_MEMBASE_REG:
2610 /* we can do two things: load the immed in a register
2611 * and use an indexed load, or see if the immed can be
2612 * represented as an ad_imm + a load with a smaller offset
2613 * that fits. We just do the first for now, optimize later.
2615 if (ppc_is_imm16 (ins->inst_offset))
2617 NEW_INS (cfg, temp, OP_ICONST);
2618 temp->inst_c0 = ins->inst_offset;
2619 temp->dreg = mono_alloc_ireg (cfg);
2620 ins->sreg2 = temp->dreg;
2621 ins->opcode = map_to_reg_reg_op (ins->opcode);
2623 case OP_STORE_MEMBASE_IMM:
2624 case OP_STOREI1_MEMBASE_IMM:
2625 case OP_STOREI2_MEMBASE_IMM:
2626 case OP_STOREI4_MEMBASE_IMM:
2627 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2628 NEW_INS (cfg, temp, OP_ICONST);
2629 temp->inst_c0 = ins->inst_imm;
2630 temp->dreg = mono_alloc_ireg (cfg);
2631 ins->sreg1 = temp->dreg;
2632 ins->opcode = map_to_reg_reg_op (ins->opcode);
2634 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2637 if (cfg->compile_aot) {
2638 /* Keep these in the aot case */
2641 NEW_INS (cfg, temp, OP_ICONST);
2642 temp->inst_c0 = (gulong)ins->inst_p0;
2643 temp->dreg = mono_alloc_ireg (cfg);
2644 ins->inst_basereg = temp->dreg;
2645 ins->inst_offset = 0;
2646 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2648 /* make it handle the possibly big ins->inst_offset
2649 * later optimize to use lis + load_membase
2655 bb->last_ins = last_ins;
2656 bb->max_vreg = cfg->next_vreg;
2660 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2662 long offset = cfg->arch.fp_conv_var_offset;
2664 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2665 #ifdef __mono_ppc64__
2667 ppc_fctidz (code, ppc_f0, sreg);
2672 ppc_fctiwz (code, ppc_f0, sreg);
2675 if (ppc_is_imm16 (offset + sub_offset)) {
2676 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2678 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2680 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2682 ppc_load (code, dreg, offset);
2683 ppc_add (code, dreg, dreg, cfg->frame_reg);
2684 ppc_stfd (code, ppc_f0, 0, dreg);
2686 ppc_ldr (code, dreg, sub_offset, dreg);
2688 ppc_lwz (code, dreg, sub_offset, dreg);
2692 ppc_andid (code, dreg, dreg, 0xff);
2694 ppc_andid (code, dreg, dreg, 0xffff);
2695 #ifdef __mono_ppc64__
2697 ppc_clrldi (code, dreg, dreg, 32);
2701 ppc_extsb (code, dreg, dreg);
2703 ppc_extsh (code, dreg, dreg);
2704 #ifdef __mono_ppc64__
2706 ppc_extsw (code, dreg, dreg);
2714 const guchar *target;
2719 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2722 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2723 #ifdef __mono_ppc64__
2724 g_assert_not_reached ();
2726 PatchData *pdata = (PatchData*)user_data;
2727 guchar *code = data;
2728 guint32 *thunks = data;
2729 guint32 *endthunks = (guint32*)(code + bsize);
2733 int difflow, diffhigh;
2735 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2736 difflow = (char*)pdata->code - (char*)thunks;
2737 diffhigh = (char*)pdata->code - (char*)endthunks;
2738 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2741 templ = (guchar*)load;
2742 ppc_load_sequence (templ, ppc_r0, pdata->target);
2744 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2745 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2746 while (thunks < endthunks) {
2747 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2748 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2749 ppc_patch (pdata->code, (guchar*)thunks);
2752 static int num_thunks = 0;
2754 if ((num_thunks % 20) == 0)
2755 g_print ("num_thunks lookup: %d\n", num_thunks);
2758 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2759 /* found a free slot instead: emit thunk */
2760 code = (guchar*)thunks;
2761 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2762 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2763 ppc_mtctr (code, ppc_r0);
2764 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2765 mono_arch_flush_icache ((guchar*)thunks, 16);
2767 ppc_patch (pdata->code, (guchar*)thunks);
2770 static int num_thunks = 0;
2772 if ((num_thunks % 20) == 0)
2773 g_print ("num_thunks: %d\n", num_thunks);
2777 /* skip 16 bytes, the size of the thunk */
2781 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2788 handle_thunk (int absolute, guchar *code, const guchar *target) {
2789 MonoDomain *domain = mono_domain_get ();
2793 pdata.target = target;
2794 pdata.absolute = absolute;
2797 mono_domain_lock (domain);
2798 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2801 /* this uses the first available slot */
2803 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2805 mono_domain_unlock (domain);
2807 if (pdata.found != 1)
2808 g_print ("thunk failed for %p from %p\n", target, code);
2809 g_assert (pdata.found == 1);
2813 patch_ins (guint8 *code, guint32 ins)
2815 *(guint32*)code = GUINT32_TO_BE (ins);
2816 mono_arch_flush_icache (code, 4);
2820 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2822 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2823 guint32 prim = ins >> 26;
2826 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2828 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2829 gint diff = target - code;
2832 if (diff <= 33554431){
2833 ins = (18 << 26) | (diff) | (ins & 1);
2834 patch_ins (code, ins);
2838 /* diff between 0 and -33554432 */
2839 if (diff >= -33554432){
2840 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2841 patch_ins (code, ins);
2846 if ((glong)target >= 0){
2847 if ((glong)target <= 33554431){
2848 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2849 patch_ins (code, ins);
2853 if ((glong)target >= -33554432){
2854 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2855 patch_ins (code, ins);
2860 handle_thunk (TRUE, code, target);
2863 g_assert_not_reached ();
2871 guint32 li = (gulong)target;
2872 ins = (ins & 0xffff0000) | (ins & 3);
2873 ovf = li & 0xffff0000;
2874 if (ovf != 0 && ovf != 0xffff0000)
2875 g_assert_not_reached ();
2878 // FIXME: assert the top bits of li are 0
2880 gint diff = target - code;
2881 ins = (ins & 0xffff0000) | (ins & 3);
2882 ovf = diff & 0xffff0000;
2883 if (ovf != 0 && ovf != 0xffff0000)
2884 g_assert_not_reached ();
2888 patch_ins (code, ins);
2892 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2893 #ifdef __mono_ppc64__
2894 guint32 *seq = (guint32*)code;
2895 guint32 *branch_ins;
2897 /* the trampoline code will try to patch the blrl, blr, bcctr */
2898 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2900 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2905 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2906 branch_ins = seq + 8;
2908 branch_ins = seq + 6;
2911 seq = (guint32*)code;
2912 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2913 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2915 if (ppc_is_load_op (seq [5])) {
2916 g_assert (ppc_is_load_op (seq [6]));
2919 guint8 *buf = (guint8*)&seq [5];
2920 ppc_mr (buf, ppc_r0, ppc_r11);
2925 target = mono_get_addr_from_ftnptr ((gpointer)target);
2928 /* FIXME: make this thread safe */
2929 /* FIXME: we're assuming we're using r11 here */
2930 ppc_load_ptr_sequence (code, ppc_r11, target);
2931 mono_arch_flush_icache ((guint8*)seq, 28);
2934 /* the trampoline code will try to patch the blrl, blr, bcctr */
2935 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2938 /* this is the lis/ori/mtlr/blrl sequence */
2939 seq = (guint32*)code;
2940 g_assert ((seq [0] >> 26) == 15);
2941 g_assert ((seq [1] >> 26) == 24);
2942 g_assert ((seq [2] >> 26) == 31);
2943 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2944 /* FIXME: make this thread safe */
2945 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2946 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2947 mono_arch_flush_icache (code - 8, 8);
2950 g_assert_not_reached ();
2952 // g_print ("patched with 0x%08x\n", ins);
2956 ppc_patch (guchar *code, const guchar *target)
2958 ppc_patch_full (code, target, FALSE);
2962 mono_ppc_patch (guchar *code, const guchar *target)
2964 ppc_patch (code, target);
2968 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2970 switch (ins->opcode) {
2973 case OP_FCALL_MEMBASE:
2974 if (ins->dreg != ppc_f1)
2975 ppc_fmr (code, ins->dreg, ppc_f1);
2983 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2985 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2989 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2991 long size = cfg->param_area;
2993 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2994 size &= -MONO_ARCH_FRAME_ALIGNMENT;
2999 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3000 if (ppc_is_imm16 (-size)) {
3001 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3003 ppc_load (code, ppc_r11, -size);
3004 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3011 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3013 long size = cfg->param_area;
3015 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3016 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3021 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3022 if (ppc_is_imm16 (size)) {
3023 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3025 ppc_load (code, ppc_r11, size);
3026 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3032 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3036 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3038 MonoInst *ins, *next;
3041 guint8 *code = cfg->native_code + cfg->code_len;
3042 MonoInst *last_ins = NULL;
3043 guint last_offset = 0;
3047 /* we don't align basic blocks of loops on ppc */
3049 if (cfg->verbose_level > 2)
3050 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3052 cpos = bb->max_offset;
3054 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3055 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3056 //g_assert (!mono_compile_aot);
3059 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3060 /* this is not thread save, but good enough */
3061 /* fixme: howto handle overflows? */
3062 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3065 MONO_BB_FOR_EACH_INS (bb, ins) {
3066 offset = code - cfg->native_code;
3068 max_len = ins_native_length (cfg, ins);
3070 if (offset > (cfg->code_size - max_len - 16)) {
3071 cfg->code_size *= 2;
3072 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3073 code = cfg->native_code + offset;
3075 // if (ins->cil_code)
3076 // g_print ("cil code\n");
3077 mono_debug_record_line_number (cfg, ins, offset);
3079 switch (normalize_opcode (ins->opcode)) {
3080 case OP_RELAXED_NOP:
3083 case OP_DUMMY_STORE:
3084 case OP_NOT_REACHED:
3087 case OP_SEQ_POINT: {
3090 if (cfg->compile_aot)
3094 * Read from the single stepping trigger page. This will cause a
3095 * SIGSEGV when single stepping is enabled.
3096 * We do this _before_ the breakpoint, so single stepping after
3097 * a breakpoint is hit will step to the next IL offset.
3099 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3100 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3101 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3104 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3107 * A placeholder for a possible breakpoint inserted by
3108 * mono_arch_set_breakpoint ().
3110 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3115 emit_tls_access (code, ins->dreg, ins->inst_offset);
3118 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3119 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3120 ppc_mr (code, ppc_r4, ppc_r0);
3123 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3124 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3125 ppc_mr (code, ppc_r4, ppc_r0);
3127 case OP_MEMORY_BARRIER:
3130 case OP_STOREI1_MEMBASE_REG:
3131 if (ppc_is_imm16 (ins->inst_offset)) {
3132 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3134 if (ppc_is_imm32 (ins->inst_offset)) {
3135 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3136 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3138 ppc_load (code, ppc_r0, ins->inst_offset);
3139 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3143 case OP_STOREI2_MEMBASE_REG:
3144 if (ppc_is_imm16 (ins->inst_offset)) {
3145 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3147 if (ppc_is_imm32 (ins->inst_offset)) {
3148 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3149 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3151 ppc_load (code, ppc_r0, ins->inst_offset);
3152 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3156 case OP_STORE_MEMBASE_REG:
3157 if (ppc_is_imm16 (ins->inst_offset)) {
3158 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3160 if (ppc_is_imm32 (ins->inst_offset)) {
3161 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3162 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3164 ppc_load (code, ppc_r0, ins->inst_offset);
3165 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3169 #ifdef __mono_ilp32__
3170 case OP_STOREI8_MEMBASE_REG:
3171 if (ppc_is_imm16 (ins->inst_offset)) {
3172 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3174 ppc_load (code, ppc_r0, ins->inst_offset);
3175 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3179 case OP_STOREI1_MEMINDEX:
3180 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3182 case OP_STOREI2_MEMINDEX:
3183 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3185 case OP_STORE_MEMINDEX:
3186 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3189 g_assert_not_reached ();
3191 case OP_LOAD_MEMBASE:
3192 if (ppc_is_imm16 (ins->inst_offset)) {
3193 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3195 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3196 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3197 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3199 ppc_load (code, ppc_r0, ins->inst_offset);
3200 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3204 case OP_LOADI4_MEMBASE:
3205 #ifdef __mono_ppc64__
3206 if (ppc_is_imm16 (ins->inst_offset)) {
3207 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3209 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3210 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3211 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3213 ppc_load (code, ppc_r0, ins->inst_offset);
3214 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3219 case OP_LOADU4_MEMBASE:
3220 if (ppc_is_imm16 (ins->inst_offset)) {
3221 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3223 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3224 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3225 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3227 ppc_load (code, ppc_r0, ins->inst_offset);
3228 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3232 case OP_LOADI1_MEMBASE:
3233 case OP_LOADU1_MEMBASE:
3234 if (ppc_is_imm16 (ins->inst_offset)) {
3235 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3237 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3238 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3239 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3241 ppc_load (code, ppc_r0, ins->inst_offset);
3242 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3245 if (ins->opcode == OP_LOADI1_MEMBASE)
3246 ppc_extsb (code, ins->dreg, ins->dreg);
3248 case OP_LOADU2_MEMBASE:
3249 if (ppc_is_imm16 (ins->inst_offset)) {
3250 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3252 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3253 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3254 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3256 ppc_load (code, ppc_r0, ins->inst_offset);
3257 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3261 case OP_LOADI2_MEMBASE:
3262 if (ppc_is_imm16 (ins->inst_offset)) {
3263 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3265 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3266 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3267 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3269 ppc_load (code, ppc_r0, ins->inst_offset);
3270 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3274 #ifdef __mono_ilp32__
3275 case OP_LOADI8_MEMBASE:
3276 if (ppc_is_imm16 (ins->inst_offset)) {
3277 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3279 ppc_load (code, ppc_r0, ins->inst_offset);
3280 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3284 case OP_LOAD_MEMINDEX:
3285 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3287 case OP_LOADI4_MEMINDEX:
3288 #ifdef __mono_ppc64__
3289 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3292 case OP_LOADU4_MEMINDEX:
3293 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3295 case OP_LOADU2_MEMINDEX:
3296 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3298 case OP_LOADI2_MEMINDEX:
3299 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3301 case OP_LOADU1_MEMINDEX:
3302 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3304 case OP_LOADI1_MEMINDEX:
3305 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3306 ppc_extsb (code, ins->dreg, ins->dreg);
3308 case OP_ICONV_TO_I1:
3309 CASE_PPC64 (OP_LCONV_TO_I1)
3310 ppc_extsb (code, ins->dreg, ins->sreg1);
3312 case OP_ICONV_TO_I2:
3313 CASE_PPC64 (OP_LCONV_TO_I2)
3314 ppc_extsh (code, ins->dreg, ins->sreg1);
3316 case OP_ICONV_TO_U1:
3317 CASE_PPC64 (OP_LCONV_TO_U1)
3318 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3320 case OP_ICONV_TO_U2:
3321 CASE_PPC64 (OP_LCONV_TO_U2)
3322 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3326 CASE_PPC64 (OP_LCOMPARE)
3327 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3329 if (next && compare_opcode_is_unsigned (next->opcode))
3330 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3332 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3334 case OP_COMPARE_IMM:
3335 case OP_ICOMPARE_IMM:
3336 CASE_PPC64 (OP_LCOMPARE_IMM)
3337 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3339 if (next && compare_opcode_is_unsigned (next->opcode)) {
3340 if (ppc_is_uimm16 (ins->inst_imm)) {
3341 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3343 g_assert_not_reached ();
3346 if (ppc_is_imm16 (ins->inst_imm)) {
3347 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3349 g_assert_not_reached ();
3355 * gdb does not like encountering a trap in the debugged code. So
3356 * instead of emitting a trap, we emit a call a C function and place a
3360 ppc_mr (code, ppc_r3, ins->sreg1);
3361 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3362 (gpointer)"mono_break");
3363 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3364 ppc_load_func (code, ppc_r0, 0);
3365 ppc_mtlr (code, ppc_r0);
3373 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3376 CASE_PPC64 (OP_LADD)
3377 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3381 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3384 if (ppc_is_imm16 (ins->inst_imm)) {
3385 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3387 g_assert_not_reached ();
3392 CASE_PPC64 (OP_LADD_IMM)
3393 if (ppc_is_imm16 (ins->inst_imm)) {
3394 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3396 g_assert_not_reached ();
3400 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3402 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3403 ppc_mfspr (code, ppc_r0, ppc_xer);
3404 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3405 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3407 case OP_IADD_OVF_UN:
3408 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3410 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3411 ppc_mfspr (code, ppc_r0, ppc_xer);
3412 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3413 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3416 CASE_PPC64 (OP_LSUB_OVF)
3417 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3419 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3420 ppc_mfspr (code, ppc_r0, ppc_xer);
3421 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3422 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3424 case OP_ISUB_OVF_UN:
3425 CASE_PPC64 (OP_LSUB_OVF_UN)
3426 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3428 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3429 ppc_mfspr (code, ppc_r0, ppc_xer);
3430 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3431 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3433 case OP_ADD_OVF_CARRY:
3434 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3436 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3437 ppc_mfspr (code, ppc_r0, ppc_xer);
3438 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3439 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3441 case OP_ADD_OVF_UN_CARRY:
3442 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3444 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3445 ppc_mfspr (code, ppc_r0, ppc_xer);
3446 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3447 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3449 case OP_SUB_OVF_CARRY:
3450 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3452 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3453 ppc_mfspr (code, ppc_r0, ppc_xer);
3454 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3455 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3457 case OP_SUB_OVF_UN_CARRY:
3458 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3460 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3461 ppc_mfspr (code, ppc_r0, ppc_xer);
3462 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3463 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3467 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3470 CASE_PPC64 (OP_LSUB)
3471 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3475 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3479 CASE_PPC64 (OP_LSUB_IMM)
3480 // we add the negated value
3481 if (ppc_is_imm16 (-ins->inst_imm))
3482 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3484 g_assert_not_reached ();
3488 g_assert (ppc_is_imm16 (ins->inst_imm));
3489 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3492 ppc_subfze (code, ins->dreg, ins->sreg1);
3495 CASE_PPC64 (OP_LAND)
3496 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3497 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3501 CASE_PPC64 (OP_LAND_IMM)
3502 if (!(ins->inst_imm & 0xffff0000)) {
3503 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3504 } else if (!(ins->inst_imm & 0xffff)) {
3505 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3507 g_assert_not_reached ();
3511 CASE_PPC64 (OP_LDIV) {
3512 guint8 *divisor_is_m1;
3513 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3515 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3516 divisor_is_m1 = code;
3517 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3518 ppc_lis (code, ppc_r0, 0x8000);
3519 #ifdef __mono_ppc64__
3520 if (ins->opcode == OP_LDIV)
3521 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3523 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3524 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3525 ppc_patch (divisor_is_m1, code);
3526 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3528 if (ins->opcode == OP_IDIV)
3529 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3530 #ifdef __mono_ppc64__
3532 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3534 ppc_mfspr (code, ppc_r0, ppc_xer);
3535 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3536 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3540 CASE_PPC64 (OP_LDIV_UN)
3541 if (ins->opcode == OP_IDIV_UN)
3542 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3543 #ifdef __mono_ppc64__
3545 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3547 ppc_mfspr (code, ppc_r0, ppc_xer);
3548 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3549 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3555 g_assert_not_reached ();
3558 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3562 CASE_PPC64 (OP_LOR_IMM)
3563 if (!(ins->inst_imm & 0xffff0000)) {
3564 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3565 } else if (!(ins->inst_imm & 0xffff)) {
3566 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3568 g_assert_not_reached ();
3572 CASE_PPC64 (OP_LXOR)
3573 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3577 CASE_PPC64 (OP_LXOR_IMM)
3578 if (!(ins->inst_imm & 0xffff0000)) {
3579 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3580 } else if (!(ins->inst_imm & 0xffff)) {
3581 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3583 g_assert_not_reached ();
3587 CASE_PPC64 (OP_LSHL)
3588 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3592 CASE_PPC64 (OP_LSHL_IMM)
3593 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3596 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3602 if (MASK_SHIFT_IMM (ins->inst_imm))
3603 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3605 ppc_mr (code, ins->dreg, ins->sreg1);
3608 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3611 CASE_PPC64 (OP_LNOT)
3612 ppc_not (code, ins->dreg, ins->sreg1);
3615 CASE_PPC64 (OP_LNEG)
3616 ppc_neg (code, ins->dreg, ins->sreg1);
3619 CASE_PPC64 (OP_LMUL)
3620 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 CASE_PPC64 (OP_LMUL_IMM)
3625 if (ppc_is_imm16 (ins->inst_imm)) {
3626 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3628 g_assert_not_reached ();
3632 CASE_PPC64 (OP_LMUL_OVF)
3633 /* we annot use mcrxr, since it's not implemented on some processors
3634 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3636 if (ins->opcode == OP_IMUL_OVF)
3637 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3638 #ifdef __mono_ppc64__
3640 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3642 ppc_mfspr (code, ppc_r0, ppc_xer);
3643 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3644 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3646 case OP_IMUL_OVF_UN:
3647 CASE_PPC64 (OP_LMUL_OVF_UN)
3648 /* we first multiply to get the high word and compare to 0
3649 * to set the flags, then the result is discarded and then
3650 * we multiply to get the lower * bits result
3652 if (ins->opcode == OP_IMUL_OVF_UN)
3653 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3654 #ifdef __mono_ppc64__
3656 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3658 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3659 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3660 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3663 ppc_load (code, ins->dreg, ins->inst_c0);
3666 ppc_load (code, ins->dreg, ins->inst_l);
3669 case OP_LOAD_GOTADDR:
3670 /* The PLT implementation depends on this */
3671 g_assert (ins->dreg == ppc_r30);
3673 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3676 // FIXME: Fix max instruction length
3677 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3678 /* arch_emit_got_access () patches this */
3679 ppc_load32 (code, ppc_r0, 0);
3680 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3683 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3684 ppc_load_sequence (code, ins->dreg, 0);
3686 CASE_PPC32 (OP_ICONV_TO_I4)
3687 CASE_PPC32 (OP_ICONV_TO_U4)
3689 ppc_mr (code, ins->dreg, ins->sreg1);
3692 int saved = ins->sreg1;
3693 if (ins->sreg1 == ppc_r3) {
3694 ppc_mr (code, ppc_r0, ins->sreg1);
3697 if (ins->sreg2 != ppc_r3)
3698 ppc_mr (code, ppc_r3, ins->sreg2);
3699 if (saved != ppc_r4)
3700 ppc_mr (code, ppc_r4, saved);
3704 ppc_fmr (code, ins->dreg, ins->sreg1);
3706 case OP_FCONV_TO_R4:
3707 ppc_frsp (code, ins->dreg, ins->sreg1);
3711 MonoCallInst *call = (MonoCallInst*)ins;
3714 * Keep in sync with mono_arch_emit_epilog
3716 g_assert (!cfg->method->save_lmf);
3718 * Note: we can use ppc_r11 here because it is dead anyway:
3719 * we're leaving the method.
3721 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3722 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3723 if (ppc_is_imm16 (ret_offset)) {
3724 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3726 ppc_load (code, ppc_r11, ret_offset);
3727 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3729 ppc_mtlr (code, ppc_r0);
3732 if (ppc_is_imm16 (cfg->stack_usage)) {
3733 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3735 /* cfg->stack_usage is an int, so we can use
3736 * an addis/addi sequence here even in 64-bit. */
3737 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3738 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3740 if (!cfg->method->save_lmf) {
3742 for (i = 31; i >= 13; --i) {
3743 if (cfg->used_int_regs & (1 << i)) {
3744 pos += sizeof (gpointer);
3745 ppc_ldptr (code, i, -pos, ppc_r11);
3749 /* FIXME restore from MonoLMF: though this can't happen yet */
3752 /* Copy arguments on the stack to our argument area */
3753 if (call->stack_usage) {
3754 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3755 /* r11 was clobbered */
3756 g_assert (cfg->frame_reg == ppc_sp);
3757 if (ppc_is_imm16 (cfg->stack_usage)) {
3758 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3760 /* cfg->stack_usage is an int, so we can use
3761 * an addis/addi sequence here even in 64-bit. */
3762 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3763 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3767 ppc_mr (code, ppc_sp, ppc_r11);
3768 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3769 if (cfg->compile_aot) {
3770 /* arch_emit_got_access () patches this */
3771 ppc_load32 (code, ppc_r0, 0);
3772 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3773 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3774 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3776 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3778 ppc_mtctr (code, ppc_r0);
3779 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3786 /* ensure ins->sreg1 is not NULL */
3787 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3790 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3791 if (ppc_is_imm16 (cookie_offset)) {
3792 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3794 ppc_load (code, ppc_r0, cookie_offset);
3795 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3797 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3806 call = (MonoCallInst*)ins;
3807 if (ins->flags & MONO_INST_HAS_METHOD)
3808 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3810 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3811 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3812 ppc_load_func (code, ppc_r0, 0);
3813 ppc_mtlr (code, ppc_r0);
3818 /* FIXME: this should be handled somewhere else in the new jit */
3819 code = emit_move_return_value (cfg, ins, code);
3825 case OP_VOIDCALL_REG:
3827 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3828 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3829 /* FIXME: if we know that this is a method, we
3830 can omit this load */
3831 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3832 ppc_mtlr (code, ppc_r0);
3834 ppc_mtlr (code, ins->sreg1);
3837 /* FIXME: this should be handled somewhere else in the new jit */
3838 code = emit_move_return_value (cfg, ins, code);
3840 case OP_FCALL_MEMBASE:
3841 case OP_LCALL_MEMBASE:
3842 case OP_VCALL_MEMBASE:
3843 case OP_VCALL2_MEMBASE:
3844 case OP_VOIDCALL_MEMBASE:
3845 case OP_CALL_MEMBASE:
3846 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3847 /* The trampolines clobber this */
3848 ppc_mr (code, ppc_r29, ins->sreg1);
3849 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3851 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3853 ppc_mtlr (code, ppc_r0);
3855 /* FIXME: this should be handled somewhere else in the new jit */
3856 code = emit_move_return_value (cfg, ins, code);
3859 guint8 * zero_loop_jump, * zero_loop_start;
3860 /* keep alignment */
3861 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3862 int area_offset = alloca_waste;
3864 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3865 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3866 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3867 /* use ctr to store the number of words to 0 if needed */
3868 if (ins->flags & MONO_INST_INIT) {
3869 /* we zero 4 bytes at a time:
3870 * we add 7 instead of 3 so that we set the counter to
3871 * at least 1, otherwise the bdnz instruction will make
3872 * it negative and iterate billions of times.
3874 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3875 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3876 ppc_mtctr (code, ppc_r0);
3878 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3879 ppc_neg (code, ppc_r11, ppc_r11);
3880 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3882 /* FIXME: make this loop work in 8 byte
3883 increments on PPC64 */
3884 if (ins->flags & MONO_INST_INIT) {
3885 /* adjust the dest reg by -4 so we can use stwu */
3886 /* we actually adjust -8 because we let the loop
3889 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3890 ppc_li (code, ppc_r11, 0);
3891 zero_loop_start = code;
3892 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3893 zero_loop_jump = code;
3894 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3895 ppc_patch (zero_loop_jump, zero_loop_start);
3897 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3902 ppc_mr (code, ppc_r3, ins->sreg1);
3903 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3904 (gpointer)"mono_arch_throw_exception");
3905 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3906 ppc_load_func (code, ppc_r0, 0);
3907 ppc_mtlr (code, ppc_r0);
3916 ppc_mr (code, ppc_r3, ins->sreg1);
3917 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3918 (gpointer)"mono_arch_rethrow_exception");
3919 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3920 ppc_load_func (code, ppc_r0, 0);
3921 ppc_mtlr (code, ppc_r0);
3928 case OP_START_HANDLER: {
3929 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3930 g_assert (spvar->inst_basereg != ppc_sp);
3931 code = emit_reserve_param_area (cfg, code);
3932 ppc_mflr (code, ppc_r0);
3933 if (ppc_is_imm16 (spvar->inst_offset)) {
3934 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3936 ppc_load (code, ppc_r11, spvar->inst_offset);
3937 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3941 case OP_ENDFILTER: {
3942 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3943 g_assert (spvar->inst_basereg != ppc_sp);
3944 code = emit_unreserve_param_area (cfg, code);
3945 if (ins->sreg1 != ppc_r3)
3946 ppc_mr (code, ppc_r3, ins->sreg1);
3947 if (ppc_is_imm16 (spvar->inst_offset)) {
3948 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3950 ppc_load (code, ppc_r11, spvar->inst_offset);
3951 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3953 ppc_mtlr (code, ppc_r0);
3957 case OP_ENDFINALLY: {
3958 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3959 g_assert (spvar->inst_basereg != ppc_sp);
3960 code = emit_unreserve_param_area (cfg, code);
3961 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3962 ppc_mtlr (code, ppc_r0);
3966 case OP_CALL_HANDLER:
3967 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3969 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3972 ins->inst_c0 = code - cfg->native_code;
3975 /*if (ins->inst_target_bb->native_offset) {
3977 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3979 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3984 ppc_mtctr (code, ins->sreg1);
3985 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3989 CASE_PPC64 (OP_LCEQ)
3990 ppc_li (code, ins->dreg, 0);
3991 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3992 ppc_li (code, ins->dreg, 1);
3998 CASE_PPC64 (OP_LCLT)
3999 CASE_PPC64 (OP_LCLT_UN)
4000 ppc_li (code, ins->dreg, 1);
4001 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4002 ppc_li (code, ins->dreg, 0);
4008 CASE_PPC64 (OP_LCGT)
4009 CASE_PPC64 (OP_LCGT_UN)
4010 ppc_li (code, ins->dreg, 1);
4011 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4012 ppc_li (code, ins->dreg, 0);
4014 case OP_COND_EXC_EQ:
4015 case OP_COND_EXC_NE_UN:
4016 case OP_COND_EXC_LT:
4017 case OP_COND_EXC_LT_UN:
4018 case OP_COND_EXC_GT:
4019 case OP_COND_EXC_GT_UN:
4020 case OP_COND_EXC_GE:
4021 case OP_COND_EXC_GE_UN:
4022 case OP_COND_EXC_LE:
4023 case OP_COND_EXC_LE_UN:
4024 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4026 case OP_COND_EXC_IEQ:
4027 case OP_COND_EXC_INE_UN:
4028 case OP_COND_EXC_ILT:
4029 case OP_COND_EXC_ILT_UN:
4030 case OP_COND_EXC_IGT:
4031 case OP_COND_EXC_IGT_UN:
4032 case OP_COND_EXC_IGE:
4033 case OP_COND_EXC_IGE_UN:
4034 case OP_COND_EXC_ILE:
4035 case OP_COND_EXC_ILE_UN:
4036 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4048 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4051 /* floating point opcodes */
4053 g_assert (cfg->compile_aot);
4055 /* FIXME: Optimize this */
4057 ppc_mflr (code, ppc_r11);
4059 *(double*)code = *(double*)ins->inst_p0;
4061 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4064 g_assert_not_reached ();
4066 case OP_STORER8_MEMBASE_REG:
4067 if (ppc_is_imm16 (ins->inst_offset)) {
4068 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4070 if (ppc_is_imm32 (ins->inst_offset)) {
4071 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4072 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4074 ppc_load (code, ppc_r0, ins->inst_offset);
4075 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4079 case OP_LOADR8_MEMBASE:
4080 if (ppc_is_imm16 (ins->inst_offset)) {
4081 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4083 if (ppc_is_imm32 (ins->inst_offset)) {
4084 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4085 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4087 ppc_load (code, ppc_r0, ins->inst_offset);
4088 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4092 case OP_STORER4_MEMBASE_REG:
4093 ppc_frsp (code, ins->sreg1, ins->sreg1);
4094 if (ppc_is_imm16 (ins->inst_offset)) {
4095 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4097 if (ppc_is_imm32 (ins->inst_offset)) {
4098 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4099 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4101 ppc_load (code, ppc_r0, ins->inst_offset);
4102 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4106 case OP_LOADR4_MEMBASE:
4107 if (ppc_is_imm16 (ins->inst_offset)) {
4108 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4110 if (ppc_is_imm32 (ins->inst_offset)) {
4111 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4112 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4114 ppc_load (code, ppc_r0, ins->inst_offset);
4115 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4119 case OP_LOADR4_MEMINDEX:
4120 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4122 case OP_LOADR8_MEMINDEX:
4123 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4125 case OP_STORER4_MEMINDEX:
4126 ppc_frsp (code, ins->sreg1, ins->sreg1);
4127 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4129 case OP_STORER8_MEMINDEX:
4130 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4133 case CEE_CONV_R4: /* FIXME: change precision */
4135 g_assert_not_reached ();
4136 case OP_FCONV_TO_I1:
4137 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4139 case OP_FCONV_TO_U1:
4140 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4142 case OP_FCONV_TO_I2:
4143 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4145 case OP_FCONV_TO_U2:
4146 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4148 case OP_FCONV_TO_I4:
4150 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4152 case OP_FCONV_TO_U4:
4154 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4156 case OP_LCONV_TO_R_UN:
4157 g_assert_not_reached ();
4158 /* Implemented as helper calls */
4160 case OP_LCONV_TO_OVF_I4_2:
4161 case OP_LCONV_TO_OVF_I: {
4162 #ifdef __mono_ppc64__
4165 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4166 // Check if its negative
4167 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4168 negative_branch = code;
4169 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4170 // Its positive msword == 0
4171 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4172 msword_positive_branch = code;
4173 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4175 ovf_ex_target = code;
4176 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4178 ppc_patch (negative_branch, code);
4179 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4180 msword_negative_branch = code;
4181 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4182 ppc_patch (msword_negative_branch, ovf_ex_target);
4184 ppc_patch (msword_positive_branch, code);
4185 if (ins->dreg != ins->sreg1)
4186 ppc_mr (code, ins->dreg, ins->sreg1);
4191 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4194 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4197 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4200 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4203 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4206 ppc_fneg (code, ins->dreg, ins->sreg1);
4210 g_assert_not_reached ();
4213 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4216 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4217 ppc_li (code, ins->dreg, 0);
4218 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4219 ppc_li (code, ins->dreg, 1);
4222 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4223 ppc_li (code, ins->dreg, 1);
4224 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4225 ppc_li (code, ins->dreg, 0);
4228 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4229 ppc_li (code, ins->dreg, 1);
4230 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4231 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4232 ppc_li (code, ins->dreg, 0);
4235 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4236 ppc_li (code, ins->dreg, 1);
4237 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4238 ppc_li (code, ins->dreg, 0);
4241 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4242 ppc_li (code, ins->dreg, 1);
4243 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4244 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4245 ppc_li (code, ins->dreg, 0);
4248 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4251 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4254 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4255 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4258 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4259 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4262 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4263 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4266 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4267 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4270 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4271 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4274 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4277 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4278 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4281 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4284 g_assert_not_reached ();
4285 case OP_CHECK_FINITE: {
4286 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4287 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4288 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4289 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4292 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4293 #ifdef __mono_ppc64__
4294 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4296 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4301 #ifdef __mono_ppc64__
4302 case OP_ICONV_TO_I4:
4304 ppc_extsw (code, ins->dreg, ins->sreg1);
4306 case OP_ICONV_TO_U4:
4308 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4310 case OP_ICONV_TO_R4:
4311 case OP_ICONV_TO_R8:
4312 case OP_LCONV_TO_R4:
4313 case OP_LCONV_TO_R8: {
4315 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4316 ppc_extsw (code, ppc_r0, ins->sreg1);
4321 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4322 ppc_mffgpr (code, ins->dreg, tmp);
4324 ppc_str (code, tmp, -8, ppc_r1);
4325 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4327 ppc_fcfid (code, ins->dreg, ins->dreg);
4328 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4329 ppc_frsp (code, ins->dreg, ins->dreg);
4333 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4336 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4339 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4341 ppc_mfspr (code, ppc_r0, ppc_xer);
4342 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4343 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4345 case OP_COND_EXC_OV:
4346 ppc_mfspr (code, ppc_r0, ppc_xer);
4347 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4348 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4360 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4362 case OP_FCONV_TO_I8:
4363 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4365 case OP_FCONV_TO_U8:
4366 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4368 case OP_STOREI4_MEMBASE_REG:
4369 if (ppc_is_imm16 (ins->inst_offset)) {
4370 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4372 ppc_load (code, ppc_r0, ins->inst_offset);
4373 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4376 case OP_STOREI4_MEMINDEX:
4377 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4380 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4382 case OP_ISHR_UN_IMM:
4383 if (ins->inst_imm & 0x1f)
4384 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4386 ppc_mr (code, ins->dreg, ins->sreg1);
4388 case OP_ATOMIC_ADD_NEW_I4:
4389 case OP_ATOMIC_ADD_NEW_I8: {
4390 guint8 *loop = code, *branch;
4391 g_assert (ins->inst_offset == 0);
4392 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4393 ppc_lwarx (code, ppc_r0, 0, ins->inst_basereg);
4395 ppc_ldarx (code, ppc_r0, 0, ins->inst_basereg);
4396 ppc_add (code, ppc_r0, ppc_r0, ins->sreg2);
4397 if (ins->opcode == OP_ATOMIC_ADD_NEW_I4)
4398 ppc_stwcxd (code, ppc_r0, 0, ins->inst_basereg);
4400 ppc_stdcxd (code, ppc_r0, 0, ins->inst_basereg);
4402 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4403 ppc_patch (branch, loop);
4404 ppc_mr (code, ins->dreg, ppc_r0);
4408 case OP_ICONV_TO_R4:
4409 case OP_ICONV_TO_R8: {
4410 if (cpu_hw_caps & PPC_ISA_64) {
4411 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4412 ppc_stw (code, ppc_r0, -8, ppc_r1);
4413 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4414 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4415 ppc_fcfid (code, ins->dreg, ins->dreg);
4416 if (ins->opcode == OP_ICONV_TO_R4)
4417 ppc_frsp (code, ins->dreg, ins->dreg);
4422 case OP_ATOMIC_CAS_I4:
4423 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4424 int location = ins->sreg1;
4425 int value = ins->sreg2;
4426 int comparand = ins->sreg3;
4427 guint8 *start, *not_equal, *lost_reservation;
4430 if (ins->opcode == OP_ATOMIC_CAS_I4)
4431 ppc_lwarx (code, ppc_r0, 0, location);
4432 #ifdef __mono_ppc64__
4434 ppc_ldarx (code, ppc_r0, 0, location);
4436 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4439 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4440 if (ins->opcode == OP_ATOMIC_CAS_I4)
4441 ppc_stwcxd (code, value, 0, location);
4442 #ifdef __mono_ppc64__
4444 ppc_stdcxd (code, value, 0, location);
4447 lost_reservation = code;
4448 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4449 ppc_patch (lost_reservation, start);
4451 ppc_patch (not_equal, code);
4452 ppc_mr (code, ins->dreg, ppc_r0);
4457 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4458 g_assert_not_reached ();
4461 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4462 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4463 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4464 g_assert_not_reached ();
4470 last_offset = offset;
4473 cfg->code_len = code - cfg->native_code;
4475 #endif /* !DISABLE_JIT */
4478 mono_arch_register_lowlevel_calls (void)
4480 /* The signature doesn't matter */
4481 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4484 #ifdef __mono_ppc64__
4485 #define patch_load_sequence(ip,val) do {\
4486 guint16 *__load = (guint16*)(ip); \
4487 g_assert (sizeof (val) == sizeof (gsize)); \
4488 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4489 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4490 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4491 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4494 #define patch_load_sequence(ip,val) do {\
4495 guint16 *__lis_ori = (guint16*)(ip); \
4496 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4497 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4503 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4505 MonoJumpInfo *patch_info;
4506 gboolean compile_aot = !run_cctors;
4508 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4509 unsigned char *ip = patch_info->ip.i + code;
4510 unsigned char *target;
4511 gboolean is_fd = FALSE;
4513 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4516 switch (patch_info->type) {
4517 case MONO_PATCH_INFO_BB:
4518 case MONO_PATCH_INFO_LABEL:
4521 /* No need to patch these */
4526 switch (patch_info->type) {
4527 case MONO_PATCH_INFO_IP:
4528 patch_load_sequence (ip, ip);
4530 case MONO_PATCH_INFO_METHOD_REL:
4531 g_assert_not_reached ();
4532 *((gpointer *)(ip)) = code + patch_info->data.offset;
4534 case MONO_PATCH_INFO_SWITCH: {
4535 gpointer *table = (gpointer *)patch_info->data.table->table;
4538 patch_load_sequence (ip, table);
4540 for (i = 0; i < patch_info->data.table->table_size; i++) {
4541 table [i] = (glong)patch_info->data.table->table [i] + code;
4543 /* we put into the table the absolute address, no need for ppc_patch in this case */
4546 case MONO_PATCH_INFO_METHODCONST:
4547 case MONO_PATCH_INFO_CLASS:
4548 case MONO_PATCH_INFO_IMAGE:
4549 case MONO_PATCH_INFO_FIELD:
4550 case MONO_PATCH_INFO_VTABLE:
4551 case MONO_PATCH_INFO_IID:
4552 case MONO_PATCH_INFO_SFLDA:
4553 case MONO_PATCH_INFO_LDSTR:
4554 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4555 case MONO_PATCH_INFO_LDTOKEN:
4556 /* from OP_AOTCONST : lis + ori */
4557 patch_load_sequence (ip, target);
4559 case MONO_PATCH_INFO_R4:
4560 case MONO_PATCH_INFO_R8:
4561 g_assert_not_reached ();
4562 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4564 case MONO_PATCH_INFO_EXC_NAME:
4565 g_assert_not_reached ();
4566 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4568 case MONO_PATCH_INFO_NONE:
4569 case MONO_PATCH_INFO_BB_OVF:
4570 case MONO_PATCH_INFO_EXC_OVF:
4571 /* everything is dealt with at epilog output time */
4573 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4574 case MONO_PATCH_INFO_INTERNAL_METHOD:
4575 case MONO_PATCH_INFO_ABS:
4576 case MONO_PATCH_INFO_CLASS_INIT:
4577 case MONO_PATCH_INFO_RGCTX_FETCH:
4584 ppc_patch_full (ip, target, is_fd);
4589 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4590 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4591 * the instruction offset immediate for all the registers.
4594 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4598 for (i = 13; i <= 31; i++) {
4599 if (used_int_regs & (1 << i)) {
4600 ppc_str (code, i, pos, base_reg);
4601 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4602 pos += sizeof (mgreg_t);
4606 /* pos is the start of the MonoLMF structure */
4607 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4608 for (i = 13; i <= 31; i++) {
4609 ppc_str (code, i, offset, base_reg);
4610 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4611 offset += sizeof (mgreg_t);
4613 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4614 for (i = 14; i < 32; i++) {
4615 ppc_stfd (code, i, offset, base_reg);
4616 offset += sizeof (gdouble);
4623 * Stack frame layout:
4625 * ------------------- sp
4626 * MonoLMF structure or saved registers
4627 * -------------------
4629 * -------------------
4631 * -------------------
4632 * optional 8 bytes for tracing
4633 * -------------------
4634 * param area size is cfg->param_area
4635 * -------------------
4636 * linkage area size is PPC_STACK_PARAM_OFFSET
4637 * ------------------- sp
4641 mono_arch_emit_prolog (MonoCompile *cfg)
4643 MonoMethod *method = cfg->method;
4645 MonoMethodSignature *sig;
4647 long alloc_size, pos, max_offset, cfa_offset;
4653 int tailcall_struct_index;
4655 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4658 sig = mono_method_signature (method);
4659 cfg->code_size = 512 + sig->param_count * 32;
4660 code = cfg->native_code = g_malloc (cfg->code_size);
4664 /* We currently emit unwind info for aot, but don't use it */
4665 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4667 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4668 ppc_mflr (code, ppc_r0);
4669 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4670 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4673 alloc_size = cfg->stack_offset;
4676 if (!method->save_lmf) {
4677 for (i = 31; i >= 13; --i) {
4678 if (cfg->used_int_regs & (1 << i)) {
4679 pos += sizeof (mgreg_t);
4683 pos += sizeof (MonoLMF);
4687 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4688 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4689 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4690 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4693 cfg->stack_usage = alloc_size;
4694 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4696 if (ppc_is_imm16 (-alloc_size)) {
4697 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4698 cfa_offset = alloc_size;
4699 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4700 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4703 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4704 ppc_load (code, ppc_r0, -alloc_size);
4705 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4706 cfa_offset = alloc_size;
4707 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4708 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4711 if (cfg->frame_reg != ppc_sp) {
4712 ppc_mr (code, cfg->frame_reg, ppc_sp);
4713 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4716 /* store runtime generic context */
4717 if (cfg->rgctx_var) {
4718 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4719 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4721 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4724 /* compute max_offset in order to use short forward jumps
4725 * we always do it on ppc because the immediate displacement
4726 * for jumps is too small
4729 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4731 bb->max_offset = max_offset;
4733 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4736 MONO_BB_FOR_EACH_INS (bb, ins)
4737 max_offset += ins_native_length (cfg, ins);
4740 /* load arguments allocated to register from the stack */
4743 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4745 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4746 ArgInfo *ainfo = &cinfo->ret;
4748 inst = cfg->vret_addr;
4751 if (ppc_is_imm16 (inst->inst_offset)) {
4752 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4754 ppc_load (code, ppc_r11, inst->inst_offset);
4755 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4759 tailcall_struct_index = 0;
4760 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4761 ArgInfo *ainfo = cinfo->args + i;
4762 inst = cfg->args [pos];
4764 if (cfg->verbose_level > 2)
4765 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4766 if (inst->opcode == OP_REGVAR) {
4767 if (ainfo->regtype == RegTypeGeneral)
4768 ppc_mr (code, inst->dreg, ainfo->reg);
4769 else if (ainfo->regtype == RegTypeFP)
4770 ppc_fmr (code, inst->dreg, ainfo->reg);
4771 else if (ainfo->regtype == RegTypeBase) {
4772 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4773 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4775 g_assert_not_reached ();
4777 if (cfg->verbose_level > 2)
4778 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4780 /* the argument should be put on the stack: FIXME handle size != word */
4781 if (ainfo->regtype == RegTypeGeneral) {
4782 switch (ainfo->size) {
4784 if (ppc_is_imm16 (inst->inst_offset)) {
4785 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4787 if (ppc_is_imm32 (inst->inst_offset)) {
4788 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4789 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4791 ppc_load (code, ppc_r11, inst->inst_offset);
4792 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4797 if (ppc_is_imm16 (inst->inst_offset)) {
4798 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4800 if (ppc_is_imm32 (inst->inst_offset)) {
4801 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4802 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4804 ppc_load (code, ppc_r11, inst->inst_offset);
4805 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4809 #ifdef __mono_ppc64__
4811 if (ppc_is_imm16 (inst->inst_offset)) {
4812 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4814 if (ppc_is_imm32 (inst->inst_offset)) {
4815 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4816 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4818 ppc_load (code, ppc_r11, inst->inst_offset);
4819 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4824 if (ppc_is_imm16 (inst->inst_offset)) {
4825 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4827 ppc_load (code, ppc_r11, inst->inst_offset);
4828 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4833 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4834 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4835 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4837 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4838 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4839 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4840 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4845 if (ppc_is_imm16 (inst->inst_offset)) {
4846 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4848 if (ppc_is_imm32 (inst->inst_offset)) {
4849 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4850 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4852 ppc_load (code, ppc_r11, inst->inst_offset);
4853 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4858 } else if (ainfo->regtype == RegTypeBase) {
4859 g_assert (ppc_is_imm16 (ainfo->offset));
4860 /* load the previous stack pointer in r11 */
4861 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4862 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4863 switch (ainfo->size) {
4865 if (ppc_is_imm16 (inst->inst_offset)) {
4866 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4868 if (ppc_is_imm32 (inst->inst_offset)) {
4869 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4870 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4872 ppc_load (code, ppc_r11, inst->inst_offset);
4873 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4878 if (ppc_is_imm16 (inst->inst_offset)) {
4879 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4881 if (ppc_is_imm32 (inst->inst_offset)) {
4882 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4883 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4885 ppc_load (code, ppc_r11, inst->inst_offset);
4886 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4890 #ifdef __mono_ppc64__
4892 if (ppc_is_imm16 (inst->inst_offset)) {
4893 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4895 if (ppc_is_imm32 (inst->inst_offset)) {
4896 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4897 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4899 ppc_load (code, ppc_r11, inst->inst_offset);
4900 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4905 if (ppc_is_imm16 (inst->inst_offset)) {
4906 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4908 ppc_load (code, ppc_r11, inst->inst_offset);
4909 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4914 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4915 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4916 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4917 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4918 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4920 /* use r12 to load the 2nd half of the long before we clobber r11. */
4921 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4922 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4923 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4924 ppc_stw (code, ppc_r0, 0, ppc_r11);
4925 ppc_stw (code, ppc_r12, 4, ppc_r11);
4930 if (ppc_is_imm16 (inst->inst_offset)) {
4931 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4933 if (ppc_is_imm32 (inst->inst_offset)) {
4934 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4935 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4937 ppc_load (code, ppc_r11, inst->inst_offset);
4938 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4943 } else if (ainfo->regtype == RegTypeFP) {
4944 g_assert (ppc_is_imm16 (inst->inst_offset));
4945 if (ainfo->size == 8)
4946 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4947 else if (ainfo->size == 4)
4948 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4950 g_assert_not_reached ();
4951 } else if (ainfo->regtype == RegTypeStructByVal) {
4952 int doffset = inst->inst_offset;
4956 g_assert (ppc_is_imm16 (inst->inst_offset));
4957 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4958 /* FIXME: what if there is no class? */
4959 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4960 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4961 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4964 * Darwin handles 1 and 2 byte
4965 * structs specially by
4966 * loading h/b into the arg
4967 * register. Only done for
4971 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4973 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4977 #ifdef __mono_ppc64__
4979 g_assert (cur_reg == 0);
4980 ppc_sldi (code, ppc_r0, ainfo->reg,
4981 (sizeof (gpointer) - ainfo->bytes) * 8);
4982 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
4986 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
4987 inst->inst_basereg);
4990 soffset += sizeof (gpointer);
4991 doffset += sizeof (gpointer);
4993 if (ainfo->vtsize) {
4994 /* FIXME: we need to do the shifting here, too */
4997 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4998 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4999 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5000 code = emit_memcpy (code, size - soffset,
5001 inst->inst_basereg, doffset,
5002 ppc_r11, ainfo->offset + soffset);
5004 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5005 inst->inst_basereg, doffset,
5006 ppc_r11, ainfo->offset + soffset);
5009 } else if (ainfo->regtype == RegTypeStructByAddr) {
5010 /* if it was originally a RegTypeBase */
5011 if (ainfo->offset) {
5012 /* load the previous stack pointer in r11 */
5013 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5014 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5016 ppc_mr (code, ppc_r11, ainfo->reg);
5019 if (cfg->tailcall_valuetype_addrs) {
5020 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5022 g_assert (ppc_is_imm16 (addr->inst_offset));
5023 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5025 tailcall_struct_index++;
5028 g_assert (ppc_is_imm16 (inst->inst_offset));
5029 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5030 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5032 g_assert_not_reached ();
5037 if (method->save_lmf) {
5038 if (lmf_pthread_key != -1) {
5039 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5040 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5041 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5043 if (cfg->compile_aot) {
5044 /* Compute the got address which is needed by the PLT entry */
5045 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5047 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5048 (gpointer)"mono_get_lmf_addr");
5049 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5050 ppc_load_func (code, ppc_r0, 0);
5051 ppc_mtlr (code, ppc_r0);
5057 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5058 /* lmf_offset is the offset from the previous stack pointer,
5059 * alloc_size is the total stack space allocated, so the offset
5060 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5061 * The pointer to the struct is put in ppc_r11 (new_lmf).
5062 * The callee-saved registers are already in the MonoLMF structure
5064 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5065 /* ppc_r3 is the result from mono_get_lmf_addr () */
5066 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5067 /* new_lmf->previous_lmf = *lmf_addr */
5068 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5069 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5070 /* *(lmf_addr) = r11 */
5071 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5072 /* save method info */
5073 if (cfg->compile_aot)
5075 ppc_load (code, ppc_r0, 0);
5077 ppc_load_ptr (code, ppc_r0, method);
5078 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5079 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5080 /* save the current IP */
5081 if (cfg->compile_aot) {
5083 ppc_mflr (code, ppc_r0);
5085 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5086 #ifdef __mono_ppc64__
5087 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5089 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5092 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5096 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5098 cfg->code_len = code - cfg->native_code;
5099 g_assert (cfg->code_len <= cfg->code_size);
5106 mono_arch_emit_epilog (MonoCompile *cfg)
5108 MonoMethod *method = cfg->method;
5110 int max_epilog_size = 16 + 20*4;
5113 if (cfg->method->save_lmf)
5114 max_epilog_size += 128;
5116 if (mono_jit_trace_calls != NULL)
5117 max_epilog_size += 50;
5119 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5120 max_epilog_size += 50;
5122 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5123 cfg->code_size *= 2;
5124 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5125 cfg->stat_code_reallocs++;
5129 * Keep in sync with OP_JMP
5131 code = cfg->native_code + cfg->code_len;
5133 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5134 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5138 if (method->save_lmf) {
5140 pos += sizeof (MonoLMF);
5142 /* save the frame reg in r8 */
5143 ppc_mr (code, ppc_r8, cfg->frame_reg);
5144 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5145 /* r5 = previous_lmf */
5146 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5148 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5149 /* *(lmf_addr) = previous_lmf */
5150 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5151 /* FIXME: speedup: there is no actual need to restore the registers if
5152 * we didn't actually change them (idea from Zoltan).
5155 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5157 /*for (i = 14; i < 32; i++) {
5158 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5160 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5161 /* use the saved copy of the frame reg in r8 */
5162 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5163 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5164 ppc_mtlr (code, ppc_r0);
5166 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5168 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5169 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5170 if (ppc_is_imm16 (return_offset)) {
5171 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5173 ppc_load (code, ppc_r11, return_offset);
5174 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5176 ppc_mtlr (code, ppc_r0);
5178 if (ppc_is_imm16 (cfg->stack_usage)) {
5179 int offset = cfg->stack_usage;
5180 for (i = 13; i <= 31; i++) {
5181 if (cfg->used_int_regs & (1 << i))
5182 offset -= sizeof (mgreg_t);
5184 if (cfg->frame_reg != ppc_sp)
5185 ppc_mr (code, ppc_r11, cfg->frame_reg);
5186 /* note r31 (possibly the frame register) is restored last */
5187 for (i = 13; i <= 31; i++) {
5188 if (cfg->used_int_regs & (1 << i)) {
5189 ppc_ldr (code, i, offset, cfg->frame_reg);
5190 offset += sizeof (mgreg_t);
5193 if (cfg->frame_reg != ppc_sp)
5194 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5196 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5198 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5199 if (cfg->used_int_regs) {
5200 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5201 for (i = 31; i >= 13; --i) {
5202 if (cfg->used_int_regs & (1 << i)) {
5203 pos += sizeof (mgreg_t);
5204 ppc_ldr (code, i, -pos, ppc_r11);
5207 ppc_mr (code, ppc_sp, ppc_r11);
5209 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5216 cfg->code_len = code - cfg->native_code;
5218 g_assert (cfg->code_len < cfg->code_size);
5221 #endif /* ifndef DISABLE_JIT */
5223 /* remove once throw_exception_by_name is eliminated */
5225 exception_id_by_name (const char *name)
5227 if (strcmp (name, "IndexOutOfRangeException") == 0)
5228 return MONO_EXC_INDEX_OUT_OF_RANGE;
5229 if (strcmp (name, "OverflowException") == 0)
5230 return MONO_EXC_OVERFLOW;
5231 if (strcmp (name, "ArithmeticException") == 0)
5232 return MONO_EXC_ARITHMETIC;
5233 if (strcmp (name, "DivideByZeroException") == 0)
5234 return MONO_EXC_DIVIDE_BY_ZERO;
5235 if (strcmp (name, "InvalidCastException") == 0)
5236 return MONO_EXC_INVALID_CAST;
5237 if (strcmp (name, "NullReferenceException") == 0)
5238 return MONO_EXC_NULL_REF;
5239 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5240 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5241 if (strcmp (name, "ArgumentException") == 0)
5242 return MONO_EXC_ARGUMENT;
5243 g_error ("Unknown intrinsic exception %s\n", name);
5249 mono_arch_emit_exceptions (MonoCompile *cfg)
5251 MonoJumpInfo *patch_info;
5254 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5255 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5256 int max_epilog_size = 50;
5258 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5259 exc_throw_pos [i] = NULL;
5260 exc_throw_found [i] = 0;
5263 /* count the number of exception infos */
5266 * make sure we have enough space for exceptions
5268 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5269 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5270 i = exception_id_by_name (patch_info->data.target);
5271 if (!exc_throw_found [i]) {
5272 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5273 exc_throw_found [i] = TRUE;
5275 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5276 max_epilog_size += 12;
5277 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5278 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5279 i = exception_id_by_name (ovfj->data.exception);
5280 if (!exc_throw_found [i]) {
5281 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5282 exc_throw_found [i] = TRUE;
5284 max_epilog_size += 8;
5288 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5289 cfg->code_size *= 2;
5290 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5291 cfg->stat_code_reallocs++;
5294 code = cfg->native_code + cfg->code_len;
5296 /* add code to raise exceptions */
5297 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5298 switch (patch_info->type) {
5299 case MONO_PATCH_INFO_BB_OVF: {
5300 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5301 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5302 /* patch the initial jump */
5303 ppc_patch (ip, code);
5304 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5306 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5307 /* jump back to the true target */
5309 ip = ovfj->data.bb->native_offset + cfg->native_code;
5310 ppc_patch (code - 4, ip);
5311 patch_info->type = MONO_PATCH_INFO_NONE;
5314 case MONO_PATCH_INFO_EXC_OVF: {
5315 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5316 MonoJumpInfo *newji;
5317 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5318 unsigned char *bcl = code;
5319 /* patch the initial jump: we arrived here with a call */
5320 ppc_patch (ip, code);
5321 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5323 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5324 /* patch the conditional jump to the right handler */
5325 /* make it processed next */
5326 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5327 newji->type = MONO_PATCH_INFO_EXC;
5328 newji->ip.i = bcl - cfg->native_code;
5329 newji->data.target = ovfj->data.exception;
5330 newji->next = patch_info->next;
5331 patch_info->next = newji;
5332 patch_info->type = MONO_PATCH_INFO_NONE;
5335 case MONO_PATCH_INFO_EXC: {
5336 MonoClass *exc_class;
5338 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5339 i = exception_id_by_name (patch_info->data.target);
5340 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5341 ppc_patch (ip, exc_throw_pos [i]);
5342 patch_info->type = MONO_PATCH_INFO_NONE;
5345 exc_throw_pos [i] = code;
5348 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5349 g_assert (exc_class);
5351 ppc_patch (ip, code);
5352 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5353 ppc_load (code, ppc_r3, exc_class->type_token);
5354 /* we got here from a conditional call, so the calling ip is set in lr */
5355 ppc_mflr (code, ppc_r4);
5356 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5357 patch_info->data.name = "mono_arch_throw_corlib_exception";
5358 patch_info->ip.i = code - cfg->native_code;
5359 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5360 ppc_load_func (code, ppc_r0, 0);
5361 ppc_mtctr (code, ppc_r0);
5362 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5374 cfg->code_len = code - cfg->native_code;
5376 g_assert (cfg->code_len <= cfg->code_size);
5382 try_offset_access (void *value, guint32 idx)
5384 register void* me __asm__ ("r2");
5385 void ***p = (void***)((char*)me + 284);
5386 int idx1 = idx / 32;
5387 int idx2 = idx % 32;
5390 if (value != p[idx1][idx2])
5397 setup_tls_access (void)
5401 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5402 size_t conf_size = 0;
5405 /* FIXME for darwin */
5406 guint32 *ins, *code;
5407 guint32 cmplwi_1023, li_0x48, blr_ins;
5411 tls_mode = TLS_MODE_FAILED;
5414 if (tls_mode == TLS_MODE_FAILED)
5416 if (g_getenv ("MONO_NO_TLS")) {
5417 tls_mode = TLS_MODE_FAILED;
5421 if (tls_mode == TLS_MODE_DETECT) {
5422 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5423 tls_mode = TLS_MODE_DARWIN_G4;
5424 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5425 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5426 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5427 tls_mode = TLS_MODE_NPTL;
5428 #elif !defined(TARGET_PS3)
5429 ins = (guint32*)pthread_getspecific;
5430 /* uncond branch to the real method */
5431 if ((*ins >> 26) == 18) {
5433 val = (*ins & ~3) << 6;
5437 ins = (guint32*)(long)val;
5439 ins = (guint32*) ((char*)ins + val);
5442 code = &cmplwi_1023;
5443 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5445 ppc_li (code, ppc_r4, 0x48);
5448 if (*ins == cmplwi_1023) {
5449 int found_lwz_284 = 0;
5450 for (ptk = 0; ptk < 20; ++ptk) {
5452 if (!*ins || *ins == blr_ins)
5454 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5459 if (!found_lwz_284) {
5460 tls_mode = TLS_MODE_FAILED;
5463 tls_mode = TLS_MODE_LTHREADS;
5464 } else if (*ins == li_0x48) {
5466 /* uncond branch to the real method */
5467 if ((*ins >> 26) == 18) {
5469 val = (*ins & ~3) << 6;
5473 ins = (guint32*)(long)val;
5475 ins = (guint32*) ((char*)ins + val);
5477 code = (guint32*)&val;
5478 ppc_li (code, ppc_r0, 0x7FF2);
5479 if (ins [1] == val) {
5480 /* Darwin on G4, implement */
5481 tls_mode = TLS_MODE_FAILED;
5484 code = (guint32*)&val;
5485 ppc_mfspr (code, ppc_r3, 104);
5486 if (ins [1] != val) {
5487 tls_mode = TLS_MODE_FAILED;
5490 tls_mode = TLS_MODE_DARWIN_G5;
5493 tls_mode = TLS_MODE_FAILED;
5497 tls_mode = TLS_MODE_FAILED;
5503 if (tls_mode == TLS_MODE_DETECT)
5504 tls_mode = TLS_MODE_FAILED;
5505 if (tls_mode == TLS_MODE_FAILED)
5507 if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5508 monodomain_key = mono_domain_get_tls_offset();
5510 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5511 mono_domain_get_tls_offset returning -1) then use keyed access. */
5512 if (monodomain_key == -1) {
5513 ptk = mono_domain_get_tls_key ();
5515 monodomain_key = ptk;
5518 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5519 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5523 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5524 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5525 if (lmf_pthread_key == -1) {
5526 ptk = mono_jit_tls_id;
5528 /*g_print ("MonoLMF at: %d\n", ptk);*/
5529 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5530 init_tls_failed = 1;
5533 lmf_pthread_key = ptk;
5542 mono_arch_finish_init (void)
5544 setup_tls_access ();
5548 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5552 #ifdef MONO_ARCH_HAVE_IMT
5554 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5556 #define LOADSTORE_SIZE 4
5557 #define JUMP_IMM_SIZE 12
5558 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5559 #define ENABLE_WRONG_METHOD_CHECK 0
5562 * LOCKING: called with the domain lock held
5565 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5566 gpointer fail_tramp)
5570 guint8 *code, *start;
5572 for (i = 0; i < count; ++i) {
5573 MonoIMTCheckItem *item = imt_entries [i];
5574 if (item->is_equals) {
5575 if (item->check_target_idx) {
5576 if (!item->compare_done)
5577 item->chunk_size += CMP_SIZE;
5578 if (item->has_target_code)
5579 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5581 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5584 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5585 if (!item->has_target_code)
5586 item->chunk_size += LOADSTORE_SIZE;
5588 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5589 #if ENABLE_WRONG_METHOD_CHECK
5590 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5595 item->chunk_size += CMP_SIZE + BR_SIZE;
5596 imt_entries [item->check_target_idx]->compare_done = TRUE;
5598 size += item->chunk_size;
5600 /* the initial load of the vtable address */
5601 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5603 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5605 code = mono_domain_code_reserve (domain, size);
5610 * We need to save and restore r11 because it might be
5611 * used by the caller as the vtable register, so
5612 * clobbering it will trip up the magic trampoline.
5614 * FIXME: Get rid of this by making sure that r11 is
5615 * not used as the vtable register in interface calls.
5617 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5618 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5620 for (i = 0; i < count; ++i) {
5621 MonoIMTCheckItem *item = imt_entries [i];
5622 item->code_target = code;
5623 if (item->is_equals) {
5624 if (item->check_target_idx) {
5625 if (!item->compare_done) {
5626 ppc_load (code, ppc_r0, (gsize)item->key);
5627 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5629 item->jmp_code = code;
5630 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5631 if (item->has_target_code) {
5632 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5634 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5635 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5637 ppc_mtctr (code, ppc_r0);
5638 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5641 ppc_load (code, ppc_r0, (gulong)item->key);
5642 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5643 item->jmp_code = code;
5644 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5645 if (item->has_target_code) {
5646 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5649 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5650 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5652 ppc_mtctr (code, ppc_r0);
5653 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5654 ppc_patch (item->jmp_code, code);
5655 ppc_load_ptr (code, ppc_r0, fail_tramp);
5656 ppc_mtctr (code, ppc_r0);
5657 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5658 item->jmp_code = NULL;
5660 /* enable the commented code to assert on wrong method */
5661 #if ENABLE_WRONG_METHOD_CHECK
5662 ppc_load (code, ppc_r0, (guint32)item->key);
5663 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5664 item->jmp_code = code;
5665 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5667 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5668 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5669 ppc_mtctr (code, ppc_r0);
5670 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5671 #if ENABLE_WRONG_METHOD_CHECK
5672 ppc_patch (item->jmp_code, code);
5674 item->jmp_code = NULL;
5679 ppc_load (code, ppc_r0, (gulong)item->key);
5680 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5681 item->jmp_code = code;
5682 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5685 /* patch the branches to get to the target items */
5686 for (i = 0; i < count; ++i) {
5687 MonoIMTCheckItem *item = imt_entries [i];
5688 if (item->jmp_code) {
5689 if (item->check_target_idx) {
5690 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5696 mono_stats.imt_thunks_size += code - start;
5697 g_assert (code - start <= size);
5698 mono_arch_flush_icache (start, size);
5703 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5705 mgreg_t *r = (mgreg_t*)regs;
5707 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5712 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5714 mgreg_t *r = (mgreg_t*)regs;
5716 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5720 mono_arch_get_cie_program (void)
5724 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5730 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5737 mono_arch_print_tree (MonoInst *tree, int arity)
5742 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5746 setup_tls_access ();
5747 if (monodomain_key == -1)
5750 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5751 ins->inst_offset = monodomain_key;
5756 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5759 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5761 g_assert (reg >= ppc_r13);
5763 return ctx->regs [reg - ppc_r13];
5767 mono_arch_get_patch_offset (guint8 *code)
5773 * mono_aot_emit_load_got_addr:
5775 * Emit code to load the got address.
5776 * On PPC, the result is placed into r30.
5779 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5782 ppc_mflr (code, ppc_r30);
5784 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5786 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5787 /* arch_emit_got_address () patches this */
5788 #if defined(TARGET_POWERPC64)
5794 ppc_load32 (code, ppc_r0, 0);
5795 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5802 * mono_ppc_emit_load_aotconst:
5804 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5805 * TARGET from the mscorlib GOT in full-aot code.
5806 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5810 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5812 /* Load the mscorlib got address */
5813 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5814 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5815 /* arch_emit_got_access () patches this */
5816 ppc_load32 (code, ppc_r0, 0);
5817 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5822 /* Soft Debug support */
5823 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5830 * mono_arch_set_breakpoint:
5832 * See mini-amd64.c for docs.
5835 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5838 guint8 *orig_code = code;
5840 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5841 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5843 g_assert (code - orig_code == BREAKPOINT_SIZE);
5845 mono_arch_flush_icache (orig_code, code - orig_code);
5849 * mono_arch_clear_breakpoint:
5851 * See mini-amd64.c for docs.
5854 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5859 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5862 mono_arch_flush_icache (ip, code - ip);
5866 * mono_arch_is_breakpoint_event:
5868 * See mini-amd64.c for docs.
5871 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5873 siginfo_t* sinfo = (siginfo_t*) info;
5874 /* Sometimes the address is off by 4 */
5875 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5882 * mono_arch_skip_breakpoint:
5884 * See mini-amd64.c for docs.
5887 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5889 /* skip the ldptr */
5890 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5898 * mono_arch_start_single_stepping:
5900 * See mini-amd64.c for docs.
5903 mono_arch_start_single_stepping (void)
5905 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5909 * mono_arch_stop_single_stepping:
5911 * See mini-amd64.c for docs.
5914 mono_arch_stop_single_stepping (void)
5916 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5920 * mono_arch_is_single_step_event:
5922 * See mini-amd64.c for docs.
5925 mono_arch_is_single_step_event (void *info, void *sigctx)
5927 siginfo_t* sinfo = (siginfo_t*) info;
5928 /* Sometimes the address is off by 4 */
5929 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5936 * mono_arch_skip_single_step:
5938 * See mini-amd64.c for docs.
5941 mono_arch_skip_single_step (MonoContext *ctx)
5943 /* skip the ldptr */
5944 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5948 * mono_arch_create_seq_point_info:
5950 * See mini-amd64.c for docs.
5953 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)