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/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/debug-helpers.h>
18 #include <mono/utils/mono-proclib.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-ppc.h>
23 #ifdef TARGET_POWERPC64
24 #include "cpu-ppc64.h"
31 #include <sys/sysctl.h>
37 #define FORCE_INDIR_CALL 1
48 /* cpu_hw_caps contains the flags defined below */
49 static int cpu_hw_caps = 0;
50 static int cachelinesize = 0;
51 static int cachelineinc = 0;
53 PPC_ICACHE_SNOOP = 1 << 0,
54 PPC_MULTIPLE_LS_UNITS = 1 << 1,
55 PPC_SMP_CAPABLE = 1 << 2,
58 PPC_MOVE_FPR_GPR = 1 << 5,
62 #define BREAKPOINT_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
64 /* This mutex protects architecture specific caches */
65 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
66 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
67 static mono_mutex_t mini_arch_mutex;
69 int mono_exc_esp_offset = 0;
70 static int tls_mode = TLS_MODE_DETECT;
71 static int lmf_pthread_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, MONO_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, MONO_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, MONO_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 mono_mutex_init_recursive (&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 mono_mutex_destroy (&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_arch_tail_call_supported (MonoCompile *cfg, 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 CASE_PPC64 (OP_LREM_IMM) {
2434 NEW_INS (cfg, temp, OP_ICONST);
2435 temp->inst_c0 = ins->inst_imm;
2436 temp->dreg = mono_alloc_ireg (cfg);
2437 ins->sreg2 = temp->dreg;
2438 if (ins->opcode == OP_IDIV_IMM)
2439 ins->opcode = OP_IDIV;
2440 else if (ins->opcode == OP_IREM_IMM)
2441 ins->opcode = OP_IREM;
2442 else if (ins->opcode == OP_IDIV_UN_IMM)
2443 ins->opcode = OP_IDIV_UN;
2444 else if (ins->opcode == OP_IREM_UN_IMM)
2445 ins->opcode = OP_IREM_UN;
2446 else if (ins->opcode == OP_LREM_IMM)
2447 ins->opcode = OP_LREM;
2449 /* handle rem separately */
2454 CASE_PPC64 (OP_LREM)
2455 CASE_PPC64 (OP_LREM_UN) {
2457 /* we change a rem dest, src1, src2 to
2458 * div temp1, src1, src2
2459 * mul temp2, temp1, src2
2460 * sub dest, src1, temp2
2462 if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2463 NEW_INS (cfg, mul, OP_IMUL);
2464 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2465 ins->opcode = OP_ISUB;
2467 NEW_INS (cfg, mul, OP_LMUL);
2468 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2469 ins->opcode = OP_LSUB;
2471 temp->sreg1 = ins->sreg1;
2472 temp->sreg2 = ins->sreg2;
2473 temp->dreg = mono_alloc_ireg (cfg);
2474 mul->sreg1 = temp->dreg;
2475 mul->sreg2 = ins->sreg2;
2476 mul->dreg = mono_alloc_ireg (cfg);
2477 ins->sreg2 = mul->dreg;
2481 CASE_PPC64 (OP_LADD_IMM)
2484 if (!ppc_is_imm16 (ins->inst_imm)) {
2485 NEW_INS (cfg, temp, OP_ICONST);
2486 temp->inst_c0 = ins->inst_imm;
2487 temp->dreg = mono_alloc_ireg (cfg);
2488 ins->sreg2 = temp->dreg;
2489 ins->opcode = map_to_reg_reg_op (ins->opcode);
2493 CASE_PPC64 (OP_LSUB_IMM)
2495 if (!ppc_is_imm16 (-ins->inst_imm)) {
2496 NEW_INS (cfg, temp, OP_ICONST);
2497 temp->inst_c0 = ins->inst_imm;
2498 temp->dreg = mono_alloc_ireg (cfg);
2499 ins->sreg2 = temp->dreg;
2500 ins->opcode = map_to_reg_reg_op (ins->opcode);
2512 gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2513 #ifdef __mono_ppc64__
2514 if (ins->inst_imm & 0xffffffff00000000ULL)
2518 NEW_INS (cfg, temp, OP_ICONST);
2519 temp->inst_c0 = ins->inst_imm;
2520 temp->dreg = mono_alloc_ireg (cfg);
2521 ins->sreg2 = temp->dreg;
2522 ins->opcode = map_to_reg_reg_op (ins->opcode);
2531 NEW_INS (cfg, temp, OP_ICONST);
2532 temp->inst_c0 = ins->inst_imm;
2533 temp->dreg = mono_alloc_ireg (cfg);
2534 ins->sreg2 = temp->dreg;
2535 ins->opcode = map_to_reg_reg_op (ins->opcode);
2537 case OP_COMPARE_IMM:
2538 case OP_ICOMPARE_IMM:
2539 CASE_PPC64 (OP_LCOMPARE_IMM)
2541 /* Branch opts can eliminate the branch */
2542 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2543 ins->opcode = OP_NOP;
2547 if (compare_opcode_is_unsigned (next->opcode)) {
2548 if (!ppc_is_uimm16 (ins->inst_imm)) {
2549 NEW_INS (cfg, temp, OP_ICONST);
2550 temp->inst_c0 = ins->inst_imm;
2551 temp->dreg = mono_alloc_ireg (cfg);
2552 ins->sreg2 = temp->dreg;
2553 ins->opcode = map_to_reg_reg_op (ins->opcode);
2556 if (!ppc_is_imm16 (ins->inst_imm)) {
2557 NEW_INS (cfg, temp, OP_ICONST);
2558 temp->inst_c0 = ins->inst_imm;
2559 temp->dreg = mono_alloc_ireg (cfg);
2560 ins->sreg2 = temp->dreg;
2561 ins->opcode = map_to_reg_reg_op (ins->opcode);
2567 if (ins->inst_imm == 1) {
2568 ins->opcode = OP_MOVE;
2571 if (ins->inst_imm == 0) {
2572 ins->opcode = OP_ICONST;
2576 imm = mono_is_power_of_two (ins->inst_imm);
2578 ins->opcode = OP_SHL_IMM;
2579 ins->inst_imm = imm;
2582 if (!ppc_is_imm16 (ins->inst_imm)) {
2583 NEW_INS (cfg, temp, OP_ICONST);
2584 temp->inst_c0 = ins->inst_imm;
2585 temp->dreg = mono_alloc_ireg (cfg);
2586 ins->sreg2 = temp->dreg;
2587 ins->opcode = map_to_reg_reg_op (ins->opcode);
2590 case OP_LOCALLOC_IMM:
2591 NEW_INS (cfg, temp, OP_ICONST);
2592 temp->inst_c0 = ins->inst_imm;
2593 temp->dreg = mono_alloc_ireg (cfg);
2594 ins->sreg1 = temp->dreg;
2595 ins->opcode = OP_LOCALLOC;
2597 case OP_LOAD_MEMBASE:
2598 case OP_LOADI4_MEMBASE:
2599 CASE_PPC64 (OP_LOADI8_MEMBASE)
2600 case OP_LOADU4_MEMBASE:
2601 case OP_LOADI2_MEMBASE:
2602 case OP_LOADU2_MEMBASE:
2603 case OP_LOADI1_MEMBASE:
2604 case OP_LOADU1_MEMBASE:
2605 case OP_LOADR4_MEMBASE:
2606 case OP_LOADR8_MEMBASE:
2607 case OP_STORE_MEMBASE_REG:
2608 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2609 case OP_STOREI4_MEMBASE_REG:
2610 case OP_STOREI2_MEMBASE_REG:
2611 case OP_STOREI1_MEMBASE_REG:
2612 case OP_STORER4_MEMBASE_REG:
2613 case OP_STORER8_MEMBASE_REG:
2614 /* we can do two things: load the immed in a register
2615 * and use an indexed load, or see if the immed can be
2616 * represented as an ad_imm + a load with a smaller offset
2617 * that fits. We just do the first for now, optimize later.
2619 if (ppc_is_imm16 (ins->inst_offset))
2621 NEW_INS (cfg, temp, OP_ICONST);
2622 temp->inst_c0 = ins->inst_offset;
2623 temp->dreg = mono_alloc_ireg (cfg);
2624 ins->sreg2 = temp->dreg;
2625 ins->opcode = map_to_reg_reg_op (ins->opcode);
2627 case OP_STORE_MEMBASE_IMM:
2628 case OP_STOREI1_MEMBASE_IMM:
2629 case OP_STOREI2_MEMBASE_IMM:
2630 case OP_STOREI4_MEMBASE_IMM:
2631 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2632 NEW_INS (cfg, temp, OP_ICONST);
2633 temp->inst_c0 = ins->inst_imm;
2634 temp->dreg = mono_alloc_ireg (cfg);
2635 ins->sreg1 = temp->dreg;
2636 ins->opcode = map_to_reg_reg_op (ins->opcode);
2638 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2641 if (cfg->compile_aot) {
2642 /* Keep these in the aot case */
2645 NEW_INS (cfg, temp, OP_ICONST);
2646 temp->inst_c0 = (gulong)ins->inst_p0;
2647 temp->dreg = mono_alloc_ireg (cfg);
2648 ins->inst_basereg = temp->dreg;
2649 ins->inst_offset = 0;
2650 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2652 /* make it handle the possibly big ins->inst_offset
2653 * later optimize to use lis + load_membase
2659 bb->last_ins = last_ins;
2660 bb->max_vreg = cfg->next_vreg;
2664 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2666 long offset = cfg->arch.fp_conv_var_offset;
2668 /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2669 #ifdef __mono_ppc64__
2671 ppc_fctidz (code, ppc_f0, sreg);
2676 ppc_fctiwz (code, ppc_f0, sreg);
2679 if (ppc_is_imm16 (offset + sub_offset)) {
2680 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2682 ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2684 ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2686 ppc_load (code, dreg, offset);
2687 ppc_add (code, dreg, dreg, cfg->frame_reg);
2688 ppc_stfd (code, ppc_f0, 0, dreg);
2690 ppc_ldr (code, dreg, sub_offset, dreg);
2692 ppc_lwz (code, dreg, sub_offset, dreg);
2696 ppc_andid (code, dreg, dreg, 0xff);
2698 ppc_andid (code, dreg, dreg, 0xffff);
2699 #ifdef __mono_ppc64__
2701 ppc_clrldi (code, dreg, dreg, 32);
2705 ppc_extsb (code, dreg, dreg);
2707 ppc_extsh (code, dreg, dreg);
2708 #ifdef __mono_ppc64__
2710 ppc_extsw (code, dreg, dreg);
2718 const guchar *target;
2723 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2726 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2727 #ifdef __mono_ppc64__
2728 g_assert_not_reached ();
2730 PatchData *pdata = (PatchData*)user_data;
2731 guchar *code = data;
2732 guint32 *thunks = data;
2733 guint32 *endthunks = (guint32*)(code + bsize);
2737 int difflow, diffhigh;
2739 /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2740 difflow = (char*)pdata->code - (char*)thunks;
2741 diffhigh = (char*)pdata->code - (char*)endthunks;
2742 if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2745 templ = (guchar*)load;
2746 ppc_load_sequence (templ, ppc_r0, pdata->target);
2748 //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2749 if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2750 while (thunks < endthunks) {
2751 //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2752 if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2753 ppc_patch (pdata->code, (guchar*)thunks);
2756 static int num_thunks = 0;
2758 if ((num_thunks % 20) == 0)
2759 g_print ("num_thunks lookup: %d\n", num_thunks);
2762 } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2763 /* found a free slot instead: emit thunk */
2764 code = (guchar*)thunks;
2765 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2766 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2767 ppc_mtctr (code, ppc_r0);
2768 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2769 mono_arch_flush_icache ((guchar*)thunks, 16);
2771 ppc_patch (pdata->code, (guchar*)thunks);
2774 static int num_thunks = 0;
2776 if ((num_thunks % 20) == 0)
2777 g_print ("num_thunks: %d\n", num_thunks);
2781 /* skip 16 bytes, the size of the thunk */
2785 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2792 handle_thunk (int absolute, guchar *code, const guchar *target) {
2793 MonoDomain *domain = mono_domain_get ();
2797 pdata.target = target;
2798 pdata.absolute = absolute;
2801 mono_domain_lock (domain);
2802 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2805 /* this uses the first available slot */
2807 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2809 mono_domain_unlock (domain);
2811 if (pdata.found != 1)
2812 g_print ("thunk failed for %p from %p\n", target, code);
2813 g_assert (pdata.found == 1);
2817 patch_ins (guint8 *code, guint32 ins)
2819 *(guint32*)code = GUINT32_TO_BE (ins);
2820 mono_arch_flush_icache (code, 4);
2824 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2826 guint32 ins = GUINT32_FROM_BE (*(guint32*)code);
2827 guint32 prim = ins >> 26;
2830 //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2832 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2833 gint diff = target - code;
2836 if (diff <= 33554431){
2837 ins = (18 << 26) | (diff) | (ins & 1);
2838 patch_ins (code, ins);
2842 /* diff between 0 and -33554432 */
2843 if (diff >= -33554432){
2844 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2845 patch_ins (code, ins);
2850 if ((glong)target >= 0){
2851 if ((glong)target <= 33554431){
2852 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
2853 patch_ins (code, ins);
2857 if ((glong)target >= -33554432){
2858 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
2859 patch_ins (code, ins);
2864 handle_thunk (TRUE, code, target);
2867 g_assert_not_reached ();
2875 guint32 li = (gulong)target;
2876 ins = (ins & 0xffff0000) | (ins & 3);
2877 ovf = li & 0xffff0000;
2878 if (ovf != 0 && ovf != 0xffff0000)
2879 g_assert_not_reached ();
2882 // FIXME: assert the top bits of li are 0
2884 gint diff = target - code;
2885 ins = (ins & 0xffff0000) | (ins & 3);
2886 ovf = diff & 0xffff0000;
2887 if (ovf != 0 && ovf != 0xffff0000)
2888 g_assert_not_reached ();
2892 patch_ins (code, ins);
2896 if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2897 #ifdef __mono_ppc64__
2898 guint32 *seq = (guint32*)code;
2899 guint32 *branch_ins;
2901 /* the trampoline code will try to patch the blrl, blr, bcctr */
2902 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2904 if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
2909 if (ppc_is_load_op (seq [5]) || ppc_opcode (seq [5]) == 31) /* ld || lwz || mr */
2910 branch_ins = seq + 8;
2912 branch_ins = seq + 6;
2915 seq = (guint32*)code;
2916 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
2917 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
2919 if (ppc_is_load_op (seq [5])) {
2920 g_assert (ppc_is_load_op (seq [6]));
2923 guint8 *buf = (guint8*)&seq [5];
2924 ppc_mr (buf, ppc_r0, ppc_r11);
2929 target = mono_get_addr_from_ftnptr ((gpointer)target);
2932 /* FIXME: make this thread safe */
2933 /* FIXME: we're assuming we're using r11 here */
2934 ppc_load_ptr_sequence (code, ppc_r11, target);
2935 mono_arch_flush_icache ((guint8*)seq, 28);
2938 /* the trampoline code will try to patch the blrl, blr, bcctr */
2939 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2942 /* this is the lis/ori/mtlr/blrl sequence */
2943 seq = (guint32*)code;
2944 g_assert ((seq [0] >> 26) == 15);
2945 g_assert ((seq [1] >> 26) == 24);
2946 g_assert ((seq [2] >> 26) == 31);
2947 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2948 /* FIXME: make this thread safe */
2949 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2950 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2951 mono_arch_flush_icache (code - 8, 8);
2954 g_assert_not_reached ();
2956 // g_print ("patched with 0x%08x\n", ins);
2960 ppc_patch (guchar *code, const guchar *target)
2962 ppc_patch_full (code, target, FALSE);
2966 mono_ppc_patch (guchar *code, const guchar *target)
2968 ppc_patch (code, target);
2972 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2974 switch (ins->opcode) {
2977 case OP_FCALL_MEMBASE:
2978 if (ins->dreg != ppc_f1)
2979 ppc_fmr (code, ins->dreg, ppc_f1);
2987 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2989 return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2993 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
2995 long size = cfg->param_area;
2997 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2998 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3003 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3004 if (ppc_is_imm16 (-size)) {
3005 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3007 ppc_load (code, ppc_r11, -size);
3008 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3015 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3017 long size = cfg->param_area;
3019 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3020 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3025 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3026 if (ppc_is_imm16 (size)) {
3027 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3029 ppc_load (code, ppc_r11, size);
3030 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3036 #define MASK_SHIFT_IMM(i) ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3040 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3042 MonoInst *ins, *next;
3045 guint8 *code = cfg->native_code + cfg->code_len;
3046 MonoInst *last_ins = NULL;
3047 guint last_offset = 0;
3051 /* we don't align basic blocks of loops on ppc */
3053 if (cfg->verbose_level > 2)
3054 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3056 cpos = bb->max_offset;
3058 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3059 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3060 //g_assert (!mono_compile_aot);
3063 // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3064 /* this is not thread save, but good enough */
3065 /* fixme: howto handle overflows? */
3066 //x86_inc_mem (code, &cov->data [bb->dfn].count);
3069 MONO_BB_FOR_EACH_INS (bb, ins) {
3070 offset = code - cfg->native_code;
3072 max_len = ins_native_length (cfg, ins);
3074 if (offset > (cfg->code_size - max_len - 16)) {
3075 cfg->code_size *= 2;
3076 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3077 code = cfg->native_code + offset;
3079 // if (ins->cil_code)
3080 // g_print ("cil code\n");
3081 mono_debug_record_line_number (cfg, ins, offset);
3083 switch (normalize_opcode (ins->opcode)) {
3084 case OP_RELAXED_NOP:
3087 case OP_DUMMY_STORE:
3088 case OP_NOT_REACHED:
3091 case OP_SEQ_POINT: {
3094 if (cfg->compile_aot)
3098 * Read from the single stepping trigger page. This will cause a
3099 * SIGSEGV when single stepping is enabled.
3100 * We do this _before_ the breakpoint, so single stepping after
3101 * a breakpoint is hit will step to the next IL offset.
3103 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3104 ppc_load (code, ppc_r11, (gsize)ss_trigger_page);
3105 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
3108 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3111 * A placeholder for a possible breakpoint inserted by
3112 * mono_arch_set_breakpoint ().
3114 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3119 emit_tls_access (code, ins->dreg, ins->inst_offset);
3122 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3123 ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3124 ppc_mr (code, ppc_r4, ppc_r0);
3127 ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3128 ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3129 ppc_mr (code, ppc_r4, ppc_r0);
3131 case OP_MEMORY_BARRIER:
3134 case OP_STOREI1_MEMBASE_REG:
3135 if (ppc_is_imm16 (ins->inst_offset)) {
3136 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3138 if (ppc_is_imm32 (ins->inst_offset)) {
3139 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3140 ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r12);
3142 ppc_load (code, ppc_r0, ins->inst_offset);
3143 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3147 case OP_STOREI2_MEMBASE_REG:
3148 if (ppc_is_imm16 (ins->inst_offset)) {
3149 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3151 if (ppc_is_imm32 (ins->inst_offset)) {
3152 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3153 ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r12);
3155 ppc_load (code, ppc_r0, ins->inst_offset);
3156 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3160 case OP_STORE_MEMBASE_REG:
3161 if (ppc_is_imm16 (ins->inst_offset)) {
3162 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3164 if (ppc_is_imm32 (ins->inst_offset)) {
3165 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3166 ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r12);
3168 ppc_load (code, ppc_r0, ins->inst_offset);
3169 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3173 #ifdef __mono_ilp32__
3174 case OP_STOREI8_MEMBASE_REG:
3175 if (ppc_is_imm16 (ins->inst_offset)) {
3176 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3178 ppc_load (code, ppc_r0, ins->inst_offset);
3179 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3183 case OP_STOREI1_MEMINDEX:
3184 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3186 case OP_STOREI2_MEMINDEX:
3187 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3189 case OP_STORE_MEMINDEX:
3190 ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3193 g_assert_not_reached ();
3195 case OP_LOAD_MEMBASE:
3196 if (ppc_is_imm16 (ins->inst_offset)) {
3197 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3199 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3200 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3201 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3203 ppc_load (code, ppc_r0, ins->inst_offset);
3204 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3208 case OP_LOADI4_MEMBASE:
3209 #ifdef __mono_ppc64__
3210 if (ppc_is_imm16 (ins->inst_offset)) {
3211 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3213 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3214 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3215 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3217 ppc_load (code, ppc_r0, ins->inst_offset);
3218 ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3223 case OP_LOADU4_MEMBASE:
3224 if (ppc_is_imm16 (ins->inst_offset)) {
3225 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3227 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3228 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3229 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3231 ppc_load (code, ppc_r0, ins->inst_offset);
3232 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3236 case OP_LOADI1_MEMBASE:
3237 case OP_LOADU1_MEMBASE:
3238 if (ppc_is_imm16 (ins->inst_offset)) {
3239 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3241 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3242 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3243 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3245 ppc_load (code, ppc_r0, ins->inst_offset);
3246 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3249 if (ins->opcode == OP_LOADI1_MEMBASE)
3250 ppc_extsb (code, ins->dreg, ins->dreg);
3252 case OP_LOADU2_MEMBASE:
3253 if (ppc_is_imm16 (ins->inst_offset)) {
3254 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3256 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3257 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3258 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3260 ppc_load (code, ppc_r0, ins->inst_offset);
3261 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3265 case OP_LOADI2_MEMBASE:
3266 if (ppc_is_imm16 (ins->inst_offset)) {
3267 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3269 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3270 ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3271 ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3273 ppc_load (code, ppc_r0, ins->inst_offset);
3274 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3278 #ifdef __mono_ilp32__
3279 case OP_LOADI8_MEMBASE:
3280 if (ppc_is_imm16 (ins->inst_offset)) {
3281 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3283 ppc_load (code, ppc_r0, ins->inst_offset);
3284 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3288 case OP_LOAD_MEMINDEX:
3289 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3291 case OP_LOADI4_MEMINDEX:
3292 #ifdef __mono_ppc64__
3293 ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3296 case OP_LOADU4_MEMINDEX:
3297 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3299 case OP_LOADU2_MEMINDEX:
3300 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3302 case OP_LOADI2_MEMINDEX:
3303 ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3305 case OP_LOADU1_MEMINDEX:
3306 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3308 case OP_LOADI1_MEMINDEX:
3309 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3310 ppc_extsb (code, ins->dreg, ins->dreg);
3312 case OP_ICONV_TO_I1:
3313 CASE_PPC64 (OP_LCONV_TO_I1)
3314 ppc_extsb (code, ins->dreg, ins->sreg1);
3316 case OP_ICONV_TO_I2:
3317 CASE_PPC64 (OP_LCONV_TO_I2)
3318 ppc_extsh (code, ins->dreg, ins->sreg1);
3320 case OP_ICONV_TO_U1:
3321 CASE_PPC64 (OP_LCONV_TO_U1)
3322 ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3324 case OP_ICONV_TO_U2:
3325 CASE_PPC64 (OP_LCONV_TO_U2)
3326 ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3330 CASE_PPC64 (OP_LCOMPARE)
3331 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3333 if (next && compare_opcode_is_unsigned (next->opcode))
3334 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3336 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3338 case OP_COMPARE_IMM:
3339 case OP_ICOMPARE_IMM:
3340 CASE_PPC64 (OP_LCOMPARE_IMM)
3341 L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3343 if (next && compare_opcode_is_unsigned (next->opcode)) {
3344 if (ppc_is_uimm16 (ins->inst_imm)) {
3345 ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3347 g_assert_not_reached ();
3350 if (ppc_is_imm16 (ins->inst_imm)) {
3351 ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3353 g_assert_not_reached ();
3359 * gdb does not like encountering a trap in the debugged code. So
3360 * instead of emitting a trap, we emit a call a C function and place a
3364 ppc_mr (code, ppc_r3, ins->sreg1);
3365 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3366 (gpointer)"mono_break");
3367 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3368 ppc_load_func (code, ppc_r0, 0);
3369 ppc_mtlr (code, ppc_r0);
3377 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3380 CASE_PPC64 (OP_LADD)
3381 ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3385 ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3388 if (ppc_is_imm16 (ins->inst_imm)) {
3389 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3391 g_assert_not_reached ();
3396 CASE_PPC64 (OP_LADD_IMM)
3397 if (ppc_is_imm16 (ins->inst_imm)) {
3398 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3400 g_assert_not_reached ();
3404 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3406 ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3407 ppc_mfspr (code, ppc_r0, ppc_xer);
3408 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3409 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3411 case OP_IADD_OVF_UN:
3412 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3414 ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3415 ppc_mfspr (code, ppc_r0, ppc_xer);
3416 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3417 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3420 CASE_PPC64 (OP_LSUB_OVF)
3421 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3423 ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3424 ppc_mfspr (code, ppc_r0, ppc_xer);
3425 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3426 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3428 case OP_ISUB_OVF_UN:
3429 CASE_PPC64 (OP_LSUB_OVF_UN)
3430 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3432 ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3433 ppc_mfspr (code, ppc_r0, ppc_xer);
3434 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3435 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3437 case OP_ADD_OVF_CARRY:
3438 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3440 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3441 ppc_mfspr (code, ppc_r0, ppc_xer);
3442 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3443 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3445 case OP_ADD_OVF_UN_CARRY:
3446 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3448 ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3449 ppc_mfspr (code, ppc_r0, ppc_xer);
3450 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3451 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3453 case OP_SUB_OVF_CARRY:
3454 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3456 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3457 ppc_mfspr (code, ppc_r0, ppc_xer);
3458 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3459 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3461 case OP_SUB_OVF_UN_CARRY:
3462 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3464 ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3465 ppc_mfspr (code, ppc_r0, ppc_xer);
3466 ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3467 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3471 ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3474 CASE_PPC64 (OP_LSUB)
3475 ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3479 ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3483 CASE_PPC64 (OP_LSUB_IMM)
3484 // we add the negated value
3485 if (ppc_is_imm16 (-ins->inst_imm))
3486 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3488 g_assert_not_reached ();
3492 g_assert (ppc_is_imm16 (ins->inst_imm));
3493 ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3496 ppc_subfze (code, ins->dreg, ins->sreg1);
3499 CASE_PPC64 (OP_LAND)
3500 /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3501 ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3505 CASE_PPC64 (OP_LAND_IMM)
3506 if (!(ins->inst_imm & 0xffff0000)) {
3507 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3508 } else if (!(ins->inst_imm & 0xffff)) {
3509 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3511 g_assert_not_reached ();
3515 CASE_PPC64 (OP_LDIV) {
3516 guint8 *divisor_is_m1;
3517 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3519 ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3520 divisor_is_m1 = code;
3521 ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3522 ppc_lis (code, ppc_r0, 0x8000);
3523 #ifdef __mono_ppc64__
3524 if (ins->opcode == OP_LDIV)
3525 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3527 ppc_compare (code, 0, ins->sreg1, ppc_r0);
3528 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3529 ppc_patch (divisor_is_m1, code);
3530 /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3532 if (ins->opcode == OP_IDIV)
3533 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3534 #ifdef __mono_ppc64__
3536 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3538 ppc_mfspr (code, ppc_r0, ppc_xer);
3539 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3540 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3544 CASE_PPC64 (OP_LDIV_UN)
3545 if (ins->opcode == OP_IDIV_UN)
3546 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3547 #ifdef __mono_ppc64__
3549 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3551 ppc_mfspr (code, ppc_r0, ppc_xer);
3552 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3553 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3559 g_assert_not_reached ();
3562 ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3566 CASE_PPC64 (OP_LOR_IMM)
3567 if (!(ins->inst_imm & 0xffff0000)) {
3568 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3569 } else if (!(ins->inst_imm & 0xffff)) {
3570 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3572 g_assert_not_reached ();
3576 CASE_PPC64 (OP_LXOR)
3577 ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3581 CASE_PPC64 (OP_LXOR_IMM)
3582 if (!(ins->inst_imm & 0xffff0000)) {
3583 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3584 } else if (!(ins->inst_imm & 0xffff)) {
3585 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3587 g_assert_not_reached ();
3591 CASE_PPC64 (OP_LSHL)
3592 ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3596 CASE_PPC64 (OP_LSHL_IMM)
3597 ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3600 ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3603 ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3606 if (MASK_SHIFT_IMM (ins->inst_imm))
3607 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3609 ppc_mr (code, ins->dreg, ins->sreg1);
3612 ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 CASE_PPC64 (OP_LNOT)
3616 ppc_not (code, ins->dreg, ins->sreg1);
3619 CASE_PPC64 (OP_LNEG)
3620 ppc_neg (code, ins->dreg, ins->sreg1);
3623 CASE_PPC64 (OP_LMUL)
3624 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3628 CASE_PPC64 (OP_LMUL_IMM)
3629 if (ppc_is_imm16 (ins->inst_imm)) {
3630 ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3632 g_assert_not_reached ();
3636 CASE_PPC64 (OP_LMUL_OVF)
3637 /* we annot use mcrxr, since it's not implemented on some processors
3638 * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3640 if (ins->opcode == OP_IMUL_OVF)
3641 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3642 #ifdef __mono_ppc64__
3644 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3646 ppc_mfspr (code, ppc_r0, ppc_xer);
3647 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3648 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3650 case OP_IMUL_OVF_UN:
3651 CASE_PPC64 (OP_LMUL_OVF_UN)
3652 /* we first multiply to get the high word and compare to 0
3653 * to set the flags, then the result is discarded and then
3654 * we multiply to get the lower * bits result
3656 if (ins->opcode == OP_IMUL_OVF_UN)
3657 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3658 #ifdef __mono_ppc64__
3660 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3662 ppc_cmpi (code, 0, 0, ppc_r0, 0);
3663 EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3664 ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3667 ppc_load (code, ins->dreg, ins->inst_c0);
3670 ppc_load (code, ins->dreg, ins->inst_l);
3673 case OP_LOAD_GOTADDR:
3674 /* The PLT implementation depends on this */
3675 g_assert (ins->dreg == ppc_r30);
3677 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3680 // FIXME: Fix max instruction length
3681 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3682 /* arch_emit_got_access () patches this */
3683 ppc_load32 (code, ppc_r0, 0);
3684 ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3687 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3688 ppc_load_sequence (code, ins->dreg, 0);
3690 CASE_PPC32 (OP_ICONV_TO_I4)
3691 CASE_PPC32 (OP_ICONV_TO_U4)
3693 ppc_mr (code, ins->dreg, ins->sreg1);
3696 int saved = ins->sreg1;
3697 if (ins->sreg1 == ppc_r3) {
3698 ppc_mr (code, ppc_r0, ins->sreg1);
3701 if (ins->sreg2 != ppc_r3)
3702 ppc_mr (code, ppc_r3, ins->sreg2);
3703 if (saved != ppc_r4)
3704 ppc_mr (code, ppc_r4, saved);
3708 ppc_fmr (code, ins->dreg, ins->sreg1);
3710 case OP_FCONV_TO_R4:
3711 ppc_frsp (code, ins->dreg, ins->sreg1);
3715 MonoCallInst *call = (MonoCallInst*)ins;
3718 * Keep in sync with mono_arch_emit_epilog
3720 g_assert (!cfg->method->save_lmf);
3722 * Note: we can use ppc_r11 here because it is dead anyway:
3723 * we're leaving the method.
3725 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3726 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3727 if (ppc_is_imm16 (ret_offset)) {
3728 ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3730 ppc_load (code, ppc_r11, ret_offset);
3731 ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
3733 ppc_mtlr (code, ppc_r0);
3736 if (ppc_is_imm16 (cfg->stack_usage)) {
3737 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3739 /* cfg->stack_usage is an int, so we can use
3740 * an addis/addi sequence here even in 64-bit. */
3741 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3742 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3744 if (!cfg->method->save_lmf) {
3746 for (i = 31; i >= 13; --i) {
3747 if (cfg->used_int_regs & (1 << i)) {
3748 pos += sizeof (gpointer);
3749 ppc_ldptr (code, i, -pos, ppc_r11);
3753 /* FIXME restore from MonoLMF: though this can't happen yet */
3756 /* Copy arguments on the stack to our argument area */
3757 if (call->stack_usage) {
3758 code = emit_memcpy (code, call->stack_usage, ppc_r11, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3759 /* r11 was clobbered */
3760 g_assert (cfg->frame_reg == ppc_sp);
3761 if (ppc_is_imm16 (cfg->stack_usage)) {
3762 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage);
3764 /* cfg->stack_usage is an int, so we can use
3765 * an addis/addi sequence here even in 64-bit. */
3766 ppc_addis (code, ppc_r11, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3767 ppc_addi (code, ppc_r11, ppc_r11, cfg->stack_usage);
3771 ppc_mr (code, ppc_sp, ppc_r11);
3772 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3773 if (cfg->compile_aot) {
3774 /* arch_emit_got_access () patches this */
3775 ppc_load32 (code, ppc_r0, 0);
3776 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3777 ppc_ldptr_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3778 ppc_ldptr (code, ppc_r0, 0, ppc_r11);
3780 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3782 ppc_mtctr (code, ppc_r0);
3783 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3790 /* ensure ins->sreg1 is not NULL */
3791 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3794 long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3795 if (ppc_is_imm16 (cookie_offset)) {
3796 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3798 ppc_load (code, ppc_r0, cookie_offset);
3799 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3801 ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3810 call = (MonoCallInst*)ins;
3811 if (ins->flags & MONO_INST_HAS_METHOD)
3812 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3814 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3815 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3816 ppc_load_func (code, ppc_r0, 0);
3817 ppc_mtlr (code, ppc_r0);
3822 /* FIXME: this should be handled somewhere else in the new jit */
3823 code = emit_move_return_value (cfg, ins, code);
3829 case OP_VOIDCALL_REG:
3831 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3832 ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3833 /* FIXME: if we know that this is a method, we
3834 can omit this load */
3835 ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3836 ppc_mtlr (code, ppc_r0);
3838 ppc_mtlr (code, ins->sreg1);
3841 /* FIXME: this should be handled somewhere else in the new jit */
3842 code = emit_move_return_value (cfg, ins, code);
3844 case OP_FCALL_MEMBASE:
3845 case OP_LCALL_MEMBASE:
3846 case OP_VCALL_MEMBASE:
3847 case OP_VCALL2_MEMBASE:
3848 case OP_VOIDCALL_MEMBASE:
3849 case OP_CALL_MEMBASE:
3850 if (cfg->compile_aot && ins->sreg1 == ppc_r11) {
3851 /* The trampolines clobber this */
3852 ppc_mr (code, ppc_r29, ins->sreg1);
3853 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
3855 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
3857 ppc_mtlr (code, ppc_r0);
3859 /* FIXME: this should be handled somewhere else in the new jit */
3860 code = emit_move_return_value (cfg, ins, code);
3863 guint8 * zero_loop_jump, * zero_loop_start;
3864 /* keep alignment */
3865 int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3866 int area_offset = alloca_waste;
3868 ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3869 /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
3870 ppc_clear_right_imm (code, ppc_r11, ppc_r11, 4);
3871 /* use ctr to store the number of words to 0 if needed */
3872 if (ins->flags & MONO_INST_INIT) {
3873 /* we zero 4 bytes at a time:
3874 * we add 7 instead of 3 so that we set the counter to
3875 * at least 1, otherwise the bdnz instruction will make
3876 * it negative and iterate billions of times.
3878 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3879 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
3880 ppc_mtctr (code, ppc_r0);
3882 ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3883 ppc_neg (code, ppc_r11, ppc_r11);
3884 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r11);
3886 /* FIXME: make this loop work in 8 byte
3887 increments on PPC64 */
3888 if (ins->flags & MONO_INST_INIT) {
3889 /* adjust the dest reg by -4 so we can use stwu */
3890 /* we actually adjust -8 because we let the loop
3893 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3894 ppc_li (code, ppc_r11, 0);
3895 zero_loop_start = code;
3896 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3897 zero_loop_jump = code;
3898 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3899 ppc_patch (zero_loop_jump, zero_loop_start);
3901 ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3906 ppc_mr (code, ppc_r3, ins->sreg1);
3907 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3908 (gpointer)"mono_arch_throw_exception");
3909 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3910 ppc_load_func (code, ppc_r0, 0);
3911 ppc_mtlr (code, ppc_r0);
3920 ppc_mr (code, ppc_r3, ins->sreg1);
3921 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3922 (gpointer)"mono_arch_rethrow_exception");
3923 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3924 ppc_load_func (code, ppc_r0, 0);
3925 ppc_mtlr (code, ppc_r0);
3932 case OP_START_HANDLER: {
3933 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3934 g_assert (spvar->inst_basereg != ppc_sp);
3935 code = emit_reserve_param_area (cfg, code);
3936 ppc_mflr (code, ppc_r0);
3937 if (ppc_is_imm16 (spvar->inst_offset)) {
3938 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3940 ppc_load (code, ppc_r11, spvar->inst_offset);
3941 ppc_stptr_indexed (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3945 case OP_ENDFILTER: {
3946 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3947 g_assert (spvar->inst_basereg != ppc_sp);
3948 code = emit_unreserve_param_area (cfg, code);
3949 if (ins->sreg1 != ppc_r3)
3950 ppc_mr (code, ppc_r3, ins->sreg1);
3951 if (ppc_is_imm16 (spvar->inst_offset)) {
3952 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3954 ppc_load (code, ppc_r11, spvar->inst_offset);
3955 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3957 ppc_mtlr (code, ppc_r0);
3961 case OP_ENDFINALLY: {
3962 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3963 g_assert (spvar->inst_basereg != ppc_sp);
3964 code = emit_unreserve_param_area (cfg, code);
3965 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3966 ppc_mtlr (code, ppc_r0);
3970 case OP_CALL_HANDLER:
3971 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3973 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3976 ins->inst_c0 = code - cfg->native_code;
3979 /*if (ins->inst_target_bb->native_offset) {
3981 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset);
3983 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3988 ppc_mtctr (code, ins->sreg1);
3989 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3993 CASE_PPC64 (OP_LCEQ)
3994 ppc_li (code, ins->dreg, 0);
3995 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3996 ppc_li (code, ins->dreg, 1);
4002 CASE_PPC64 (OP_LCLT)
4003 CASE_PPC64 (OP_LCLT_UN)
4004 ppc_li (code, ins->dreg, 1);
4005 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4006 ppc_li (code, ins->dreg, 0);
4012 CASE_PPC64 (OP_LCGT)
4013 CASE_PPC64 (OP_LCGT_UN)
4014 ppc_li (code, ins->dreg, 1);
4015 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4016 ppc_li (code, ins->dreg, 0);
4018 case OP_COND_EXC_EQ:
4019 case OP_COND_EXC_NE_UN:
4020 case OP_COND_EXC_LT:
4021 case OP_COND_EXC_LT_UN:
4022 case OP_COND_EXC_GT:
4023 case OP_COND_EXC_GT_UN:
4024 case OP_COND_EXC_GE:
4025 case OP_COND_EXC_GE_UN:
4026 case OP_COND_EXC_LE:
4027 case OP_COND_EXC_LE_UN:
4028 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4030 case OP_COND_EXC_IEQ:
4031 case OP_COND_EXC_INE_UN:
4032 case OP_COND_EXC_ILT:
4033 case OP_COND_EXC_ILT_UN:
4034 case OP_COND_EXC_IGT:
4035 case OP_COND_EXC_IGT_UN:
4036 case OP_COND_EXC_IGE:
4037 case OP_COND_EXC_IGE_UN:
4038 case OP_COND_EXC_ILE:
4039 case OP_COND_EXC_ILE_UN:
4040 EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4052 EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4055 /* floating point opcodes */
4057 g_assert (cfg->compile_aot);
4059 /* FIXME: Optimize this */
4061 ppc_mflr (code, ppc_r11);
4063 *(double*)code = *(double*)ins->inst_p0;
4065 ppc_lfd (code, ins->dreg, 8, ppc_r11);
4068 g_assert_not_reached ();
4070 case OP_STORER8_MEMBASE_REG:
4071 if (ppc_is_imm16 (ins->inst_offset)) {
4072 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4074 if (ppc_is_imm32 (ins->inst_offset)) {
4075 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4076 ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r12);
4078 ppc_load (code, ppc_r0, ins->inst_offset);
4079 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4083 case OP_LOADR8_MEMBASE:
4084 if (ppc_is_imm16 (ins->inst_offset)) {
4085 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4087 if (ppc_is_imm32 (ins->inst_offset)) {
4088 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4089 ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r12);
4091 ppc_load (code, ppc_r0, ins->inst_offset);
4092 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4096 case OP_STORER4_MEMBASE_REG:
4097 ppc_frsp (code, ins->sreg1, ins->sreg1);
4098 if (ppc_is_imm16 (ins->inst_offset)) {
4099 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4101 if (ppc_is_imm32 (ins->inst_offset)) {
4102 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4103 ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r12);
4105 ppc_load (code, ppc_r0, ins->inst_offset);
4106 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4110 case OP_LOADR4_MEMBASE:
4111 if (ppc_is_imm16 (ins->inst_offset)) {
4112 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4114 if (ppc_is_imm32 (ins->inst_offset)) {
4115 ppc_addis (code, ppc_r12, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4116 ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r12);
4118 ppc_load (code, ppc_r0, ins->inst_offset);
4119 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4123 case OP_LOADR4_MEMINDEX:
4124 ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4126 case OP_LOADR8_MEMINDEX:
4127 ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4129 case OP_STORER4_MEMINDEX:
4130 ppc_frsp (code, ins->sreg1, ins->sreg1);
4131 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4133 case OP_STORER8_MEMINDEX:
4134 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4137 case CEE_CONV_R4: /* FIXME: change precision */
4139 g_assert_not_reached ();
4140 case OP_FCONV_TO_I1:
4141 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4143 case OP_FCONV_TO_U1:
4144 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4146 case OP_FCONV_TO_I2:
4147 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4149 case OP_FCONV_TO_U2:
4150 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4152 case OP_FCONV_TO_I4:
4154 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4156 case OP_FCONV_TO_U4:
4158 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4160 case OP_LCONV_TO_R_UN:
4161 g_assert_not_reached ();
4162 /* Implemented as helper calls */
4164 case OP_LCONV_TO_OVF_I4_2:
4165 case OP_LCONV_TO_OVF_I: {
4166 #ifdef __mono_ppc64__
4169 guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4170 // Check if its negative
4171 ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4172 negative_branch = code;
4173 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4174 // Its positive msword == 0
4175 ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4176 msword_positive_branch = code;
4177 ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4179 ovf_ex_target = code;
4180 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4182 ppc_patch (negative_branch, code);
4183 ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4184 msword_negative_branch = code;
4185 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4186 ppc_patch (msword_negative_branch, ovf_ex_target);
4188 ppc_patch (msword_positive_branch, code);
4189 if (ins->dreg != ins->sreg1)
4190 ppc_mr (code, ins->dreg, ins->sreg1);
4195 ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4198 ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4201 ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4204 ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4207 ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4210 ppc_fneg (code, ins->dreg, ins->sreg1);
4214 g_assert_not_reached ();
4217 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4220 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4221 ppc_li (code, ins->dreg, 0);
4222 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4223 ppc_li (code, ins->dreg, 1);
4226 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4227 ppc_li (code, ins->dreg, 1);
4228 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4229 ppc_li (code, ins->dreg, 0);
4232 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4233 ppc_li (code, ins->dreg, 1);
4234 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4235 ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4236 ppc_li (code, ins->dreg, 0);
4239 ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4240 ppc_li (code, ins->dreg, 1);
4241 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4242 ppc_li (code, ins->dreg, 0);
4245 ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4246 ppc_li (code, ins->dreg, 1);
4247 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4248 ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4249 ppc_li (code, ins->dreg, 0);
4252 EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4255 EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4258 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4259 EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4262 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4263 EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4266 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4267 EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4270 EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4271 EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4274 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4275 EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4278 EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4281 ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4282 EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4285 EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4288 g_assert_not_reached ();
4289 case OP_CHECK_FINITE: {
4290 ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4291 ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4292 ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4293 EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4296 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4297 #ifdef __mono_ppc64__
4298 ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4300 ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4305 #ifdef __mono_ppc64__
4306 case OP_ICONV_TO_I4:
4308 ppc_extsw (code, ins->dreg, ins->sreg1);
4310 case OP_ICONV_TO_U4:
4312 ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4314 case OP_ICONV_TO_R4:
4315 case OP_ICONV_TO_R8:
4316 case OP_LCONV_TO_R4:
4317 case OP_LCONV_TO_R8: {
4319 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4320 ppc_extsw (code, ppc_r0, ins->sreg1);
4325 if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4326 ppc_mffgpr (code, ins->dreg, tmp);
4328 ppc_str (code, tmp, -8, ppc_r1);
4329 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4331 ppc_fcfid (code, ins->dreg, ins->dreg);
4332 if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4333 ppc_frsp (code, ins->dreg, ins->dreg);
4337 ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4340 ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4343 /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4345 ppc_mfspr (code, ppc_r0, ppc_xer);
4346 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4347 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4349 case OP_COND_EXC_OV:
4350 ppc_mfspr (code, ppc_r0, ppc_xer);
4351 ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4352 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4364 EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4366 case OP_FCONV_TO_I8:
4367 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4369 case OP_FCONV_TO_U8:
4370 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4372 case OP_STOREI4_MEMBASE_REG:
4373 if (ppc_is_imm16 (ins->inst_offset)) {
4374 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4376 ppc_load (code, ppc_r0, ins->inst_offset);
4377 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4380 case OP_STOREI4_MEMINDEX:
4381 ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4384 ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4386 case OP_ISHR_UN_IMM:
4387 if (ins->inst_imm & 0x1f)
4388 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4390 ppc_mr (code, ins->dreg, ins->sreg1);
4392 case OP_ATOMIC_ADD_I4:
4393 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4394 int location = ins->inst_basereg;
4395 int addend = ins->sreg2;
4396 guint8 *loop, *branch;
4397 g_assert (ins->inst_offset == 0);
4401 if (ins->opcode == OP_ATOMIC_ADD_I4)
4402 ppc_lwarx (code, ppc_r0, 0, location);
4403 #ifdef __mono_ppc64__
4405 ppc_ldarx (code, ppc_r0, 0, location);
4408 ppc_add (code, ppc_r0, ppc_r0, addend);
4410 if (ins->opcode == OP_ATOMIC_ADD_I4)
4411 ppc_stwcxd (code, ppc_r0, 0, location);
4412 #ifdef __mono_ppc64__
4414 ppc_stdcxd (code, ppc_r0, 0, location);
4418 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4419 ppc_patch (branch, loop);
4422 ppc_mr (code, ins->dreg, ppc_r0);
4426 case OP_ICONV_TO_R4:
4427 case OP_ICONV_TO_R8: {
4428 if (cpu_hw_caps & PPC_ISA_64) {
4429 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4430 ppc_stw (code, ppc_r0, -8, ppc_r1);
4431 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4432 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4433 ppc_fcfid (code, ins->dreg, ins->dreg);
4434 if (ins->opcode == OP_ICONV_TO_R4)
4435 ppc_frsp (code, ins->dreg, ins->dreg);
4440 case OP_ATOMIC_CAS_I4:
4441 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4442 int location = ins->sreg1;
4443 int value = ins->sreg2;
4444 int comparand = ins->sreg3;
4445 guint8 *start, *not_equal, *lost_reservation;
4449 if (ins->opcode == OP_ATOMIC_CAS_I4)
4450 ppc_lwarx (code, ppc_r0, 0, location);
4451 #ifdef __mono_ppc64__
4453 ppc_ldarx (code, ppc_r0, 0, location);
4456 ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4458 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4460 if (ins->opcode == OP_ATOMIC_CAS_I4)
4461 ppc_stwcxd (code, value, 0, location);
4462 #ifdef __mono_ppc64__
4464 ppc_stdcxd (code, value, 0, location);
4467 lost_reservation = code;
4468 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4469 ppc_patch (lost_reservation, start);
4470 ppc_patch (not_equal, code);
4473 ppc_mr (code, ins->dreg, ppc_r0);
4478 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4479 g_assert_not_reached ();
4482 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4483 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4484 mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4485 g_assert_not_reached ();
4491 last_offset = offset;
4494 cfg->code_len = code - cfg->native_code;
4496 #endif /* !DISABLE_JIT */
4499 mono_arch_register_lowlevel_calls (void)
4501 /* The signature doesn't matter */
4502 mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4505 #ifdef __mono_ppc64__
4506 #define patch_load_sequence(ip,val) do {\
4507 guint16 *__load = (guint16*)(ip); \
4508 g_assert (sizeof (val) == sizeof (gsize)); \
4509 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff; \
4510 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff; \
4511 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff; \
4512 __load [9] = ((guint64)(gsize)(val)) & 0xffff; \
4515 #define patch_load_sequence(ip,val) do {\
4516 guint16 *__lis_ori = (guint16*)(ip); \
4517 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff; \
4518 __lis_ori [3] = ((gulong)(val)) & 0xffff; \
4524 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4526 MonoJumpInfo *patch_info;
4527 gboolean compile_aot = !run_cctors;
4529 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4530 unsigned char *ip = patch_info->ip.i + code;
4531 unsigned char *target;
4532 gboolean is_fd = FALSE;
4534 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4537 switch (patch_info->type) {
4538 case MONO_PATCH_INFO_BB:
4539 case MONO_PATCH_INFO_LABEL:
4542 /* No need to patch these */
4547 switch (patch_info->type) {
4548 case MONO_PATCH_INFO_IP:
4549 patch_load_sequence (ip, ip);
4551 case MONO_PATCH_INFO_METHOD_REL:
4552 g_assert_not_reached ();
4553 *((gpointer *)(ip)) = code + patch_info->data.offset;
4555 case MONO_PATCH_INFO_SWITCH: {
4556 gpointer *table = (gpointer *)patch_info->data.table->table;
4559 patch_load_sequence (ip, table);
4561 for (i = 0; i < patch_info->data.table->table_size; i++) {
4562 table [i] = (glong)patch_info->data.table->table [i] + code;
4564 /* we put into the table the absolute address, no need for ppc_patch in this case */
4567 case MONO_PATCH_INFO_METHODCONST:
4568 case MONO_PATCH_INFO_CLASS:
4569 case MONO_PATCH_INFO_IMAGE:
4570 case MONO_PATCH_INFO_FIELD:
4571 case MONO_PATCH_INFO_VTABLE:
4572 case MONO_PATCH_INFO_IID:
4573 case MONO_PATCH_INFO_SFLDA:
4574 case MONO_PATCH_INFO_LDSTR:
4575 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4576 case MONO_PATCH_INFO_LDTOKEN:
4577 /* from OP_AOTCONST : lis + ori */
4578 patch_load_sequence (ip, target);
4580 case MONO_PATCH_INFO_R4:
4581 case MONO_PATCH_INFO_R8:
4582 g_assert_not_reached ();
4583 *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4585 case MONO_PATCH_INFO_EXC_NAME:
4586 g_assert_not_reached ();
4587 *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4589 case MONO_PATCH_INFO_NONE:
4590 case MONO_PATCH_INFO_BB_OVF:
4591 case MONO_PATCH_INFO_EXC_OVF:
4592 /* everything is dealt with at epilog output time */
4594 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4595 case MONO_PATCH_INFO_INTERNAL_METHOD:
4596 case MONO_PATCH_INFO_ABS:
4597 case MONO_PATCH_INFO_CLASS_INIT:
4598 case MONO_PATCH_INFO_RGCTX_FETCH:
4599 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4606 ppc_patch_full (ip, target, is_fd);
4611 * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4612 * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4613 * the instruction offset immediate for all the registers.
4616 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4620 for (i = 13; i <= 31; i++) {
4621 if (used_int_regs & (1 << i)) {
4622 ppc_str (code, i, pos, base_reg);
4623 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4624 pos += sizeof (mgreg_t);
4628 /* pos is the start of the MonoLMF structure */
4629 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4630 for (i = 13; i <= 31; i++) {
4631 ppc_str (code, i, offset, base_reg);
4632 mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4633 offset += sizeof (mgreg_t);
4635 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4636 for (i = 14; i < 32; i++) {
4637 ppc_stfd (code, i, offset, base_reg);
4638 offset += sizeof (gdouble);
4645 * Stack frame layout:
4647 * ------------------- sp
4648 * MonoLMF structure or saved registers
4649 * -------------------
4651 * -------------------
4653 * -------------------
4654 * optional 8 bytes for tracing
4655 * -------------------
4656 * param area size is cfg->param_area
4657 * -------------------
4658 * linkage area size is PPC_STACK_PARAM_OFFSET
4659 * ------------------- sp
4663 mono_arch_emit_prolog (MonoCompile *cfg)
4665 MonoMethod *method = cfg->method;
4667 MonoMethodSignature *sig;
4669 long alloc_size, pos, max_offset, cfa_offset;
4675 int tailcall_struct_index;
4677 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4680 sig = mono_method_signature (method);
4681 cfg->code_size = 512 + sig->param_count * 32;
4682 code = cfg->native_code = g_malloc (cfg->code_size);
4686 /* We currently emit unwind info for aot, but don't use it */
4687 mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4689 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4690 ppc_mflr (code, ppc_r0);
4691 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4692 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4695 alloc_size = cfg->stack_offset;
4698 if (!method->save_lmf) {
4699 for (i = 31; i >= 13; --i) {
4700 if (cfg->used_int_regs & (1 << i)) {
4701 pos += sizeof (mgreg_t);
4705 pos += sizeof (MonoLMF);
4709 // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4710 if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4711 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4712 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4715 cfg->stack_usage = alloc_size;
4716 g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4718 if (ppc_is_imm16 (-alloc_size)) {
4719 ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4720 cfa_offset = alloc_size;
4721 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4722 code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4725 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4726 ppc_load (code, ppc_r0, -alloc_size);
4727 ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4728 cfa_offset = alloc_size;
4729 mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4730 code = save_registers (cfg, code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs, cfa_offset);
4733 if (cfg->frame_reg != ppc_sp) {
4734 ppc_mr (code, cfg->frame_reg, ppc_sp);
4735 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4738 /* store runtime generic context */
4739 if (cfg->rgctx_var) {
4740 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4741 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4743 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4746 /* compute max_offset in order to use short forward jumps
4747 * we always do it on ppc because the immediate displacement
4748 * for jumps is too small
4751 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4753 bb->max_offset = max_offset;
4755 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4758 MONO_BB_FOR_EACH_INS (bb, ins)
4759 max_offset += ins_native_length (cfg, ins);
4762 /* load arguments allocated to register from the stack */
4765 cinfo = get_call_info (cfg->generic_sharing_context, sig);
4767 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4768 ArgInfo *ainfo = &cinfo->ret;
4770 inst = cfg->vret_addr;
4773 if (ppc_is_imm16 (inst->inst_offset)) {
4774 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4776 ppc_load (code, ppc_r11, inst->inst_offset);
4777 ppc_stptr_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4781 tailcall_struct_index = 0;
4782 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4783 ArgInfo *ainfo = cinfo->args + i;
4784 inst = cfg->args [pos];
4786 if (cfg->verbose_level > 2)
4787 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4788 if (inst->opcode == OP_REGVAR) {
4789 if (ainfo->regtype == RegTypeGeneral)
4790 ppc_mr (code, inst->dreg, ainfo->reg);
4791 else if (ainfo->regtype == RegTypeFP)
4792 ppc_fmr (code, inst->dreg, ainfo->reg);
4793 else if (ainfo->regtype == RegTypeBase) {
4794 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4795 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r11);
4797 g_assert_not_reached ();
4799 if (cfg->verbose_level > 2)
4800 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4802 /* the argument should be put on the stack: FIXME handle size != word */
4803 if (ainfo->regtype == RegTypeGeneral) {
4804 switch (ainfo->size) {
4806 if (ppc_is_imm16 (inst->inst_offset)) {
4807 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4809 if (ppc_is_imm32 (inst->inst_offset)) {
4810 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4811 ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
4813 ppc_load (code, ppc_r11, inst->inst_offset);
4814 ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4819 if (ppc_is_imm16 (inst->inst_offset)) {
4820 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4822 if (ppc_is_imm32 (inst->inst_offset)) {
4823 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4824 ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
4826 ppc_load (code, ppc_r11, inst->inst_offset);
4827 ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4831 #ifdef __mono_ppc64__
4833 if (ppc_is_imm16 (inst->inst_offset)) {
4834 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4836 if (ppc_is_imm32 (inst->inst_offset)) {
4837 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4838 ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
4840 ppc_load (code, ppc_r11, inst->inst_offset);
4841 ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4846 if (ppc_is_imm16 (inst->inst_offset)) {
4847 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4849 ppc_load (code, ppc_r11, inst->inst_offset);
4850 ppc_str_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4855 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4856 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4857 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4859 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4860 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4861 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4862 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4867 if (ppc_is_imm16 (inst->inst_offset)) {
4868 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4870 if (ppc_is_imm32 (inst->inst_offset)) {
4871 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4872 ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
4874 ppc_load (code, ppc_r11, inst->inst_offset);
4875 ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
4880 } else if (ainfo->regtype == RegTypeBase) {
4881 g_assert (ppc_is_imm16 (ainfo->offset));
4882 /* load the previous stack pointer in r11 */
4883 ppc_ldr (code, ppc_r11, 0, ppc_sp);
4884 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r11);
4885 switch (ainfo->size) {
4887 if (ppc_is_imm16 (inst->inst_offset)) {
4888 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4890 if (ppc_is_imm32 (inst->inst_offset)) {
4891 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4892 ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
4894 ppc_load (code, ppc_r11, inst->inst_offset);
4895 ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4900 if (ppc_is_imm16 (inst->inst_offset)) {
4901 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4903 if (ppc_is_imm32 (inst->inst_offset)) {
4904 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4905 ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
4907 ppc_load (code, ppc_r11, inst->inst_offset);
4908 ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4912 #ifdef __mono_ppc64__
4914 if (ppc_is_imm16 (inst->inst_offset)) {
4915 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4917 if (ppc_is_imm32 (inst->inst_offset)) {
4918 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4919 ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
4921 ppc_load (code, ppc_r11, inst->inst_offset);
4922 ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
4927 if (ppc_is_imm16 (inst->inst_offset)) {
4928 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4930 ppc_load (code, ppc_r11, inst->inst_offset);
4931 ppc_str_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4936 g_assert (ppc_is_imm16 (ainfo->offset + 4));
4937 if (ppc_is_imm16 (inst->inst_offset + 4)) {
4938 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4939 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4940 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4942 /* use r12 to load the 2nd half of the long before we clobber r11. */
4943 ppc_lwz (code, ppc_r12, ainfo->offset + 4, ppc_r11);
4944 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4945 ppc_addi (code, ppc_r11, ppc_r11, inst->inst_offset);
4946 ppc_stw (code, ppc_r0, 0, ppc_r11);
4947 ppc_stw (code, ppc_r12, 4, ppc_r11);
4952 if (ppc_is_imm16 (inst->inst_offset)) {
4953 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4955 if (ppc_is_imm32 (inst->inst_offset)) {
4956 ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
4957 ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
4959 ppc_load (code, ppc_r11, inst->inst_offset);
4960 ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
4965 } else if (ainfo->regtype == RegTypeFP) {
4966 g_assert (ppc_is_imm16 (inst->inst_offset));
4967 if (ainfo->size == 8)
4968 ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4969 else if (ainfo->size == 4)
4970 ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4972 g_assert_not_reached ();
4973 } else if (ainfo->regtype == RegTypeStructByVal) {
4974 int doffset = inst->inst_offset;
4978 g_assert (ppc_is_imm16 (inst->inst_offset));
4979 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
4980 /* FIXME: what if there is no class? */
4981 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4982 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4983 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
4986 * Darwin handles 1 and 2 byte
4987 * structs specially by
4988 * loading h/b into the arg
4989 * register. Only done for
4993 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4995 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4999 #ifdef __mono_ppc64__
5001 g_assert (cur_reg == 0);
5002 ppc_sldi (code, ppc_r0, ainfo->reg,
5003 (sizeof (gpointer) - ainfo->bytes) * 8);
5004 ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5008 ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5009 inst->inst_basereg);
5012 soffset += sizeof (gpointer);
5013 doffset += sizeof (gpointer);
5015 if (ainfo->vtsize) {
5016 /* FIXME: we need to do the shifting here, too */
5019 /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
5020 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5021 if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5022 code = emit_memcpy (code, size - soffset,
5023 inst->inst_basereg, doffset,
5024 ppc_r11, ainfo->offset + soffset);
5026 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5027 inst->inst_basereg, doffset,
5028 ppc_r11, ainfo->offset + soffset);
5031 } else if (ainfo->regtype == RegTypeStructByAddr) {
5032 /* if it was originally a RegTypeBase */
5033 if (ainfo->offset) {
5034 /* load the previous stack pointer in r11 */
5035 ppc_ldr (code, ppc_r11, 0, ppc_sp);
5036 ppc_ldptr (code, ppc_r11, ainfo->offset, ppc_r11);
5038 ppc_mr (code, ppc_r11, ainfo->reg);
5041 if (cfg->tailcall_valuetype_addrs) {
5042 MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5044 g_assert (ppc_is_imm16 (addr->inst_offset));
5045 ppc_stptr (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
5047 tailcall_struct_index++;
5050 g_assert (ppc_is_imm16 (inst->inst_offset));
5051 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
5052 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5054 g_assert_not_reached ();
5059 if (method->save_lmf) {
5060 if (lmf_pthread_key != -1) {
5061 emit_tls_access (code, ppc_r3, lmf_pthread_key);
5062 if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5063 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5065 if (cfg->compile_aot) {
5066 /* Compute the got address which is needed by the PLT entry */
5067 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5069 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
5070 (gpointer)"mono_get_lmf_addr");
5071 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5072 ppc_load_func (code, ppc_r0, 0);
5073 ppc_mtlr (code, ppc_r0);
5079 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5080 /* lmf_offset is the offset from the previous stack pointer,
5081 * alloc_size is the total stack space allocated, so the offset
5082 * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5083 * The pointer to the struct is put in ppc_r11 (new_lmf).
5084 * The callee-saved registers are already in the MonoLMF structure
5086 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
5087 /* ppc_r3 is the result from mono_get_lmf_addr () */
5088 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5089 /* new_lmf->previous_lmf = *lmf_addr */
5090 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5091 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5092 /* *(lmf_addr) = r11 */
5093 ppc_stptr (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5094 /* save method info */
5095 if (cfg->compile_aot)
5097 ppc_load (code, ppc_r0, 0);
5099 ppc_load_ptr (code, ppc_r0, method);
5100 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
5101 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
5102 /* save the current IP */
5103 if (cfg->compile_aot) {
5105 ppc_mflr (code, ppc_r0);
5107 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5108 #ifdef __mono_ppc64__
5109 ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5111 ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5114 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
5118 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5120 cfg->code_len = code - cfg->native_code;
5121 g_assert (cfg->code_len <= cfg->code_size);
5128 mono_arch_emit_epilog (MonoCompile *cfg)
5130 MonoMethod *method = cfg->method;
5132 int max_epilog_size = 16 + 20*4;
5135 if (cfg->method->save_lmf)
5136 max_epilog_size += 128;
5138 if (mono_jit_trace_calls != NULL)
5139 max_epilog_size += 50;
5141 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5142 max_epilog_size += 50;
5144 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5145 cfg->code_size *= 2;
5146 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5147 cfg->stat_code_reallocs++;
5151 * Keep in sync with OP_JMP
5153 code = cfg->native_code + cfg->code_len;
5155 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5156 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5160 if (method->save_lmf) {
5162 pos += sizeof (MonoLMF);
5164 /* save the frame reg in r8 */
5165 ppc_mr (code, ppc_r8, cfg->frame_reg);
5166 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5167 /* r5 = previous_lmf */
5168 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
5170 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
5171 /* *(lmf_addr) = previous_lmf */
5172 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5173 /* FIXME: speedup: there is no actual need to restore the registers if
5174 * we didn't actually change them (idea from Zoltan).
5177 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
5179 /*for (i = 14; i < 32; i++) {
5180 ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5182 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5183 /* use the saved copy of the frame reg in r8 */
5184 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5185 ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5186 ppc_mtlr (code, ppc_r0);
5188 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5190 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5191 long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5192 if (ppc_is_imm16 (return_offset)) {
5193 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5195 ppc_load (code, ppc_r11, return_offset);
5196 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5198 ppc_mtlr (code, ppc_r0);
5200 if (ppc_is_imm16 (cfg->stack_usage)) {
5201 int offset = cfg->stack_usage;
5202 for (i = 13; i <= 31; i++) {
5203 if (cfg->used_int_regs & (1 << i))
5204 offset -= sizeof (mgreg_t);
5206 if (cfg->frame_reg != ppc_sp)
5207 ppc_mr (code, ppc_r11, cfg->frame_reg);
5208 /* note r31 (possibly the frame register) is restored last */
5209 for (i = 13; i <= 31; i++) {
5210 if (cfg->used_int_regs & (1 << i)) {
5211 ppc_ldr (code, i, offset, cfg->frame_reg);
5212 offset += sizeof (mgreg_t);
5215 if (cfg->frame_reg != ppc_sp)
5216 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5218 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5220 ppc_load32 (code, ppc_r11, cfg->stack_usage);
5221 if (cfg->used_int_regs) {
5222 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5223 for (i = 31; i >= 13; --i) {
5224 if (cfg->used_int_regs & (1 << i)) {
5225 pos += sizeof (mgreg_t);
5226 ppc_ldr (code, i, -pos, ppc_r11);
5229 ppc_mr (code, ppc_sp, ppc_r11);
5231 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5238 cfg->code_len = code - cfg->native_code;
5240 g_assert (cfg->code_len < cfg->code_size);
5243 #endif /* ifndef DISABLE_JIT */
5245 /* remove once throw_exception_by_name is eliminated */
5247 exception_id_by_name (const char *name)
5249 if (strcmp (name, "IndexOutOfRangeException") == 0)
5250 return MONO_EXC_INDEX_OUT_OF_RANGE;
5251 if (strcmp (name, "OverflowException") == 0)
5252 return MONO_EXC_OVERFLOW;
5253 if (strcmp (name, "ArithmeticException") == 0)
5254 return MONO_EXC_ARITHMETIC;
5255 if (strcmp (name, "DivideByZeroException") == 0)
5256 return MONO_EXC_DIVIDE_BY_ZERO;
5257 if (strcmp (name, "InvalidCastException") == 0)
5258 return MONO_EXC_INVALID_CAST;
5259 if (strcmp (name, "NullReferenceException") == 0)
5260 return MONO_EXC_NULL_REF;
5261 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5262 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5263 if (strcmp (name, "ArgumentException") == 0)
5264 return MONO_EXC_ARGUMENT;
5265 g_error ("Unknown intrinsic exception %s\n", name);
5271 mono_arch_emit_exceptions (MonoCompile *cfg)
5273 MonoJumpInfo *patch_info;
5276 guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5277 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5278 int max_epilog_size = 50;
5280 for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5281 exc_throw_pos [i] = NULL;
5282 exc_throw_found [i] = 0;
5285 /* count the number of exception infos */
5288 * make sure we have enough space for exceptions
5290 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5291 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5292 i = exception_id_by_name (patch_info->data.target);
5293 if (!exc_throw_found [i]) {
5294 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5295 exc_throw_found [i] = TRUE;
5297 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5298 max_epilog_size += 12;
5299 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5300 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5301 i = exception_id_by_name (ovfj->data.exception);
5302 if (!exc_throw_found [i]) {
5303 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5304 exc_throw_found [i] = TRUE;
5306 max_epilog_size += 8;
5310 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5311 cfg->code_size *= 2;
5312 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5313 cfg->stat_code_reallocs++;
5316 code = cfg->native_code + cfg->code_len;
5318 /* add code to raise exceptions */
5319 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5320 switch (patch_info->type) {
5321 case MONO_PATCH_INFO_BB_OVF: {
5322 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5323 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5324 /* patch the initial jump */
5325 ppc_patch (ip, code);
5326 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5328 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5329 /* jump back to the true target */
5331 ip = ovfj->data.bb->native_offset + cfg->native_code;
5332 ppc_patch (code - 4, ip);
5333 patch_info->type = MONO_PATCH_INFO_NONE;
5336 case MONO_PATCH_INFO_EXC_OVF: {
5337 MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5338 MonoJumpInfo *newji;
5339 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5340 unsigned char *bcl = code;
5341 /* patch the initial jump: we arrived here with a call */
5342 ppc_patch (ip, code);
5343 ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5345 ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5346 /* patch the conditional jump to the right handler */
5347 /* make it processed next */
5348 newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5349 newji->type = MONO_PATCH_INFO_EXC;
5350 newji->ip.i = bcl - cfg->native_code;
5351 newji->data.target = ovfj->data.exception;
5352 newji->next = patch_info->next;
5353 patch_info->next = newji;
5354 patch_info->type = MONO_PATCH_INFO_NONE;
5357 case MONO_PATCH_INFO_EXC: {
5358 MonoClass *exc_class;
5360 unsigned char *ip = patch_info->ip.i + cfg->native_code;
5361 i = exception_id_by_name (patch_info->data.target);
5362 if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5363 ppc_patch (ip, exc_throw_pos [i]);
5364 patch_info->type = MONO_PATCH_INFO_NONE;
5367 exc_throw_pos [i] = code;
5370 exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5371 g_assert (exc_class);
5373 ppc_patch (ip, code);
5374 /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5375 ppc_load (code, ppc_r3, exc_class->type_token);
5376 /* we got here from a conditional call, so the calling ip is set in lr */
5377 ppc_mflr (code, ppc_r4);
5378 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5379 patch_info->data.name = "mono_arch_throw_corlib_exception";
5380 patch_info->ip.i = code - cfg->native_code;
5381 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5382 ppc_load_func (code, ppc_r0, 0);
5383 ppc_mtctr (code, ppc_r0);
5384 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5396 cfg->code_len = code - cfg->native_code;
5398 g_assert (cfg->code_len <= cfg->code_size);
5404 try_offset_access (void *value, guint32 idx)
5406 register void* me __asm__ ("r2");
5407 void ***p = (void***)((char*)me + 284);
5408 int idx1 = idx / 32;
5409 int idx2 = idx % 32;
5412 if (value != p[idx1][idx2])
5419 setup_tls_access (void)
5421 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5422 size_t conf_size = 0;
5425 /* FIXME for darwin */
5426 guint32 *ins, *code;
5427 guint32 cmplwi_1023, li_0x48, blr_ins;
5431 tls_mode = TLS_MODE_FAILED;
5434 if (tls_mode == TLS_MODE_FAILED)
5436 if (g_getenv ("MONO_NO_TLS")) {
5437 tls_mode = TLS_MODE_FAILED;
5441 if (tls_mode == TLS_MODE_DETECT) {
5442 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5443 tls_mode = TLS_MODE_DARWIN_G4;
5444 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5445 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5446 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5447 tls_mode = TLS_MODE_NPTL;
5448 #elif !defined(TARGET_PS3)
5449 ins = (guint32*)pthread_getspecific;
5450 /* uncond branch to the real method */
5451 if ((*ins >> 26) == 18) {
5453 val = (*ins & ~3) << 6;
5457 ins = (guint32*)(long)val;
5459 ins = (guint32*) ((char*)ins + val);
5462 code = &cmplwi_1023;
5463 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5465 ppc_li (code, ppc_r4, 0x48);
5468 if (*ins == cmplwi_1023) {
5469 int found_lwz_284 = 0;
5471 for (ptk = 0; ptk < 20; ++ptk) {
5473 if (!*ins || *ins == blr_ins)
5475 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5480 if (!found_lwz_284) {
5481 tls_mode = TLS_MODE_FAILED;
5484 tls_mode = TLS_MODE_LTHREADS;
5485 } else if (*ins == li_0x48) {
5487 /* uncond branch to the real method */
5488 if ((*ins >> 26) == 18) {
5490 val = (*ins & ~3) << 6;
5494 ins = (guint32*)(long)val;
5496 ins = (guint32*) ((char*)ins + val);
5498 code = (guint32*)&val;
5499 ppc_li (code, ppc_r0, 0x7FF2);
5500 if (ins [1] == val) {
5501 /* Darwin on G4, implement */
5502 tls_mode = TLS_MODE_FAILED;
5505 code = (guint32*)&val;
5506 ppc_mfspr (code, ppc_r3, 104);
5507 if (ins [1] != val) {
5508 tls_mode = TLS_MODE_FAILED;
5511 tls_mode = TLS_MODE_DARWIN_G5;
5514 tls_mode = TLS_MODE_FAILED;
5518 tls_mode = TLS_MODE_FAILED;
5524 if (tls_mode == TLS_MODE_DETECT)
5525 tls_mode = TLS_MODE_FAILED;
5526 if (tls_mode == TLS_MODE_FAILED)
5528 if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5529 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5533 /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5534 mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5535 if (lmf_pthread_key == -1) {
5536 guint32 ptk = mono_jit_tls_id;
5538 /*g_print ("MonoLMF at: %d\n", ptk);*/
5539 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5540 init_tls_failed = 1;
5543 lmf_pthread_key = ptk;
5552 mono_arch_finish_init (void)
5554 setup_tls_access ();
5558 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5562 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5564 #define LOADSTORE_SIZE 4
5565 #define JUMP_IMM_SIZE 12
5566 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5567 #define ENABLE_WRONG_METHOD_CHECK 0
5570 * LOCKING: called with the domain lock held
5573 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5574 gpointer fail_tramp)
5578 guint8 *code, *start;
5580 for (i = 0; i < count; ++i) {
5581 MonoIMTCheckItem *item = imt_entries [i];
5582 if (item->is_equals) {
5583 if (item->check_target_idx) {
5584 if (!item->compare_done)
5585 item->chunk_size += CMP_SIZE;
5586 if (item->has_target_code)
5587 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5589 item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5592 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5593 if (!item->has_target_code)
5594 item->chunk_size += LOADSTORE_SIZE;
5596 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5597 #if ENABLE_WRONG_METHOD_CHECK
5598 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5603 item->chunk_size += CMP_SIZE + BR_SIZE;
5604 imt_entries [item->check_target_idx]->compare_done = TRUE;
5606 size += item->chunk_size;
5608 /* the initial load of the vtable address */
5609 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5611 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5613 code = mono_domain_code_reserve (domain, size);
5618 * We need to save and restore r11 because it might be
5619 * used by the caller as the vtable register, so
5620 * clobbering it will trip up the magic trampoline.
5622 * FIXME: Get rid of this by making sure that r11 is
5623 * not used as the vtable register in interface calls.
5625 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5626 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5628 for (i = 0; i < count; ++i) {
5629 MonoIMTCheckItem *item = imt_entries [i];
5630 item->code_target = code;
5631 if (item->is_equals) {
5632 if (item->check_target_idx) {
5633 if (!item->compare_done) {
5634 ppc_load (code, ppc_r0, (gsize)item->key);
5635 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5637 item->jmp_code = code;
5638 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5639 if (item->has_target_code) {
5640 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5642 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5643 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5645 ppc_mtctr (code, ppc_r0);
5646 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5649 ppc_load (code, ppc_r0, (gulong)item->key);
5650 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5651 item->jmp_code = code;
5652 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5653 if (item->has_target_code) {
5654 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5657 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5658 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5660 ppc_mtctr (code, ppc_r0);
5661 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5662 ppc_patch (item->jmp_code, code);
5663 ppc_load_ptr (code, ppc_r0, fail_tramp);
5664 ppc_mtctr (code, ppc_r0);
5665 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5666 item->jmp_code = NULL;
5668 /* enable the commented code to assert on wrong method */
5669 #if ENABLE_WRONG_METHOD_CHECK
5670 ppc_load (code, ppc_r0, (guint32)item->key);
5671 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5672 item->jmp_code = code;
5673 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5675 ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5676 ppc_ldptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5677 ppc_mtctr (code, ppc_r0);
5678 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5679 #if ENABLE_WRONG_METHOD_CHECK
5680 ppc_patch (item->jmp_code, code);
5682 item->jmp_code = NULL;
5687 ppc_load (code, ppc_r0, (gulong)item->key);
5688 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5689 item->jmp_code = code;
5690 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5693 /* patch the branches to get to the target items */
5694 for (i = 0; i < count; ++i) {
5695 MonoIMTCheckItem *item = imt_entries [i];
5696 if (item->jmp_code) {
5697 if (item->check_target_idx) {
5698 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5704 mono_stats.imt_thunks_size += code - start;
5705 g_assert (code - start <= size);
5706 mono_arch_flush_icache (start, size);
5711 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5713 mgreg_t *r = (mgreg_t*)regs;
5715 return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5719 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5721 mgreg_t *r = (mgreg_t*)regs;
5723 return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5727 mono_arch_get_cie_program (void)
5731 mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5737 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5744 mono_arch_print_tree (MonoInst *tree, int arity)
5750 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5753 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5755 g_assert (reg >= ppc_r13);
5757 return ctx->regs [reg - ppc_r13];
5761 mono_arch_get_patch_offset (guint8 *code)
5767 * mono_aot_emit_load_got_addr:
5769 * Emit code to load the got address.
5770 * On PPC, the result is placed into r30.
5773 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5776 ppc_mflr (code, ppc_r30);
5778 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5780 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5781 /* arch_emit_got_address () patches this */
5782 #if defined(TARGET_POWERPC64)
5788 ppc_load32 (code, ppc_r0, 0);
5789 ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5796 * mono_ppc_emit_load_aotconst:
5798 * Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5799 * TARGET from the mscorlib GOT in full-aot code.
5800 * On PPC, the GOT address is assumed to be in r30, and the result is placed into
5804 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5806 /* Load the mscorlib got address */
5807 ppc_ldptr (code, ppc_r11, sizeof (gpointer), ppc_r30);
5808 *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5809 /* arch_emit_got_access () patches this */
5810 ppc_load32 (code, ppc_r0, 0);
5811 ppc_ldptr_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5816 /* Soft Debug support */
5817 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5824 * mono_arch_set_breakpoint:
5826 * See mini-amd64.c for docs.
5829 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5832 guint8 *orig_code = code;
5834 ppc_load_sequence (code, ppc_r11, (gsize)bp_trigger_page);
5835 ppc_ldptr (code, ppc_r11, 0, ppc_r11);
5837 g_assert (code - orig_code == BREAKPOINT_SIZE);
5839 mono_arch_flush_icache (orig_code, code - orig_code);
5843 * mono_arch_clear_breakpoint:
5845 * See mini-amd64.c for docs.
5848 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5853 for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5856 mono_arch_flush_icache (ip, code - ip);
5860 * mono_arch_is_breakpoint_event:
5862 * See mini-amd64.c for docs.
5865 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5867 siginfo_t* sinfo = (siginfo_t*) info;
5868 /* Sometimes the address is off by 4 */
5869 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5876 * mono_arch_skip_breakpoint:
5878 * See mini-amd64.c for docs.
5881 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5883 /* skip the ldptr */
5884 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5892 * mono_arch_start_single_stepping:
5894 * See mini-amd64.c for docs.
5897 mono_arch_start_single_stepping (void)
5899 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5903 * mono_arch_stop_single_stepping:
5905 * See mini-amd64.c for docs.
5908 mono_arch_stop_single_stepping (void)
5910 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5914 * mono_arch_is_single_step_event:
5916 * See mini-amd64.c for docs.
5919 mono_arch_is_single_step_event (void *info, void *sigctx)
5921 siginfo_t* sinfo = (siginfo_t*) info;
5922 /* Sometimes the address is off by 4 */
5923 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5930 * mono_arch_skip_single_step:
5932 * See mini-amd64.c for docs.
5935 mono_arch_skip_single_step (MonoContext *ctx)
5937 /* skip the ldptr */
5938 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5942 * mono_arch_create_seq_point_info:
5944 * See mini-amd64.c for docs.
5947 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5954 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5956 ext->lmf.previous_lmf = prev_lmf;
5957 /* Mark that this is a MonoLMFExt */
5958 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5959 ext->lmf.ebp = (gssize)ext;
5965 mono_arch_opcode_supported (int opcode)
5968 case OP_ATOMIC_ADD_I4:
5969 case OP_ATOMIC_CAS_I4:
5970 #ifdef TARGET_POWERPC64
5971 case OP_ATOMIC_ADD_I8:
5972 case OP_ATOMIC_CAS_I8: